<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" media="screen" href="/styles/xslt/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:media="http://search.yahoo.com/mrss/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:c9="http://channel9.msdn.com">
<channel>
	<title>Channel 9</title>
    <atom:link rel="self" type="application/rss+xml" href="http://channel9.msdn.com/Niners/c4f.Giovanni-Montrone/Posts/RSS"></atom:link>
    <itunes:summary></itunes:summary>
    <itunes:author>Microsoft</itunes:author>
    <itunes:subtitle></itunes:subtitle>
    <image>
      <url>http://mschnlnine.vo.llnwd.net/d1/Dev/App_Themes/C9/images/feedimage.png</url>
      <title>Channel 9</title>
      <link>http://channel9.msdn.com/Niners/c4f.Giovanni-Montrone/Posts</link>
    </image>
    <itunes:image href=""></itunes:image>
    <itunes:category text="Technology"></itunes:category>
    <description>Channel 9 keeps you up to date with the latest news and behind the scenes info from Microsoft that developers love to keep up with. From LINQ to SilverLight – Watch videos and hear about all the cool technologies coming and the people behind them.</description>
    <link>http://channel9.msdn.com/Niners/c4f.Giovanni-Montrone/Posts</link>
    <language>en</language>
    <pubDate>Fri, 24 May 2013 18:23:34 GMT</pubDate>
    <lastBuildDate>Fri, 24 May 2013 18:23:34 GMT</lastBuildDate>
    <generator>Rev9</generator>
    <c9:totalResults>2</c9:totalResults>
    <c9:pageCount>1</c9:pageCount>
    <c9:pageSize>25</c9:pageSize>
  <item>
      <title>Silverlight 3 File Transfer Application</title>
      <description><![CDATA[<p>Every once in a while I will run into a situation where I need to send a file to someone, but struggle to find an easy way of doing it.&nbsp; Instant messenger programs usually work until you run into a situation where someone just cannot send or receive a file
 from chat client whether it's due to firewalls, differing client versions, or multi-IM incompatibilities.&nbsp; Other times, I will try to send the file via email just to find out that the person's email server blocks specific extensions.&nbsp; This quick application
 will allow two users to quickly and easily connect to a Silverlight 3 client and send each other files.&nbsp;
</p>
<h3>Overview</h3>
<p>In this application, a user will connect to the Silverlight application and choose to either host or join a session.&nbsp; If a user decides to host a session, he or she will be given a random eight character session key, and he or she will be in a waiting status
 until another user connects.&nbsp; When a user wishes to connect to the host, he or she can supply the host's session key which will establish a connection between the two users.&nbsp; Once connected, the users will be able to send files to one another, and will also
 be able to chat with each other via simple text messages.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9876572/SendFile.jpg"><img title="SendFile" border="0" alt="SendFile" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9876572/SendFile_thumb.jpg" width="544" height="237"></a>
</p>
<h3>Polling Duplex</h3>
<p>Sending a file from one client application to another requires a common central point in order to properly route the message from one user to another.&nbsp; Since it is easy to host a Silverlight application in an ASP.NET page, we will use an ASP.NET back end
 to manage all communications between all connected users.&nbsp; In order to do this, we must be able to host a service that is able to accept incoming messages from the Silverlight client, and perform a push back out to the intended recipient.&nbsp; This is accomplished
 by using the WCF Polling Duplex (<strong>System.ServiceModel.PollingDuplex.dll</strong>) channel.&nbsp; Silverlight 3 allows us to directly add a service reference to a service of this type, and handles all of the complexities for us.&nbsp; I began by using the<strong>
 DuplexService.cs</strong> file from a sample application from MIX09 when Silverlight 3 beta was released.&nbsp; The code starts us out with a couple of base abstract classes, and interfaces that we must inherit from in order to create our own service.&nbsp;
</p>
<h3>FileSendService</h3>
<p>The two main things we need to do in order to create our own service is to define custom message types that will be used for communication, and override the base
<strong>DuplexService</strong> class to properly handle these messages.&nbsp; We will create our custom message types by using
<strong>DuplexMessage</strong> (defined in <strong>DuplexService.cs</strong>) as our base class.&nbsp; Our message classes must be defined with the
<strong>[DataContract]</strong> attribute, and the the member variables must be public and contain the
<strong>[DataMember]</strong> attribute.&nbsp; This will allow our Silverlight client project to share these definitions using a service reference.&nbsp; Additionally, the Duplex message class must have the
<strong>[KnownType]</strong> attribute for each descendant message created.</p>
<p>&nbsp;<strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><p>[KnownType(<span>typeof</span>(HostSessionMessage))]<br>[KnownType(<span>typeof</span>(JoinSessionMessage))]<br>[KnownType(<span>typeof</span>(FileBeginUploadMessage))]<br>[KnownType(<span>typeof</span>(FileTransferBytesMessage))]<br><span>public</span> <span>class</span> DuplexMessage { }</p></pre>
</div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">[DataContract]<br><span>public</span> <span>class</span> HostSessionMessage : DuplexMessage<br>{<br>    [DataMember]<br>    <span>public</span> <span>string</span> Username;<br>}<br><br>[DataContract]<br><span>public</span> <span>class</span> JoinSessionMessage : DuplexMessage<br>{<br>    [DataMember]<br>    <span>public</span> <span>string</span> Username;<br>    [DataMember]<br>    <span>public</span> <span>string</span> SessionKey;<br>}<br><br>[DataContract]<br><span>public</span> <span>class</span> FileBeginUploadMessage : DuplexMessage<br>{<br>    [DataMember]<br>    <span>public</span> <span>string</span> FileName;<br>    [DataMember]<br>    <span>public</span> <span>long</span> TotalBytes;<br>}<br><br>[DataContract]<br><span>public</span> <span>class</span> FileTransferBytesMessage : DuplexMessage<br>{<br>    [DataMember]<br>    <span>public</span> <span>long</span> StartByte;<br>    [DataMember]<br>    <span>public</span> <span>long</span> PacketSize;<br>    [DataMember]<br>    <span>public</span> <span>byte</span>[] Bytes;<br>    [DataMember]<br>    <span>public</span> <span>bool</span> EndFile;<br>}</pre>
<br>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">&lt;DataContract(<span>Namespace</span> := <span>&quot;http://samples.microsoft.com/silverlight2/duplex&quot;</span>), <br>KnownType(<span>GetType</span>(HostSessionMessage)), KnownType(<span>GetType</span>(JoinSessionMessage)), KnownType(<span>GetType</span>(FileBeginUploadMessage)), KnownType(<span>GetType</span>(FileTransferBytesMessage))&gt; _<br><span>Public</span> <span>Class</span> DuplexMessage<br><span>End</span> Class</pre>
<br>
</div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">&lt;DataContract()&gt; _<br><span>Public</span> <span>Class</span> HostSessionMessage<br>    <span>Inherits</span> DuplexMessage<br>    &lt;DataMember()&gt; <span>Public</span> Username <span>As</span> <span>String</span><br><span>End</span> <span>Class</span><br><br>&lt;DataContract()&gt; _<br><span>Public</span> <span>Class</span> JoinSessionMessage<br>    <span>Inherits</span> DuplexMessage<br>    &lt;DataMember()&gt; <span>Public</span> Username <span>As</span> <span>String</span><br>    &lt;DataMember()&gt; <span>Public</span> SessionKey <span>As</span> <span>String</span><br><span>End</span> <span>Class</span><br><br>&lt;DataContract()&gt; _<br><span>Public</span> <span>Class</span> FileTransferBytesMessage<br>    <span>Inherits</span> DuplexMessage<br>    &lt;DataMember()&gt; <span>Public</span> StartByte <span>As</span> <span>Long</span><br>    &lt;DataMember()&gt; <span>Public</span> PacketSize <span>As</span> <span>Long</span><br>    &lt;DataMember()&gt; <span>Public</span> Bytes() <span>As</span> <span>Byte</span><br>    &lt;DataMember()&gt; <span>Public</span> EndFile <span>As</span> <span>Boolean</span><br><span>End</span> <span>Class</span><br><br>&lt;DataContract()&gt; _<br><span>Public</span> <span>Class</span> FileBeginUploadMessage<br>    <span>Inherits</span> DuplexMessage<br>    &lt;DataMember()&gt; <span>Public</span> FileName <span>As</span> <span>String</span><br>    &lt;DataMember()&gt; <span>Public</span> TotalBytes <span>As</span> <span>Long</span><br><span>End</span> Class</pre>
<br>
</div>
<p>The next step is to create our <strong>FileSendService</strong> class which descends from the
<strong>DuplexService</strong> class as described above.&nbsp; We override the <strong>
OnMessage</strong> method so that we can do custom processing based on the type of message sent as shown below.&nbsp;
</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]<br><span>public</span> <span>class</span> FileSendService : DuplexService<br>{<br>    <span>private</span> List&lt;SessionConnectionInfo&gt; sessionConnections = <span>new</span> List&lt;SessionConnectionInfo&gt;();<br><br>    {...}<br><br>    <span>protected</span> <span>override</span> <span>void</span> OnMessage(<span>string</span> sessionId, DuplexMessage data)<br>    {<br>        <span>if</span> (data <span>is</span> HostSessionMessage)<br>            CreateHostSession(data <span>as</span> HostSessionMessage);<br>        <span>else</span> <span>if</span> (data <span>is</span> JoinSessionMessage)<br>            JoinSession(data <span>as</span> JoinSessionMessage);<br>        <span>else</span> <span>if</span> (data <span>is</span> FileBeginUploadMessage)<br>            StartSendFile(data <span>as</span> FileBeginUploadMessage);<br>        <span>else</span><br>            SendMessage(data);<br>    }<br>    <br>}</pre>
<pre id="codeSnippet"><br>        <span>else</span> <span>if</span> (data <span>is</span> JoinSessionMessage)<br>            JoinSession(data <span>as</span> JoinSessionMessage);<br>        <span>else</span> <span>if</span> (data <span>is</span> FileBeginUploadMessage)<br>            StartSendFile(data <span>as</span> FileBeginUploadMessage);<br>        <span>else</span><br>            SendMessage(data);<br>    }<br>    <br>}</pre>
<pre id="codeSnippet"><br>    }<br>    <br>}</pre>
<br>
</div>
<p>&nbsp;<strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Class</span> FileSenderServiceFactory<br>    <span>Inherits</span> DuplexServiceFactory(Of FileSendService)<br><span>End</span> <span>Class</span><br><br>&lt;AspNetCompatibilityRequirements(RequirementsMode := AspNetCompatibilityRequirementsMode.Allowed)&gt; _<br><span>Public</span> <span>Class</span> FileSendService<br>    <span>Inherits</span> DuplexService<br>    <span>Private</span> sessionConnections <span>As</span> <span>New</span> List(Of SessionConnectionInfo)()<br><br>    ...<br><br>    <span>Protected</span> <span>Overrides</span> <span>Sub</span> OnMessage(<span>ByVal</span> sessionId <span>As</span> <span>String</span>, <span>ByVal</span> data <span>As</span> DuplexMessage)<br>        <span>If</span> <span>TypeOf</span> data <span>Is</span> HostSessionMessage <span>Then</span><br>            CreateHostSession(<span>TryCast</span>(data, HostSessionMessage))<br>        <span>ElseIf</span> <span>TypeOf</span> data <span>Is</span> JoinSessionMessage <span>Then</span><br>            JoinSession(<span>TryCast</span>(data, JoinSessionMessage))<br>        <span>ElseIf</span> <span>TypeOf</span> data <span>Is</span> FileBeginUploadMessage <span>Then</span><br>            StartSendFile(<span>TryCast</span>(data, FileBeginUploadMessage))<br>        <span>Else</span><br>            SendMessage(data)<br>        <span>End</span> <span>If</span><br>    <span>End</span> <span>Sub</span><br><br><span>End</span> Class</pre>
<br>
</div>
<p>Since we are going to have to keep track of each host and user connected to that host, we will create a class,&nbsp;
<strong>SessionConnectionInfo</strong>, to manage the relevant data.&nbsp; When a user decides to host a session, our
<strong>OnMessage</strong> method will receive a <strong>HostSessionMessage</strong> which will scan our<strong> List&lt;SessionConnectionInfo&gt;</strong> to see if there is another host with the same username.&nbsp; If not found, a new
<strong>SessionConnectionInfo</strong> object is created along with a randomly generated session key.&nbsp; When a user attempts to join a session, the
<strong>OnMessage</strong> method will receive a <strong>JoinSessionMessage</strong> containing a session key and the name of the user joining the session.&nbsp; The service will search for a
<strong>SessionConnectionInfo</strong> object containing that session key, and if found, establishes a connection between the two users.&nbsp;
</p>
<p>&nbsp;<strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>class</span> SessionConnectionInfo<br>{<br>    <span>public</span> <span>string</span> HostUserName { get; set; }<br>    <span>public</span> <span>string</span> ConnectedUsername { get; <span>private</span> set; }<br>    <span>public</span> <span>string</span> SessionKey { get; set; }<br><br>    <span>public</span> <span>string</span> ConnectedUserInternalSession { get; <span>private</span> set; }<br>    <span>public</span> <span>string</span> HostInternalSession { get; set; }<br><br>    <span>public</span> <span>bool</span> UserConnected<br>    {<br>        get { <span>return</span> ConnectedUserInternalSession != <span>string</span>.Empty; }<br>    }<br><br>    <span>public</span> SessionConnectionInfo()<br>    {<br>        ConnectedUserInternalSession = <span>string</span>.Empty;<br>        ConnectedUsername = <span>string</span>.Empty;<br>    }<br><br>    ....<br>}<br></pre>
</div>
<p><strong>VB</strong>&nbsp;</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Class</span> SessionConnectionInfo<br>    <span>Private</span> privateHostUserName <span>As</span> <span>String</span><br>    <span>Public</span> <span>Property</span> HostUserName() <span>As</span> <span>String</span><br>        <span>Get</span><br>            <span>Return</span> privateHostUserName<br>        <span>End</span> <span>Get</span><br>        <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)<br>            privateHostUserName = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br>    <span>Private</span> privateConnectedUsername <span>As</span> <span>String</span><br>    <span>Public</span> <span>Property</span> ConnectedUsername() <span>As</span> <span>String</span><br>        <span>Get</span><br>            <span>Return</span> privateConnectedUsername<br>        <span>End</span> <span>Get</span><br>        <span>Private</span> <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)<br>            privateConnectedUsername = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br>    <span>Private</span> privateSessionKey <span>As</span> <span>String</span><br>    <span>Public</span> <span>Property</span> SessionKey() <span>As</span> <span>String</span><br>        <span>Get</span><br>            <span>Return</span> privateSessionKey<br>        <span>End</span> <span>Get</span><br>        <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)<br>            privateSessionKey = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br><br>    <span>Private</span> privateConnectedUserInternalSession <span>As</span> <span>String</span><br>    <span>Public</span> <span>Property</span> ConnectedUserInternalSession() <span>As</span> <span>String</span><br>        <span>Get</span><br>            <span>Return</span> privateConnectedUserInternalSession<br>        <span>End</span> <span>Get</span><br>        <span>Private</span> <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)<br>            privateConnectedUserInternalSession = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br>    <span>Private</span> privateHostInternalSession <span>As</span> <span>String</span><br>    <span>Public</span> <span>Property</span> HostInternalSession() <span>As</span> <span>String</span><br>        <span>Get</span><br>            <span>Return</span> privateHostInternalSession<br>        <span>End</span> <span>Get</span><br>        <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>String</span>)<br>            privateHostInternalSession = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br><br>    <span>Public</span> <span>ReadOnly</span> <span>Property</span> UserConnected() <span>As</span> <span>Boolean</span><br>        <span>Get</span><br>            <span>Return</span> ConnectedUserInternalSession &lt;&gt; <span>String</span>.Empty<br>        <span>End</span> <span>Get</span><br>    <span>End</span> <span>Property</span><br><br>    <span>Public</span> <span>Sub</span> <span>New</span>()<br>        ConnectedUserInternalSession = <span>String</span>.Empty<br>        ConnectedUsername = <span>String</span>.Empty<br>    <span>End</span> <span>Sub</span><br><br><br><span>End</span> Class</pre>
<br>
</div>
<h2>Client Side</h2>
<p>Now that we have the basic server side complete, we can add a service reference, and create the necessary service reference.&nbsp; Our service is hosted within ASP.NET via a simple xml file (see
<strong>FileSendService.svc</strong>), which allows our Silverlight project to see it.</p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9876572/AddServiceRef.jpg"><img title="Add Service Ref" border="0" alt="Add Service Ref" src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9876572/AddServiceRef_thumb.jpg" width="540" height="475"></a>
</p>
<p>Be sure to mark the checkbox “Always generate message contracts”.&nbsp; Note that your web portion of the project must be compiled before you will be able to “Discover” the service.</p>
<p>We will now have access to the <strong>DuplexServiceClient</strong> class which will allow us to send and receive messages to the server.&nbsp; We instantiate the service as shown below.&nbsp; In order to do this, you must manually add a reference to
<strong>System.ServiceModel.PollingDuplex</strong> assembly.</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> DuplexServiceClient fileDuplexService;<br><br><span>private</span> CustomBinding binding = <span>new</span> CustomBinding(<br>    <span>new</span> PollingDuplexBindingElement(),<br>    <span>new</span> BinaryMessageEncodingBindingElement(),<br>    <span>new</span> HttpTransportBindingElement());<br><br><span>public</span> MainPage()<br>{<br>    InitializeComponent();<br>    fileDuplexService = <span>new</span> DuplexServiceClient(binding, <span>new</span> EndpointAddress(<span>&quot;http://localhost:9797/FileSendService.svc&quot;</span>));<br>    ...<br>}</pre>
<br>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><p><span>Private</span> fileDuplexService <span>As</span> DuplexServiceClient<br><br><span>Private</span> binding <span>As</span> <span>New</span> CustomBinding(<span>New</span> PollingDuplexBindingElement(), <span>New</span> BinaryMessageEncodingBindingElement(), <span>New</span> HttpTransportBindingElement())<br></p><p>    <br><span>Public</span> <span>Sub</span> <span>New</span>()<br>&nbsp;&nbsp;&nbsp; InitializeComponent()<br>    fileDuplexService = <span>New</span> DuplexServiceClient(binding, <span>New</span> EndpointAddress(<span>&quot;http://localhost:9797/FileSendService.svc&quot;</span>))<br><span>End</span> <span>Sub</span><br></p></pre>
<br>
</div>
<p>Note that at the time of this writing, adding the service reference does not properly create the
<strong>ServiceReferences.ClientConfig</strong> file.&nbsp; This is the reason the above is done using code.</p>
<p>Now that our service is setup, we need to set it up to handle sending and receiving of messages.&nbsp;&nbsp; In order to send a message, we must first create a
<strong>DupexMessage</strong> (or a descendant), and use the <strong>SendToServiceAsync</strong> method.&nbsp; This requires a
<strong>SendToService</strong> object which will contain the message, and an optional
<strong>userState</strong> object which we can use to tag the request.&nbsp; In this case, we will pass an enum value which represents the status of our upload.&nbsp; In the example below, when the user clicks on the send file button, after choosing the file, we open
 our file, and send a <strong>FileBeginUpload</strong> message which contains the file name and its size.&nbsp; Note that the server is set to deny any file that is greater than 20 million bytes.</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> btnSendFile_Click(<span>object</span> sender, RoutedEventArgs e)<br> {<br>     OpenFileDialog openFileDialog = <span>new</span> OpenFileDialog();<br>     openFileDialog.Multiselect = <span>false</span>;<br>     openFileDialog.ShowDialog();<br>     <span>if</span> (openFileDialog.File != <span>null</span>)<br>     {<br>         fileToSend = openFileDialog.File.OpenRead();<br><br>         FileBeginUploadMessage fsm = <span>new</span> FileBeginUploadMessage();<br>         fsm.FileName = openFileDialog.File.Name;<br>         fsm.TotalBytes = openFileDialog.File.Length;<br>         fileDuplexService.SendToServiceAsync(<span>new</span> SendToService(fsm), FileSendState.FileStart);<br>         ....<br>     }<br> }</pre>
<br>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> btnSendFile_Click(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> RoutedEventArgs)<br>    <span>Dim</span> openFileDialog <span>As</span> <span>New</span> OpenFileDialog()<br>    openFileDialog.Multiselect = <span>False</span><br>    openFileDialog.ShowDialog()<br>    <span>If</span> openFileDialog.File IsNot <span>Nothing</span> <span>Then</span><br>        fileToSend = openFileDialog.File.OpenRead()<br>        <span>Dim</span> fsm <span>As</span> <span>New</span> FileBeginUploadMessage()<br>        fsm.FileName = openFileDialog.File.Name<br>        fsm.TotalBytes = openFileDialog.File.Length<br>        totalBytesSent = 0<br>        fileDuplexService.SendToServiceAsync(<span>New</span> SendToService(fsm), FileSendState.FileStart)<br>        ....<br>    <span>End</span> <span>If</span><br><span>End</span> Sub</pre>
<br>
</div>
<p>The service object fires two main events that need to be handled: <strong>SendToServiceCompleted</strong> and
<strong>SendToClientReceived</strong>. <strong>SendToServiceCompleted</strong> is the event which is fired after the server acknowledges that it has received and processed a message that the client has sent.&nbsp; Once the server receives and processes the
<strong>FileBeginUploadMessage</strong>, the event handler below will receive the results.&nbsp; In this case, if there isn't an error, and the value of
<strong>userState</strong> is <strong>FileSendState.FileStart</strong>,&nbsp; the method will send a
<strong>FileTransferBytesMessage</strong> which will send the bytes from the file.&nbsp;
</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><p><span>private</span> <span>void</span> FileDuplexServiceSendToServiceCompleted(<span>object</span> sender, System.ComponentModel.AsyncCompletedEventArgs e)<br>{<br>    <span>if</span> (e.Error == <span>null</span>)<br>    {<br>        {...}<br>        <span>if</span> ((FileSendState)e.UserState == FileSendState.FileEnd)<br>        {<br>            fileToSend.Close();<br>            fileProgress.Value = 100;<br>            <span>return</span>;<br>        }<br>        <span>if</span> ((FileSendState)e.UserState == FileSendState.FileStart || (FileSendState)e.UserState == FileSendState.FileContinue)<br>        {<br></p><p><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br>            FileTransferBytesMessage fileMessage = <span>new</span> FileTransferBytesMessage();<br>            fileMessage.StartByte = totalBytesSent;<br>            fileMessage.EndFile = <span>false</span>;<br>            fileMessage.PacketSize = CHUNK;<br><br>            ...<br><br>            <span>byte</span>[] bytes = <span>new</span> <span>byte</span>[numBytesToRead];<br>            fileToSend.Read(bytes, 0, numBytesToRead);<br>            totalBytesSent &#43;= numBytesToRead;<br>            fileMessage.Bytes = bytes;<br><br>            <span>if</span> (fileMessage.EndFile)<br>                fileDuplexService.SendToServiceAsync(<span>new</span> SendToService(fileMessage), FileSendState.FileEnd);<br>            <span>else</span><br>                fileDuplexService.SendToServiceAsync(<span>new</span> SendToService(fileMessage), FileSendState.FileContinue);<br>        }<br>    }<br>}</p></pre>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> FileDuplexServiceSendToServiceCompleted(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> System.ComponentModel.AsyncCompletedEventArgs)<br>    <span>If</span> e.<span>Error</span> <span>Is</span> <span>Nothing</span> <span>Then</span><br>        <span>If</span> e.UserState <span>Is</span> <span>Nothing</span> <span>Then</span><br>            <span>Return</span><br>        <span>End</span> <span>If</span><br>        <span>If</span> <span>CType</span>(e.UserState, FileSendState) = FileSendState.FileEnd <span>Then</span><br>            fileToSend.Close()<br>            fileProgress.Value = 100<br>            <span>Return</span><br>        <span>End</span> <span>If</span><br>        <span>If</span> <span>CType</span>(e.UserState, FileSendState) = FileSendState.FileStart <span>OrElse</span> <span>CType</span>(e.UserState, FileSendState) = FileSendState.FileContinue <span>Then</span><br>            ...<br>            <span>Dim</span> fileMessage <span>As</span> <span>New</span> FileTransferBytesMessage()<br>            fileMessage.StartByte = totalBytesSent<br>            fileMessage.EndFile = <span>False</span><br>            fileMessage.PacketSize = CHUNK<br>            ...<br>            <span>Dim</span> bytes(numBytesToRead - 1) <span>As</span> <span>Byte</span><br>            fileToSend.Read(bytes, 0, numBytesToRead)<br>            totalBytesSent &#43;= numBytesToRead<br>            fileMessage.Bytes = bytes<br><br>            <span>If</span> fileMessage.EndFile <span>Then</span><br>                fileDuplexService.SendToServiceAsync(<span>New</span> SendToService(fileMessage), FileSendState.FileEnd)<br>            <span>Else</span><br>                fileDuplexService.SendToServiceAsync(<span>New</span> SendToService(fileMessage), FileSendState.FileContinue)<br>            <span>End</span> <span>If</span><br>        <span>End</span> <span>If</span><br>    <span>End</span> <span>If</span><br><span>End</span> <span>Sub</span><br></pre>
<br>
</div>
<p>The <strong>SendToClientReceived</strong> event is fired when a message has been sent from the service.&nbsp; In this case, the client will check to see which message was received and process it accordingly.&nbsp; The method below shows that when a
<strong>FileBeginUpload</strong> message is received, the user is prompted to accept or deny the file.&nbsp; If the user does not accept the file, a
<strong>FileDenyMessage</strong> will be sent which will notify the sender to stop sending bytes.&nbsp; If accepted, file bytes are added to a buffer.&nbsp;
</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> FileDuplexServiceSendToClientReceived(<span>object</span> sender, SendToClientReceivedEventArgs e)<br>{<br>    <span>if</span> (e.Error == <span>null</span>)<br>    {<br>        <span>if</span> (e.request.msg <span>is</span> ClientConnectedMessage)<br>        {<br>            ClientConnectedMessage msg = (ClientConnectedMessage)e.request.msg;<br>            AddMsgToListbox(msg.Username &#43; <span>&quot; has just connected.&quot;</span>);<br>            connectedTo = msg.Username;<br>            UIState = UIState.Chat;<br>        }<br><br>        <span>else</span> <span>if</span> (e.request.msg <span>is</span> HostSessionServerMessage)<br>        {<br>            HostSessionServerMessage hssm = e.request.msg <span>as</span> HostSessionServerMessage;<br>            <span>if</span> (hssm.Failed) {...}<br>            SessionCreated(hssm);<br><br>        }<br>        <span>else</span> <span>if</span> (e.request.msg <span>is</span> JoinSessionServerMessage)<br>        {<br>            JoinSessionServerMessage jssm = e.request.msg <span>as</span> JoinSessionServerMessage;<br>            <span>if</span> (jssm.Failed) {....}<br>            SessionJoined(jssm);<br>        }<br>        <span>else</span> <span>if</span> (e.request.msg <span>is</span> FileBeginUploadMessage )<br>        {<br>            FileBeginUploadMessage fsm = (FileBeginUploadMessage)e.request.msg;<br><br>            <span>int</span> sizeInKB = (<span>int</span>)fsm.TotalBytes / 1024;<br>            totalRevd = 0;<br>            <span>if</span> (MessageBox.Show(connectedTo &#43; <span>&quot; would like to send you the file: &quot;</span> &#43; fsm.FileName &#43; <span>&quot;, Size: &quot;</span> &#43; sizeInKB &#43; <span>&quot;.  Would you like to receive this file?&quot;</span>, <span>&quot;File Upload&quot;</span>, MessageBoxButton.OKCancel) == MessageBoxResult.OK)<br>            {<br>                bytesReceived = <span>new</span> List&lt;<span>byte</span>&gt;((<span>int</span>)fsm.TotalBytes);<br>                fileNameReceiving = fsm.FileName;<br>                ....<br>            }<br>            <span>else</span><br>            {<br>                fileDuplexService.SendToServiceAsync(<span>new</span> SendToService(<span>new</span> FileDenyMessage()));<br>            }<br>        }<br>        <span>else</span> <span>if</span> (e.request.msg <span>is</span> FileTransferBytesMessage)<br>        {<br>            <span>if</span> (bytesReceived == <span>null</span>)<br>                <span>return</span>;<br>            FileTransferBytesMessage fm = (FileTransferBytesMessage)e.request.msg;<br>            bytesReceived.AddRange(fm.Bytes);<br>            ....<br>        }<br>        <span>else</span> {....}<br><br>    }<br>}</pre>
<br>
</div>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> FileDuplexServiceSendToClientReceived(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> SendToClientReceivedEventArgs)<br>    <span>If</span> e.<span>Error</span> <span>Is</span> <span>Nothing</span> <span>Then</span><br>        <span>If</span> <span>TypeOf</span> e.request.msg <span>Is</span> ClientConnectedMessage <span>Then</span><br>            <span>Dim</span> msg <span>As</span> ClientConnectedMessage = <span>CType</span>(e.request.msg, ClientConnectedMessage)<br>            AddMsgToListbox(msg.Username &amp; <span>&quot; has just connected.&quot;</span>)<br>            connectedTo = msg.Username<br>            UIState = UIState.Chat<br><br>        <span>ElseIf</span> <span>TypeOf</span> e.request.msg <span>Is</span> HostSessionServerMessage <span>Then</span><br>            <span>Dim</span> hssm <span>As</span> HostSessionServerMessage = <span>TryCast</span>(e.request.msg, HostSessionServerMessage)<br>            <span>If</span> hssm.Failed <span>Then</span> ...<br><br>            SessionCreated(hssm)<br><br>        <span>ElseIf</span> <span>TypeOf</span> e.request.msg <span>Is</span> JoinSessionServerMessage <span>Then</span><br>            <span>Dim</span> jssm <span>As</span> JoinSessionServerMessage = <span>TryCast</span>(e.request.msg, JoinSessionServerMessage)<br>            <span>If</span> jssm.Failed <span>Then</span> ...<br><br>            SessionJoined(jssm)<br>        <span>ElseIf</span> <span>TypeOf</span> e.request.msg <span>Is</span> FileBeginUploadMessage <span>Then</span><br>            <span>Dim</span> fsm <span>As</span> FileBeginUploadMessage = <span>CType</span>(e.request.msg, FileBeginUploadMessage)<br><br>            <span>Dim</span> sizeInKB <span>As</span> <span>Integer</span> = <span>CInt</span>(Fix(fsm.TotalBytes)) / 1024<br>            totalRevd = 0<br>            <span>If</span> MessageBox.Show(connectedTo &amp; <span>&quot; would like to send you the file: &quot;</span> &amp; fsm.FileName &amp; <span>&quot;, Size: &quot;</span> &amp; sizeInKB &amp; <span>&quot; KB.  Would you like to receive this file?&quot;</span>, <span>&quot;File Upload&quot;</span>, MessageBoxButton.OKCancel) = MessageBoxResult.OK <span>Then</span><br>                bytesReceived = <span>New</span> List(Of <span>Byte</span>)(<span>CInt</span>(Fix(fsm.TotalBytes)))<br>                fileNameReceiving = fsm.FileName<br>                ...<br>            <span>Else</span><br>                fileDuplexService.SendToServiceAsync(<span>New</span> SendToService(<span>New</span> FileDenyMessage()))<br>            <span>End</span> <span>If</span><br>        <span>ElseIf</span> <span>TypeOf</span> e.request.msg <span>Is</span> FileTransferBytesMessage <span>Then</span><br>            <span>If</span> bytesReceived <span>Is</span> <span>Nothing</span> <span>Then</span><br>                <span>Return</span><br>            <span>End</span> <span>If</span><br>            <span>Dim</span> fm <span>As</span> FileTransferBytesMessage = <span>CType</span>(e.request.msg, FileTransferBytesMessage)<br>            bytesReceived.AddRange(fm.Bytes)<br>            ...<br>        <span>ElseIf</span> <br>          ...<br><br>    <span>End</span> <span>If</span><br><span>End</span> Sub</pre>
<br>
</div>
<p>&nbsp;</p>
<p>When the file is complete, the user will be presented with two buttons.&nbsp; One button will allow the user to save, and the other will allow the user to discard/ignore the file.&nbsp; If the user chooses to save, a
<strong>SaveFileDialog</strong> is created, and we use the filename to assign the default extension and filter so that when the user saves the file, no extension needs to be typed in.&nbsp; Once the dialog appears and the user enters the file name, the bytes will
 be written to disk.&nbsp; Finally we send a message back to the server which will notify the sender that user has done something with the file.&nbsp; During file send operations, the Send File button is disabled, and becomes re-enabled once a file has been received,
 cancelled, or denied.</p>
<p><strong>C#</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> void btnSaveFile_Click(<span>object</span> sender, RoutedEventArgs e)<br>{<br>    SaveFileDialog sfd = <span>new</span> SaveFileDialog();<br>    <span>string</span> extension = GetExtension(fileNameReceiving);<br>    sfd.DefaultExt = extension;<br>    sfd.Filter = extension &#43;  <span>&quot; Files|&quot;</span> &#43; extension;<br><br>    <span>if</span> (sfd.ShowDialog() == <span>true</span>)<br>    {<br>        using (Stream fsx = sfd.OpenFile())<br>        {<br>            <span>byte</span>[] fBytes = bytesReceived.ToArray();<br>            fsx.Write(fBytes, 0, fBytes.Length);<br>            fsx.Close();<br>        }<br><br>        fileDuplexService.SendToServiceAsync(<span>new</span> SendToService(<span>new</span> FileReceivedMessage()));<br>        UIState = UIState.Chat;<br>        btnSendFile.IsEnabled = <span>true</span>;<br>    }<br>}</pre>
<br>
</div>
<p>&nbsp;</p>
<p><strong>VB</strong></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> btnSaveFile_Click(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> RoutedEventArgs)<br>    <span>Dim</span> sfd <span>As</span> <span>New</span> SaveFileDialog()<br>    <span>Dim</span> extension <span>As</span> <span>String</span> = GetExtension(fileNameReceiving)<br>    sfd.DefaultExt = extension<br>    sfd.Filter = extension &amp; <span>&quot; Files|&quot;</span> &amp; extension<br><br>    <span>If</span> sfd.ShowDialog() = <span>True</span> <span>Then</span><br>        Using fsx <span>As</span> Stream = sfd.OpenFile()<br>            <span>Dim</span> fBytes() <span>As</span> <span>Byte</span> = bytesReceived.ToArray()<br>            fsx.Write(fBytes, 0, fBytes.Length)<br>            fsx.Close()<br>        <span>End</span> Using<br><br>        fileDuplexService.SendToServiceAsync(<span>New</span> SendToService(<span>New</span> FileReceivedMessage()))<br>        UIState = UIState.Chat<br>        btnSendFile.IsEnabled = <span>True</span><br>    <span>End</span> <span>If</span><br><span>End</span> Sub</pre>
<br>
</div>
<h3>&nbsp;</h3>
<h3>Conclusion</h3>
<p>Overall, the application does what I set out for it to.&nbsp; It allows a user to send a file to another user and even does basic chat.&nbsp; There is definitely a lot of room for improvement, and some general additions that can make this more robust.&nbsp; Right now we
 keep a list of connections, but never do basic pinging to see if the clients are still there.&nbsp; The only way to know if a client has disconnected is when a message fails, or when the user decides to hit the disconnect button. Better maintenance of this list
 is needed.&nbsp; The file bytes are basically being stored in memory, which is why i set a file size limit, but I'm sure with things like Silverlight local storage, we can increase the limit.&nbsp;
</p>
<h3>Thanks</h3>
<p>I would like to thank <a href="http://www.brianpeek.com/">Brian Peek</a> for taking the time to review my article and test the code.</p>
<h3>Additional Notes</h3>
<p>The ASP.NET project requires a file called System.ServiceModel.PollingDuplex.dll to be added as a reference.&nbsp; Somewhere between Silverlight 3 Beta and Silverlight 3 RTW, the file was no longer available via the basic add .NET reference link.&nbsp; In order to
 add the file, I had to browse for it in <strong>%Program Files%\Microsoft SDKs\Silverlight\v3.0\Libraries\Server</strong>.&nbsp; For 64 bit users, it will be the
<strong>Program Files (x86)</strong> folder.&nbsp; </p>
<p>For ease of use, I used a static port (9797) for this project. When deploying to a server, you must rename all references of http://localhost:9797 in the Silverlight project.&nbsp; This will remain true until the config file is supported.
</p>
<p>The user interface uses the Silverlight Toolkit TwilightBlue theme.&nbsp; For more information about this,&nbsp; see
<a title="http://www.codeplex.com/Silverlight" href="http://www.codeplex.com/Silverlight">
http://www.codeplex.com/Silverlight</a></p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Giovanni-Montrone/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:897e42c9a80348ceb4d09e7600cb6fa1">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Silverlight-3-File-Transfer-Application</comments>
      <itunes:summary>Every once in a while I will run into a situation where I need to send a file to someone, but struggle to find an easy way of doing it.&amp;nbsp; Instant messenger programs usually work until you run into a situation where someone just cannot send or receive a file
 from chat client whether it&#39;s due to firewalls, differing client versions, or multi-IM incompatibilities.&amp;nbsp; Other times, I will try to send the file via email just to find out that the person&#39;s email server blocks specific extensions.&amp;nbsp; This quick application
 will allow two users to quickly and easily connect to a Silverlight 3 client and send each other files.&amp;nbsp;
 
Overview
In this application, a user will connect to the Silverlight application and choose to either host or join a session.&amp;nbsp; If a user decides to host a session, he or she will be given a random eight character session key, and he or she will be in a waiting status
 until another user connects.&amp;nbsp; When a user wishes to connect to the host, he or she can supply the host&#39;s session key which will establish a connection between the two users.&amp;nbsp; Once connected, the users will be able to send files to one another, and will also
 be able to chat with each other via simple text messages. 

 
Polling Duplex
Sending a file from one client application to another requires a common central point in order to properly route the message from one user to another.&amp;nbsp; Since it is easy to host a Silverlight application in an ASP.NET page, we will use an ASP.NET back end
 to manage all communications between all connected users.&amp;nbsp; In order to do this, we must be able to host a service that is able to accept incoming messages from the Silverlight client, and perform a push back out to the intended recipient.&amp;nbsp; This is accomplished
 by using the WCF Polling Duplex (System.ServiceModel.PollingDuplex.dll) channel.&amp;nbsp; Silverlight 3 allows us to directly add a service reference to a service of this type, and handles all of the comple</itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Silverlight-3-File-Transfer-Application</link>
      <pubDate>Fri, 04 Sep 2009 03:43:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Silverlight-3-File-Transfer-Application</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9876572_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9876572_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Giovanni Montrone </dc:creator>
      <itunes:author>Giovanni Montrone </itunes:author>
      <slash:comments>10</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Silverlight-3-File-Transfer-Application/RSS</wfw:commentRss>
      <category>Silverlight</category>
      <category>utility</category>
      <category>Web</category>
      <category>web miscellaneous</category>
    </item>
  <item>
      <title>Blu-ray/DVD Comparison Utility</title>
      <description><![CDATA[
<table border="0" cellpadding="1" cellspacing="0" width="100%">
<tbody>
<tr class="entry_overview">
<td><span class="entry_description">In this article, Giovanni Montrone will provide an overview on how to create an image comparison application for DVD and Blu-ray screen captures.</span></td>
</tr>
<tr>
<td colspan="2">
<div class="entry_author"><a href="http://www.gmontrone.com/" target="_blank">Giovanni Montrone</a></div>
<div class="entry_company"><a href="http://www.aspsoft.com/">ASPSOFT, Inc.</a></div>
<br>
<div class="entry_details"><b>Difficulty: </b><span class="entry_details_input">Beginner</span></div>
<div class="entry_details"><b>Time Required:</b> 2<span class="entry_details_input">-3 hours</span></div>
<div class="entry_details"><b>Cost: </b><span class="entry_details_input">Free</span></div>
<div class="entry_details"><b>Software: </b><span class="entry_details_input"><a href="http://msdn.com/express/">Visual Web Developer Express SP1</a> (or Visual Studio 2008 SP1),
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=c22d6a7b-546f-4407-8ef6-d60c8ee221ed&amp;displaylang=en">
Silverlight 2 Tools</a></span></div>
<div class="entry_details"><b>Hardware: </b>None</div>
<div class="entry_details"><b>Application: </b><a href="http://gmontrone.com/bdcompare/BlurayDVDCompare.html" target="_blank">Run the application</a></div>
<div class="entry_details"><b>Source Download: </b><a href="http://channel9.msdn.com/playground/Sandbox/462814-Blu-rayDVD-Comparison-Utility/" target="_blank">Download the source</a></div>
</td>
</tr>
</tbody>
</table>
<p>&nbsp;</p>
<h3>Introduction</h3>
<p>As a fan of High Definition movies and television, I often find it difficult to explain the benefits of upgrading from DVD to blu-ray to family and friends.&nbsp; Many people believe that DVDs look good enough and/or that you need a really big television to notice
 the difference, and, even then, feel the improvement is not good enough to justify the upgrade.&nbsp; The best way to convince someone is to show him/her the same movie playing side by side on blu-ray and dvd using the same sized screens.&nbsp; Since it's difficult
 to do, the next best thing is to look at still images from both the DVD and the blu-ray and compare them.&nbsp; The images should be from the exact same scene.&nbsp; Fortunately there are places on the web such as
<a href="http://www.avsforum.com/">AVSForum</a> where members take the time to do this.&nbsp; They usually do this to help people determine what kind of an upgrade they can expect when viewing the blu-ray compared to the DVD.&nbsp; Sometimes the differences are easy
 to see, and other times they are not as clear.&nbsp; I built this comparison tool as a way to see what differences exist, and provided a few ways to make those differences easier to see.&nbsp;
</p>
<p>This utility will allow the user to compare two different images using 3 different modes: dual view, swap view, and Rectangle View. Dual view will allow a side by side comparison where you see part of the first image, and the remaining part of the second
 image. Moving the mouse left or right will show more of one image, and less of the other. The swap mode will allow the user to see one image in its entirety, and then, when placing the mouse over the image, the application will swap the first image with the
 second one. The last mode will allow the user to specify a region that he or she wishes to compare. They can draw a rectangle using the mouse, and the application will show the first image with a chunk cut out, replacing the rectangle area with the equivalent
 area on the second image. The image below shows an example of the rectangle view.
</p>
<p>&nbsp; </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/bddvdcompare1_2.jpg"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/bddvdcompare1_thumb.jpg" alt="bddvdcompare1" border="0" height="484" width="543"></a>
</p>
<h3>Notes</h3>
<p>The application is set to handle images that are 1920x1080 in resolution (the standard resolution of blu-ray movies).&nbsp; DVDs have a resolution of 720x480, but are typically up-converted to 1920x1080 in order to do a direct comparison.&nbsp; This upconversion is
 similar to what happens when you play a DVD on a 1080p high definition television.&nbsp; While it wouldn't be too difficult to handle other image sizes, to keep things simple, the application assumes the user will be providing images at the proper resolution.&nbsp;
 Using different images with different resolutions will result in incorrect behavior.
</p>
<p>At the time of this writing, Silverlight 3 beta has just recently been released, but has not been tested with this application.
</p>
<h3>Setup</h3>
<p>Before beginning, you must have Visual Studio 2008 SP1 or Visual Web Developer Express SP1.&nbsp; Be sure to install
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=c22d6a7b-546f-4407-8ef6-d60c8ee221ed&amp;displaylang=en">
Silverlight 2 Tools</a> in order to create and run the project.&nbsp; Once you have that, start a new Silverlight Application and call it BlurayDVDCompare, or whatever you desire.&nbsp; As shown in figure 1, choose the option to host Silverlight with an ASP.NET web application.
 This will create a web project and a separate Silverlight project.&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp; </p>
<p><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/figure1_2.png"><img src="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/figure1_thumb.png" alt="figure1" border="0" height="311" width="349"></a>
</p>
<p>&nbsp; </p>
<h3>Creating the UI </h3>
<p>Since we will be displaying HD images (1920x1080), our next step is to ensure that the browser adds scrollbars so that the entire Silverlight control can be seen.&nbsp; To do this, we need to open and edit the hosting web page (BlurayDVDCompareTestPage.aspx)
 and set the Width and Height properties of the Silverlight control to 1920 x 1200 as shown below.&nbsp; The 1200 is extra room for other controls that we will add.
</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>asp:Silverlight</span> <span>ID</span><span>=&quot;Xaml1&quot;</span> <span>runat</span><span>=&quot;server&quot;</span><br><span>Source</span><span>=&quot;~/ClientBin/BlurayDVDCompare.xap&quot;</span><br><span>MinimumVersion</span><span>=&quot;2.0.31005.0&quot;</span> <span>Width</span><span>=&quot;1920&quot;</span> <span>Height</span><span>=&quot;1200&quot;</span> <span>/&gt;</span></pre>
<br>
</div>
<div>Our UI will be pretty simple.&nbsp; We will have a couple of textboxes which will be used so that a user can specify a URLs to images they wish to compare.&nbsp; We will also add a couple of progress indicators so that we can show progress when the images are being
 loaded.&nbsp;&nbsp; We will also have three radio buttons to allow the user to select which comparison mode they wish to use.&nbsp;
</div>
<p>The main part of our UI, will be the canvas that holds the two images that we are comparing.&nbsp; Each image has a clip region which will be used to display parts of each image or to hide/show an image.&nbsp; For example, in DualView mode, we want to display part
 of one image, and the remaining part of the second image.&nbsp; If no clip regions were set, the default behavior would force the second image to cover the first.&nbsp; The final thing we add is a border which we will be used to draw a line as a separator between the
 two images in DualView.&nbsp; In Rectangle view, the border is used to draw the rectangle.</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>&lt;</span><span>StackPanel</span><span>&gt;</span><br>    <span>&lt;</span><span>Canvas</span> <span>x:Name</span><span>=&quot;canvas&quot;</span> <span>Background</span><span>=&quot;White&quot;</span> <span>Width</span><span>=&quot;1920&quot;</span> <span>Height</span><span>=&quot;1080&quot;</span> <span>Margin</span><span>=&quot;0,5,0,0&quot;</span><span>&gt;</span>    <br>        <span>&lt;</span><span>Image</span> <span>x:Name</span><span>=&quot;img1&quot;</span> <span>Stretch</span><span>=&quot;None&quot;</span> <span>&gt;</span>        <br>            <span>&lt;</span><span>Image.Clip</span><span>&gt;</span><br>                <span>&lt;</span><span>RectangleGeometry</span>  <span>Rect</span><span>=&quot;0,0,960,1080&quot;</span> <span>x:Name</span><span>=&quot;rcImg1&quot;</span> <span>/&gt;</span><br>            <span>&lt;/</span><span>Image.Clip</span><span>&gt;</span><br>        <span>&lt;/</span><span>Image</span><span>&gt;</span><br><br>        <span>&lt;</span><span>Image</span> <span>x:Name</span><span>=&quot;img2&quot;</span> <span>Stretch</span><span>=&quot;None&quot;</span> <span>&gt;</span><br>            <span>&lt;</span><span>Image.Clip</span> <span>&gt;</span><br>                <span>&lt;</span><span>RectangleGeometry</span> <span>Rect</span><span>=&quot;960,0,1920,1080&quot;</span> <span>x:Name</span><span>=&quot;rcImg2&quot;</span>  <span>/&gt;</span><br>            <span>&lt;/</span><span>Image.Clip</span><span>&gt;</span><br>        <span>&lt;/</span><span>Image</span><span>&gt;</span>    <br>            <br>        <span>&lt;</span><span>Border</span> <span>x:Name</span><span>=&quot;border&quot;</span> <span>Width</span><span>=&quot;2&quot;</span> <span>Height</span><span>=&quot;1920&quot;</span> <span>Margin</span><span>=&quot;0,0,0,0&quot;</span> <span>BorderBrush</span><span>=&quot;Bisque&quot;</span> <span>BorderThickness</span><span>=&quot;0&quot;</span> <span>/&gt;</span><br>    <span>&lt;/</span><span>Canvas</span><span>&gt;</span><br><span>&lt;/</span><span>StackPanel</span><span>&gt;</span></pre>
<br>
</div>
<div>&nbsp;</div>
<h3>Implementation</h3>
<div>Since we want to allow the application to load images from the web, we define the LoadImages() method which accepts two URLs.&nbsp; In order to do this, we create new BitmapImage objects with the given URLs.&nbsp; This will load the images asynchronously and we
 will assign them as the image Source property for the two UIElements.&nbsp; Once loading has finished, they will automatically appear in the canvas.&nbsp;
</div>
<div>&nbsp;</div>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> LoadImages(<span>string</span> s1, <span>string</span> s2)<br>{<br>    brLoading.Visibility = Visibility.Visible;<br>    spLoadingError.Visibility = Visibility.Collapsed;<br><br>    <span>if</span> (<span>string</span>.IsNullOrEmpty(s1) || <span>string</span>.IsNullOrEmpty(s2))<br>    {<br>        txtLoadingError.Text = <span>&quot;Invalid image location given&quot;</span>;<br>        brLoading.Visibility = Visibility.Collapsed;<br>        spLoadingError.Visibility = Visibility.Visible;<br>        <span>return</span>;<br>    }<br><br>    prgLoading1.Value = 0;<br>    prgLoading2.Value = 0;<br>    <br>    _bmi1 = <span>new</span> BitmapImage();<br>    _bmi2 = <span>new</span> BitmapImage();<br>    _bmi1.DownloadProgress &#43;= <span>new</span> EventHandler&lt;DownloadProgressEventArgs&gt;(bmi1_DownloadProgress);<br>    _bmi2.DownloadProgress &#43;= <span>new</span> EventHandler&lt;DownloadProgressEventArgs&gt;(bmi2_DownloadProgress);<br><br>    _bmi1.UriSource = <span>new</span> Uri(s1, UriKind.Absolute);<br>    _bmi2.UriSource = <span>new</span> Uri(s2, UriKind.Absolute);<br><br>    img1.Source = _bmi1;<br>    img2.Source = _bmi2;           <br>}</pre>
<br>
</div>
<div>&nbsp;</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> LoadImages(<span>ByVal</span> s1 <span>As</span> <span>String</span>, <span>ByVal</span> s2 <span>As</span> <span>String</span>)<br>    brLoading.Visibility = Visibility.Visible<br>    spLoadingError.Visibility = Visibility.Collapsed<br><br>    <span>If</span> <span>String</span>.IsNullOrEmpty(s1) <span>OrElse</span> <span>String</span>.IsNullOrEmpty(s2) <span>Then</span><br>        txtLoadingError.Text = <span>&quot;Invalid image location given&quot;</span><br>        brLoading.Visibility = Visibility.Collapsed<br>        spLoadingError.Visibility = Visibility.Visible<br>        <span>Return</span><br>    <span>End</span> <span>If</span><br><br>    prgLoading1.Value = 0<br>    prgLoading2.Value = 0<br><br>    _bmi1 = <span>New</span> BitmapImage()<br>    _bmi2 = <span>New</span> BitmapImage()<br>    <span>AddHandler</span> _bmi1.DownloadProgress, <span>AddressOf</span> bmi1_DownloadProgress<br>    <span>AddHandler</span> _bmi2.DownloadProgress, <span>AddressOf</span> bmi2_DownloadProgress<br><br>    _bmi1.UriSource = <span>New</span> Uri(s1, UriKind.Absolute)<br>    _bmi2.UriSource = <span>New</span> Uri(s2, UriKind.Absolute)<br><br>    img1.Source = _bmi1<br>    img2.Source = _bmi2<br><span>End</span> Sub</pre>
<br>
</div>
<div>Now that we have a way to load images, the next step is to handle the different type of comparison modes.&nbsp;&nbsp; We will start with the dual view since that will be our default mode.&nbsp; As mentioned earlier, the dual view basically shows both images side by side
 in such a way where both images are presented as one. The first image is partially shown, and the second is shown as a continuation of the first.&nbsp; In order to do this, we track the mouse movement when it is inside of the canvas by setting up a MouseMove event
 handler.&nbsp; Every time the mouse moves, we grab the new x,y coordinates.&nbsp; Since dual view is only concerned with left/right movement, we only pass in the x coordinate.&nbsp;&nbsp;&nbsp;
</div>
<div>&nbsp;</div>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>void</span> canvas_MouseMove(<span>object</span> sender, MouseEventArgs e)<br>{<br>    <span>double</span> x = e.GetPosition(canvas).X;<br>    <span>double</span> y = e.GetPosition(canvas).Y;<br>    <br>    <span>if</span> (_comparisonMode == ComparisonMode.DualView)<br>        DisplayDualView(x);<br>    <span>else</span> <span>if</span> (_comparisonMode == ComparisonMode.Rectangle)<br>    {<br>        <span>// ...</span><br>    }<br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> canvas_MouseMove(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> MouseEventArgs)<br>    <span>Dim</span> x <span>As</span> <span>Double</span> = e.GetPosition(canvas).X<br>    <span>Dim</span> y <span>As</span> <span>Double</span> = e.GetPosition(canvas).Y<br><br>    <span>If</span> _comparisonMode = ComparisonMode.DualView <span>Then</span><br>        DisplayDualView(x)<br>    <span>ElseIf</span> _comparisonMode = ComparisonMode.Rectangle <span>Then</span>            <span>' .....</span><br>    <span>End</span> <span>If</span><br><span>End</span> Sub</pre>
<br>
</div>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> DisplayDualView(<span>double</span> x)<br>{<br>    rcImg1.Rect = <span>new</span> Rect(0, 0, x, IMGHEIGHT);         <span>// Show the first half (left side), up to xCoord</span><br>    rcImg2.Rect = <span>new</span> Rect(x, 0, IMGWIDTH, IMGHEIGHT);  <span>// Show the second-half (right side), starting from xCoord</span><br><br>    Canvas.SetLeft(border, x);                          <span>// make the separator start at x</span><br>    Canvas.SetTop(border, 0);                           <span>// set the separator to the top</span><br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> DisplayDualView(<span>ByVal</span> x <span>As</span> <span>Double</span>)<br>    rcImg1.Rect = <span>New</span> Rect(0, 0, x, IMGHEIGHT)         <span>' Show the first half (left side), up to xCoord</span><br>    rcImg2.Rect = <span>New</span> Rect(x, 0, IMGWIDTH, IMGHEIGHT)  <span>' Show the second-half (right side), starting from xCoord</span><br><br>    Canvas.SetLeft(border, x) <span>' make the separator start at x</span><br>    Canvas.SetTop(border, 0)  <span>' set the separator to the top</span><br><span>End</span> <span>Sub</span><br></pre>
<br>
</div>
<div><b></b>&nbsp;</div>
<div>The DisplayDualView() method sets the image clip region of the first image to be a rectangle starting from pixel 0 to pixel x, then sets the clip region of the second image to be the remaining pixels.&nbsp; It uses our border to represent a break in the two
 images so that it is clear where our mouse is. Note that the border is defined as having a width of 2 and a height of 1080 in order to display as a single line separating the two images.&nbsp; The border size is defined when the comparison mode is selected.</div>
<div>&nbsp;</div>
<div>For the next comparison, we will focus on is the swap view mode.&nbsp; This is the easiest one to implement.&nbsp; In this, we show the first image in its entirety until the user places the mouse inside the canvas.&nbsp; When that happens, the second image is displayed
 until the user moves the mouse outside of the canvas. </div>
<div>&nbsp;</div>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> DisplaySwapView(<span>bool</span> mouseOver)<br>{<br>    <span>if</span> (!mouseOver)<br>    {<br>        rcImg1.Rect = <span>new</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT);<br>        rcImg2.Rect = <span>new</span> Rect(0, 0, 0, 0);<br>    }<br>    <span>else</span><br>    {<br>        rcImg1.Rect = <span>new</span> Rect(0, 0, 0, 0);<br>        rcImg2.Rect = <span>new</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT);<br>    }<br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> DisplaySwapView(<span>ByVal</span> mouseOver <span>As</span> <span>Boolean</span>)<br>    <span>If</span> (<span>Not</span> mouseOver) <span>Then</span><br>        rcImg1.Rect = <span>New</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT)<br>        rcImg2.Rect = <span>New</span> Rect(0, 0, 0, 0)<br>    <span>Else</span><br>        rcImg1.Rect = <span>New</span> Rect(0, 0, 0, 0)<br>        rcImg2.Rect = <span>New</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT)<br>    <span>End</span> <span>If</span><br><span>End</span> <span>Sub</span><br></pre>
<br>
</div>
<div><b></b></div>
<div>Our DisplaySwapView() method is very basic in that it basically uses the clip region to show an entire image, or to show none of the image depending on the value of the passed in bool, mouseOver.&nbsp; When mouseOver is false, we show the first image, when
 true we show the second image.&nbsp; While we could have used the Visibility property to show/hide the images, we use clipping in order to be consistent with our other modes.</div>
<p>The rectangle view is the last and most involved.&nbsp; Since the user will be drawing a rectangle with the mouse, we must keep track of mouse movement, the state of the mouse button, and the coordinates for the rectangle.&nbsp; We also need to display the rectangle
 as the user is drawing it and update clipped area of the image in real time in.&nbsp; In order to make this easier, we create a class called MouseRectangle will contain the important information about the mouse state and rectangle size and location.&nbsp;
</p>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>public</span> <span>class</span> MouseRectangle<br>{<br>    <span>public</span> <span>bool</span> MouseLeftButtonDown { get; set;}<br>    <span>private</span> Rect _rtg;<br><br>    <span>private</span> <span>double</span>? _startX;<br>    <span>private</span> <span>double</span>? _startY;<br><br>    <span>public</span> <span>bool</span> RectangleIsDrawn { get; set; }<br>    <span>public</span> Rect Rectangle { get { <span>return</span> _rtg;} }<br><br>    <span>public</span> MouseRectangle()<br>    {<br>        RectangleIsDrawn = <span>false</span>;<br>    }<br><br>    <span>public</span> <span>void</span> Reset()<br>    {<br>        _startX = <span>null</span>;<br>        _startY = <span>null</span>;<br>        RectangleIsDrawn = <span>false</span>;<br>    }<br><br>    <span>public</span> <span>void</span> CalculateRectangle(<span>double</span> x, <span>double</span> y)<br>    {<br>        <span>if</span> (_startX == <span>null</span>)<br>            _startX = x;<br>        <span>if</span> (_startY == <span>null</span>)<br>            _startY = y;<br><br>        <span>// pick the smaller of the two</span><br>        <span>double</span> left = Math.Min(_startX.Value, x);<br>        <span>double</span> top = Math.Min(_startY.Value, y);<br><br>        _rtg = <span>new</span> Rect(left, top, Math.Abs(_startX.Value - x), Math.Abs(_startY.Value - y));             <br>    }<br><br>    <span>public</span> <span>bool</span> InBoundsOfRect(<span>double</span> x, <span>double</span> y)<br>    {<br>        <span>if</span> (x &gt; _rtg.Left &amp;&amp; x &lt; _rtg.Right &amp;&amp;<br>            y &gt; _rtg.Top &amp;&amp; y &lt; _rtg.Bottom)<br>            <span>return</span> <span>true</span>;<br>        <span>return</span> <span>false</span>;<br>    }<br><br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Public</span> <span>Class</span> MouseRectangle<br>    <span>Private</span> privateMouseLeftButtonDown <span>As</span> <span>Boolean</span><br>    <span>Public</span> <span>Property</span> MouseLeftButtonDown() <span>As</span> <span>Boolean</span><br>        <span>Get</span><br>            <span>Return</span> privateMouseLeftButtonDown<br>        <span>End</span> <span>Get</span><br>        <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Boolean</span>)<br>            privateMouseLeftButtonDown = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br>    <span>Private</span> _rtg <span>As</span> Rect<br><br>    <span>Private</span> _startX? <span>As</span> <span>Double</span><br>    <span>Private</span> _startY? <span>As</span> <span>Double</span><br><br>    <span>Private</span> privateRectangleIsDrawn <span>As</span> <span>Boolean</span><br>    <span>Public</span> <span>Property</span> RectangleIsDrawn() <span>As</span> <span>Boolean</span><br>        <span>Get</span><br>            <span>Return</span> privateRectangleIsDrawn<br>        <span>End</span> <span>Get</span><br>        <span>Set</span>(<span>ByVal</span> value <span>As</span> <span>Boolean</span>)<br>            privateRectangleIsDrawn = value<br>        <span>End</span> <span>Set</span><br>    <span>End</span> <span>Property</span><br>    <span>Public</span> <span>ReadOnly</span> <span>Property</span> Rectangle() <span>As</span> Rect<br>        <span>Get</span><br>            <span>Return</span> _rtg<br>        <span>End</span> <span>Get</span><br>    <span>End</span> <span>Property</span><br><br>    <span>Public</span> <span>Sub</span> <span>New</span>()<br>        RectangleIsDrawn = <span>False</span><br>    <span>End</span> <span>Sub</span><br><br>    <span>Public</span> <span>Sub</span> Reset()<br>        _startX = <span>Nothing</span><br>        _startY = <span>Nothing</span><br>        RectangleIsDrawn = <span>False</span><br>    <span>End</span> <span>Sub</span><br><br>    <span>Public</span> <span>Sub</span> CalculateRectangle(<span>ByVal</span> x <span>As</span> <span>Double</span>, <span>ByVal</span> y <span>As</span> <span>Double</span>)<br>        <span>If</span> <span>Not</span> _startX.HasValue <span>Then</span><br>            _startX = x<br>        <span>End</span> <span>If</span><br>        <span>If</span> <span>Not</span> _startY.HasValue <span>Then</span><br>            _startY = y<br>        <span>End</span> <span>If</span><br><br>        <span>' pick the smaller of the two</span><br>        <span>Dim</span> left <span>As</span> <span>Double</span> = Math.Min(_startX.Value, x)<br>        <span>Dim</span> top <span>As</span> <span>Double</span> = Math.Min(_startY.Value, y)<br><br>        _rtg = <span>New</span> Rect(left, top, Math.Abs(_startX.Value - x), Math.Abs(_startY.Value - y))<br>    <span>End</span> <span>Sub</span><br><br>    <span>Public</span> <span>Function</span> InBoundsOfRect(<span>ByVal</span> x <span>As</span> <span>Double</span>, <span>ByVal</span> y <span>As</span> <span>Double</span>) <span>As</span> <span>Boolean</span><br>        <span>If</span> x &gt; _rtg.Left <span>AndAlso</span> x &lt; _rtg.Right <span>AndAlso</span> y &gt; _rtg.Top <span>AndAlso</span> y &lt; _rtg.Bottom <span>Then</span><br>            <span>Return</span> <span>True</span><br>        <span>End</span> <span>If</span><br>        <span>Return</span> <span>False</span><br>    <span>End</span> <span>Function</span><br><br><span>End</span> Class</pre>
<br>
</div>
<div>The MouseLeftButtonDown property keeps track of whether the left button is currently being held down.&nbsp; There is also a Rect (_rtg) object which contains the location and dimension of the rectangle that has been drawn.&nbsp; The _startX and _startY member variables
 are nullable doubles used to keep track of the initial location where the mouse button was pressed.&nbsp;
</div>
<div>&nbsp;</div>
<div>Our CalculateRectangle() method is what we use to create the dimensions and location of the rectangle.&nbsp; We start by looking at the inital x,y coordinates, and if they are not set, it means the rectangle hasn't been drawn.&nbsp; In that case, a 0 pixel rectangle
 will be created.&nbsp; If those values are already set, we create the rectangle based on the x and y values passed in.</div>
<div>&nbsp;</div>
<div>The InBoundsOfRect() method is a simple helper function that will tell us whether or not an x,y coordinate is within the bounds of the rectangle.
</div>
<div>&nbsp;</div>
<div>When in rectangle mode, the rectangle drawing begins when the mouse's left button is pressed down, and when the mouse is de-pressed, the drawing ends, and we consider the rectangle complete.</div>
<div>&nbsp;</div>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>void</span> canvas_MouseLeftButtonDown(<span>object</span> sender, MouseButtonEventArgs e)<br>{<br>    _mouseRectangle.Reset();<br>    _mouseRectangle.MouseLeftButtonDown = <span>true</span>;<br>}<br><br><span>void</span> canvas_MouseLeftButtonUp(<span>object</span> sender, MouseButtonEventArgs e)<br>{<br>    _mouseRectangle.MouseLeftButtonDown = <span>false</span>;<br>    _mouseRectangle.RectangleIsDrawn = <span>true</span>;<br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> canvas_MouseLeftButtonDown(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> MouseButtonEventArgs)<br>    _mouseRectangle.Reset()<br>    _mouseRectangle.MouseLeftButtonDown = <span>True</span><br><span>End</span> <span>Sub</span><br><br><span>Private</span> <span>Sub</span> canvas_MouseLeftButtonUp(<span>ByVal</span> sender <span>As</span> <span>Object</span>, <span>ByVal</span> e <span>As</span> MouseButtonEventArgs)<br>    _mouseRectangle.MouseLeftButtonDown = <span>False</span><br>    _mouseRectangle.RectangleIsDrawn = <span>True</span><br><span>End</span> Sub</pre>
<br>
</div>
<div>While in rectangle mode, when the mouse moves over the canvas, there are two different states.&nbsp; If the mouse button is pressed, it means the user is drawing, and our goal is to update the rectangle to match the location where the user's mouse is in relation
 to the canvas.</div>
<div>&nbsp;</div>
<div><b>C#</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">...<br><span>else</span> <span>if</span> (_comparisonMode == ComparisonMode.Rectangle)<br>{<br>    <span>if</span> (_mouseRectangle.MouseLeftButtonDown)<br>        DrawRectangle(x,y);<br>    <span>else</span> <span>if</span> (_mouseRectangle.RectangleIsDrawn)<br>        DisplayRectangleView(x,y);<br>}<br>...</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet">...<br><span>ElseIf</span> _comparisonMode = ComparisonMode.Rectangle <span>Then</span><br>    <span>If</span> _mouseRectangle.MouseLeftButtonDown <span>Then</span><br>        DrawRectangle(x,y)<br>    <span>ElseIf</span> _mouseRectangle.RectangleIsDrawn <span>Then</span><br>        DisplayRectangleView(x,y)<br>    <span>End</span> <span>If</span><br><span>End</span> <span>If</span><br>...</pre>
<br>
</div>
<div>The DrawRectangle() method starts out by calculating the rectangle based on the current x,y coordinates.&nbsp; We then set the border to represent our rectangle outline by sitting its location based on the _mouseRectangle's Rectangle property.&nbsp; Finally we draw
 the first image in its entirety, and the second image will only display the portion of the image based on the rectangle's location and width/height information.&nbsp; This will result in seeing the the first image with the rectangular portion showing the corresponding
 2nd image.</div>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> DrawRectangle(<span>double</span> x, <span>double</span> y)<br>{<br>    _mouseRectangle.CalculateRectangle(x,y);<br><br>    Canvas.SetLeft(border, _mouseRectangle.Rectangle.Left);<br>    Canvas.SetTop(border, _mouseRectangle.Rectangle.Top);<br>    border.Width = _mouseRectangle.Rectangle.Width;<br>    border.Height = _mouseRectangle.Rectangle.Height;<br><br>    rcImg1.Rect = <span>new</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT);<br>    rcImg2.Rect = _mouseRectangle.Rectangle;<br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> DrawRectangle(<span>ByVal</span> x <span>As</span> <span>Double</span>, <span>ByVal</span> y <span>As</span> <span>Double</span>)<br>    _mouseRectangle.CalculateRectangle(x, y)<br><br>    Canvas.SetLeft(border, _mouseRectangle.Rectangle.Left)<br>    Canvas.SetTop(border, _mouseRectangle.Rectangle.Top)<br>    border.Width = _mouseRectangle.Rectangle.Width<br>    border.Height = _mouseRectangle.Rectangle.Height<br><br>    rcImg1.Rect = <span>New</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT)<br>    rcImg2.Rect = _mouseRectangle.Rectangle<br><span>End</span> Sub</pre>
<br>
</div>
<div>When the mouse button has been de-pressed, and the rectangle has been completed, we add the ability to do a mouse over effect for the rectangular region.&nbsp; While the mouse is located outside of the drawn rectangle, we leave it as is.&nbsp; If the user moves
 the mouse within the rectangle, we want them to see what the original looked like, so we display only the first image.&nbsp;
</div>
<p><b>C#</b></p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>private</span> <span>void</span> DisplayRectangleView(<span>double</span> x, <span>double</span> y)<br>{<br>    rcImg1.Rect = <span>new</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT);<br><br>    <span>if</span> (_mouseRectangle.InBoundsOfRect(x,y))<br>        rcImg2.Rect = <span>new</span> Rect(0, 0, 0, 0);<br>    <span>else</span><br>        rcImg2.Rect = _mouseRectangle.Rectangle;<br><br>}</pre>
<br>
</div>
<div><b>VB</b></div>
<div id="codeSnippetWrapper">
<pre id="codeSnippet"><span>Private</span> <span>Sub</span> DisplayRectangleView(<span>ByVal</span> x <span>As</span> <span>Double</span>, <span>ByVal</span> y <span>As</span> <span>Double</span>)<br>    rcImg1.Rect = <span>New</span> Rect(0, 0, IMGWIDTH, IMGHEIGHT)<br><br>    <span>If</span> _mouseRectangle.InBoundsOfRect(x, y) <span>Then</span><br>        rcImg2.Rect = <span>New</span> Rect(0, 0, 0, 0)<br>    <span>Else</span><br>        rcImg2.Rect = _mouseRectangle.Rectangle<br>    <span>End</span> <span>If</span><br><br><span>End</span> Sub</pre>
<br>
</div>
<div>&nbsp;</div>
<h3>Conclusion &amp; Future Work</h3>
<p>Overall, the blu-ray DVD comparison utility is a pretty straight-forward Silverlight application that you can use to see the differences between two images.&nbsp; These images don't even need to be from blu-ray or DVD sources, but as long as they are the right
 dimension, a user can use it to see subtle differences between the two by allowing three different comparison modes.&nbsp; For blu-ray purchases when you already own the DVD, I think it helps to see what kind of benefit you will get by moving to blu-ray.&nbsp; It has
 been my experience that almost every blu-ray offers some type of picture upgrade over its DVD counterpart (and sound upgrade as well).&nbsp; Sometimes the differences are subtle, sometimes they are incredibly better.&nbsp; There are a lot of factors involved, but&nbsp;
</p>
<p>Some future work that can be done to this is adding the ability to zoom in and out on the images in order to be able to see differences in a closer view.&nbsp;&nbsp; Soon there will be more movies which will be re-released on blu-ray and you can use the tool to compare
 the old release to the new one.&nbsp; This will require zooming to see some of the more finer differences.&nbsp; Other work can be done by creating a database to hold links, and have a control that allows a user to navigate to different movies and view different comparisons.&nbsp;
 I have started doing both of these, but they were not ready for this article. </p>
<p>One definite area that needs work is the UI.&nbsp; I am not good at laying out user interfaces or creating new xaml styles, so I left them default.&nbsp;
</p>
<p>What would be really useful is a full motion comparison where you can use similar modes to see how two movies compare while in motion, but the biggest problem would be finding or creating the comparison material.&nbsp; Playback would be limiting as well since
 it requires higher end CPUs/video cards.&nbsp;&nbsp; </p>
<h3>Comparisons</h3>
<p>Here are a few URLs you can use to play with the comparison utility:</p>
<table border="0" cellpadding="2" cellspacing="0" width="459">
<tbody>
<tr>
<td valign="top" width="109">&nbsp;</td>
<td valign="top" width="348">URL of Standard Def image (DVD) / HD (Blu-ray)</td>
</tr>
<tr>
<td valign="top" width="109">Prince Caspian</td>
<td valign="top" width="348"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_sd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_sd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_sd.png</a>
<br>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_hd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_hd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_hd.png</a></td>
</tr>
<tr>
<td valign="top" width="109">Prince Caspian</td>
<td valign="top" width="348"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_2_sd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_sd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_2_sd.png</a>
<br>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_2_hd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_1_hd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/pc_2_hd.png</a></td>
</tr>
<tr>
<td valign="top" width="109">Iron Man</td>
<td valign="top" width="348"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_1_sd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_1_sd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_1_sd.png</a>
<br>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_1_hd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_1_hd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_1_hd.png</a></td>
</tr>
<tr>
<td valign="top" width="109">Iron Man</td>
<td valign="top" width="348"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_2_sd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_2_sd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_2_sd.png</a>
<br>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_2_hd.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_2_hd.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/im_2_hd.png</a></td>
</tr>
<tr>
<td valign="top" width="109">Entrapment</td>
<td valign="top" width="348"><a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/Ent_4_SD.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/Ent_4_SD.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/Ent_4_SD.png</a>
<br>
<a href="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/Ent_4_HD.png" title="http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/Ent_4_HD.png">http://ecn.channel9.msdn.com/o9/c4fcontent/migration/9515699/Ent_4_HD.png</a></td>
</tr>
</tbody>
</table>
<p>Note: Images were copied from the blu-ray threads of A/V Science Forum: <a href="http://www.avsforum.com/">
www.avsforum.com</a> .</p>
<h3>Thanks</h3>
<p>I would like to thank <a href="http://www.brianpeek.com/" target="_blank">Brian Peek</a> for introducing me to Coding4Fun, and taking the time to review my article and test the code.</p>
 <img src="http://m.webtrends.com/dcs1wotjh10000w0irc493s0e_6x1g/njs.gif?dcssip=channel9.msdn.com&dcsuri=http://channel9.msdn.com/Niners/c4f.Giovanni-Montrone/Posts/RSS&WT.dl=0&WT.entryid=Entry:RSSView:e3d3615b2a654770a9729e7600ccf464">]]></description>
      <comments>http://channel9.msdn.com/coding4fun/articles/Blu-rayDVD-Comparison-Utility</comments>
      <itunes:summary>



In this article, Giovanni Montrone will provide an overview on how to create an image comparison application for DVD and Blu-ray screen captures.



Giovanni Montrone
ASPSOFT, Inc.

Difficulty: Beginner
Time Required: 2-3 hours
Cost: Free
Software: Visual Web Developer Express SP1 (or Visual Studio 2008 SP1),

Silverlight 2 Tools
Hardware: None
Application: Run the application
Source Download: Download the source




&amp;nbsp; 
Introduction
As a fan of High Definition movies and television, I often find it difficult to explain the benefits of upgrading from DVD to blu-ray to family and friends.&amp;nbsp; Many people believe that DVDs look good enough and/or that you need a really big television to notice
 the difference, and, even then, feel the improvement is not good enough to justify the upgrade.&amp;nbsp; The best way to convince someone is to show him/her the same movie playing side by side on blu-ray and dvd using the same sized screens.&amp;nbsp; Since it&#39;s difficult
 to do, the next best thing is to look at still images from both the DVD and the blu-ray and compare them.&amp;nbsp; The images should be from the exact same scene.&amp;nbsp; Fortunately there are places on the web such as
AVSForum where members take the time to do this.&amp;nbsp; They usually do this to help people determine what kind of an upgrade they can expect when viewing the blu-ray compared to the DVD.&amp;nbsp; Sometimes the differences are easy
 to see, and other times they are not as clear.&amp;nbsp; I built this comparison tool as a way to see what differences exist, and provided a few ways to make those differences easier to see.&amp;nbsp;
 
This utility will allow the user to compare two different images using 3 different modes: dual view, swap view, and Rectangle View. Dual view will allow a side by side comparison where you see part of the first image, and the remaining part of the second
 image. Moving the mouse left or right will show more of one image, and less of the other. The swap mode will allow the user to </itunes:summary>
      <link>http://channel9.msdn.com/coding4fun/articles/Blu-rayDVD-Comparison-Utility</link>
      <pubDate>Sat, 28 Mar 2009 04:30:00 GMT</pubDate>
      <guid isPermaLink="false">http://channel9.msdn.com/coding4fun/articles/Blu-rayDVD-Comparison-Utility</guid>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9515699_100.jpg" height="75" width="100"></media:thumbnail>
      <media:thumbnail url="http://ecn.channel9.msdn.com/o9/c4f/images/9515699_220.jpg" height="165" width="220"></media:thumbnail>      
      <dc:creator>Giovanni Montrone </dc:creator>
      <itunes:author>Giovanni Montrone </itunes:author>
      <slash:comments>2</slash:comments>
      <wfw:commentRss>http://channel9.msdn.com/coding4fun/articles/Blu-rayDVD-Comparison-Utility/RSS</wfw:commentRss>
      <category>Media</category>
      <category>Silverlight</category>
      <category>Web</category>
    </item>    
</channel>
</rss>