Saturday, November 28, 2009

Silverlight 4 - Drag and drop images on a Silverlight application

One of the great new features of Silverlight 4 is drag-drop. This makes it possible to drag files from your OS onto the Silverlight application.

 

In this tutorial we’ll create a ListBox and make it possible to drop images from the desktop onto the application. The images will then appear in the ListBox.

 

First steps

First of all we’ll create a “normal” Silverlight 4 App + Website using Visual Studio 2010 or Expression Blend.

Next we need a ListBox to show the images when they are dropped on it. Make sure your XAML looks similar to this:

<UserControl x:Class="DragDrop.MainPage"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable
="d"
d:DesignHeight
="328" d:DesignWidth="514">

<Grid x:Name="LayoutRoot" Background="White">
<ListBox Height="Auto" HorizontalAlignment="Left" Name="listBox1" VerticalAlignment="Stretch" Width="200" />
</Grid>
</UserControl>


Hooking it up



Next step is to create an eventhandler for the drop event. But first we need to make sure that it is allowed to drop objects onto the ListBox.



This is done by setting the AllowDrop property of the ListBox to true.



So with the addition of that line your code should look similar to this:



public MainPage()
{
InitializeComponent();
listBox1.AllowDrop
= true;
listBox1.Drop
+= new DragEventHandler(listBox1_Drop);
}

void listBox1_Drop(object sender, DragEventArgs e)
{
throw new NotImplementedException();
}


Getting the file(s) from the DragEventArgs



Now that we have everything hooked up it is time to get started with the real stuff :)



 



At this time Silverlight 4 beta only has one so called DataFormat available. With this DataForm we can retrieve the file(s) dropped onto out ListBox:



System.IO.FileInfo[] fileInfos = e.Data.GetData(DataFormats.FileDrop) as System.IO.FileInfo[];
foreach (FileInfo fileInfo in fileInfos)
{

}




The code above goes in the listbox1_Drop eventhandler.



 



Helper methods



All that is left is to add the images that were dropped to the ListBox. Before Creating the Image objects we need to make sure that the files are indeed images. All we can do to check this is to check the extension of the file.

The following method can be used to check the files:



private bool IsImageFile(string p)
{
switch (p.ToLower())
{
case ".jpg":
case ".png":
return true;
default:
break;
}
return false;
}


Now that we are pretty certain the files are images, we can create Image objects out of them. For this functionality we can use the following method:



private Image CreateImageFromFile(System.IO.FileInfo fileInfo)
{
using (FileStream fileStream = fileInfo.OpenRead())
{
BitmapImage bitmap
= new BitmapImage();
bitmap.SetSource(fileStream);
Image image
= new Image();
image.Source
= bitmap;
image.Width
= 50;
image.Stretch
= Stretch.Uniform;
return image;
}
}


 



Wrapping it up



Now all that is left for us to do is put the things together we created in the previous section.



In the foreach loop we created before, we’ll check if the files are images and if true, add them to the ListBox:



if (IsImageFile(fileInfo.Extension))
{
listBox1.Items.Add(CreateImageFromFile(fileInfo));
}


 



The entire code-behind should look something like this:



 



public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
listBox1.AllowDrop
= true;
listBox1.Drop
+= new DragEventHandler(listBox1_Drop);
}

void listBox1_Drop(object sender, DragEventArgs e)
{
System.IO.FileInfo[] fileInfos
= e.Data.GetData(DataFormats.FileDrop) as System.IO.FileInfo[];
foreach (FileInfo fileInfo in fileInfos)
{
if (IsImageFile(fileInfo.Extension))
{
listBox1.Items.Add(CreateImageFromFile(fileInfo));
}
}
}

private Image CreateImageFromFile(System.IO.FileInfo fileInfo)
{
using (FileStream fileStream = fileInfo.OpenRead())
{
BitmapImage bitmap
= new BitmapImage();
bitmap.SetSource(fileStream);
Image image
= new Image();
image.Source
= bitmap;
image.Width
= 50;
image.Stretch
= Stretch.Uniform;
return image;
}
}

private bool IsImageFile(string p)
{
switch (p.ToLower())
{
case ".jpg":
case ".png":
return true;
default:
break;
}
return false;
}
}


 



That’s it!



 



You can download the source here



 



Don’t forget to subscribe on the homepage of this site so we can keep you posted! And there’s a feed available for blogposts and news as well, so subscribe to that as well if you’re interested!

Thursday, November 19, 2009

Silverlight 4 – Using the webcam

Yesterday the beta release of Silverlight 4 was announced. Of course I couldn’t resist to get started with one of the items on my personal wish list (and on lots of other peoples wish list as well).

 

Using the webcam in Silverlight 4 turned out to be a quite easy process. I only needed about 8 lines to get it started. A few lines more and I have an application which starts and stops the webcam with the click of a button.

 

Create the controls

First thing I did was create the controls in xaml using the new designer in Visual Studio 2010. I created a Grid to show the video in (I’ll explain later on why I used a Grid instead of the expected MediaElement) and a button for starting and stopping it.

 

Huh?! No Stream?

As I mentioned before we’ll be using a Grid to display the video in. Why wouldn’t you use a MediaElement? The reason for that is that, as far as I have found out until now, no Stream output for the videocapturing devices available.

This probably has something to do with the difficulty to control the videocapturing devices and with the different formats of the streams. Note that this isn’t based on anything, it’s just my assumption.

What is available then? Good question. It took me a while to figure out, so finally I gave up and goo.. euhm binged for the webcam support in Silverlight 4 and came up with an article describing how to get the video from the capturing device.

 

The code

First we need a field to save the CaptureSource in and we need to hook up the Click event of the button:

private CaptureSource _cs = new CaptureSource(); 

public MainPage()
{
InitializeComponent();
myButton.Click
+= new RoutedEventHandler(myButton_Click);
}


 



Next we will dive into the code required for getting the video from the capturing device.



Before we’re able to show the video from the CaptureSource we need to do some checks and verfications.



First of all, we’re going to check if the state of the CaptureSource is stopped. It would cause an exception if we would start it when it is already started.



if (_cs.State == CaptureState.Stopped)if (_cs.State == CaptureState.Stopped)


 



Next we’ll need to check if the user has granted us permission to use the webcam. We can do this by using the CaptureDeviceConfiguration class as follows:



 



if (!CaptureDeviceConfiguration.AllowedDeviceAccess) 
{
CaptureDeviceConfiguration.RequestDeviceAccess();
}


 



So what will happen here is that the Silverlight plug-in will show a pop-up with the question if you want allow camera and microphone access:



image



If the user responds with “Yes” we’ll continue to the next step. The code for this is:



if (!CaptureDeviceConfiguration.AllowedDeviceAccess) 
{
CaptureDeviceConfiguration.RequestDeviceAccess();
}
if (CaptureDeviceConfiguration.AllowedDeviceAccess)
{

}


The reason for the duplicate if is that I need to be sure my sure clicked on the yes button after showing the dialogbox. If I would use an else statement the user would have to click on the start button again and if I would use no if and the user would click on the “No” button an exception will be thrown when starting the CaptureSource without permission.



 



The following code needs to be placed inside the last curly braces of the previously added code:



 







System.Windows.Media.VideoCaptureDevice videodev; 
videodev
= CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
if (videodev != null)
{
_cs.VideoCaptureDevice
= videodev;

VideoBrush vb
= new VideoBrush();
vb.SetSource(_cs);
_cs.Start();

grid1.Background
= vb;
myButton.Content
= "Stop webcam";
}



As you can see from the fifth line of the code above, the CaptureSource (_cs) needs a VideoCaptureDevice to start the capturing. We can create a VideoCaptureDevice and get the default one by using the GetDefaultVideoCaptureDevice.



We need to be sure there is a default capture device otherwise the app would crash and burn again when starting the CaptureSource.



 



In the two lines of code that follow the VideoCaptureDevice setting we created a VideoBrush and set the source to the CaptureSource. After this, most of the work is done and all we need to do now is start the capturing, set the background of my Grid to the VideoBrush and change the content of the button to “Stop webcam”.



 



In the final piece of code, which goes right after the if in the previous piece of code, we’ll create the functionality to stop the capturing and return to the state where we can start the capturing all over again:







else 
{
if (_cs.State == CaptureState.Started)
{
_cs.Stop();
myButton.Content
= "Start webcam";
}
}


 



You can find the source of the application here



 



Cheers!



 



Rob

Monday, November 2, 2009

Silverlight & Expression Usergroup in the Netherlands

I'm pretty proud to announce that Silverlight & Expression Insiders, the first Silverlight & Expression user group in the Netherlands, is starting it's activities.

Together with a number of other enthousiastic professionals we created a website. In the near future we will start more activities like organizing events and publishing articles.

If you want us to keep you posted, register on the homepage of the new website:
http://sixin.nl


Cheers!

Rob