<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" 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:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Colby Cavin - Windows Media Player</title>
    <link>http://www.cavinconsulting.com/Colby/</link>
    <description />
    <language>en-us</language>
    <copyright>Cavin Consulting</copyright>
    <lastBuildDate>Wed, 09 Jul 2008 11:44:04 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.1.8102.813</generator>
    <managingEditor>colby@cavinconsulting.com</managingEditor>
    <webMaster>colby@cavinconsulting.com</webMaster>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=e23b3b4e-84e3-448c-8acd-5ed18a63f930</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,e23b3b4e-84e3-448c-8acd-5ed18a63f930.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,e23b3b4e-84e3-448c-8acd-5ed18a63f930.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=e23b3b4e-84e3-448c-8acd-5ed18a63f930</wfw:commentRss>
      <slash:comments>4</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
          <strong>Update </strong>- The source for this article is available at <a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote7a.zip">http://www.cavinconsulting.com/Code/MediaPlayerRemote7a.zip</a>. 
</p>
        <p>
The current version of the Smart Client Software Factory comes with a clever WCF service
proxy recipe called the Disconnected Service Agent recipe. This recipe is a much nicer
version of the webservice proxy shipped with the prior version of the toolkit. One
of the nice parts of this recipe is the automatic online/offline detection capabilities.
At its root, the recipe uses a RequestManager to queue up and dispatch webservice
requests. Attached to the RequestManager is an IConnectionMonitor. By default, this
connection monitor automatically keeps track of a client's connection status.
</p>
        <p>
Unfortunately, this only determines if a client has a connection to the Internet,
not whether the client can actually call the webservice of interest. What we want
is to make sure the client is really "Online" with respect to the webservice it is
calling. There are a couple of ways we can do this. The toolkit allows us to plug
in our own service that implements IConnecitionMonitor. We could implement IConnectionMonitor
in our own custom service and add an attribute to the ConnectionMonitor tag in the
app.config file that would make the framework spin up our own, custom definition of
what it means to be "online". That's probably the right way to do things, but I decided
to implement a WebserviceMonitor service that simply polls the desired webservice
to make sure it is available.
</p>
        <p>
I added IConnectionMonitor.cs to Infrastructure.Interface/Services as an interface
with a single, read only property -- IsConnected, and a single event -- ConnectionStatusChanged.
Then, I added ConnectionMonitor.cs to Infrastructure.Module/Services as a class that
implements both IConnectionMonitor and IBuilderAware:
</p>
        <blockquote>
          <pre class="code">
            <span style="COLOR: blue">public class </span>
            <span style="COLOR: #2b91af">WebserviceMonitor </span>: <span style="COLOR: #2b91af">IWebserviceMonitor</span>, <span style="COLOR: #2b91af">IBuilderAware </span>{
... }</pre>
        </blockquote>
        <p>
The constructor of the class uses the existing IConnectionMonitor as a service dependency:
</p>
        <blockquote>
          <pre class="code">
            <span style="COLOR: blue">private </span>
            <span style="COLOR: #2b91af">IConnectionMonitor </span>_connectionMonitor; <span style="COLOR: blue">public </span>WebserviceMonitor([<span style="COLOR: #2b91af">ServiceDependency</span>] <span style="COLOR: #2b91af">IConnectionMonitor </span>connectionMonitor)
{ _connectionMonitor = connectionMonitor; _connectionMonitor.ConnectionStatusChanged
+= <span style="COLOR: blue">new </span><span style="COLOR: #2b91af">EventHandler</span>(connectionMonitor_ConnectionStatusChanged);
}</pre>
        </blockquote>
        <p>
The IConnectionMonitor manages whether the machine is online or offline. So, we need
to manage the other half (whether we can get to the webservice). So, we implement
a member method to answer the question: 
</p>
        <blockquote>
          <pre class="code">
            <span style="COLOR: blue">private void </span>UpdateConnectedStatus()
{ <span style="COLOR: blue">bool </span>wasConnected = _connected; _connected = _connectionMonitor.IsConnected
&amp;&amp; WebserviceAvailable(); <span style="COLOR: blue">if </span>(wasConnected
!= _connected) OnConnectionStatusChanged(_connected); }</pre>
        </blockquote>
        <p>
With that, we can call UpdateConnectedStatus on creation as well as any time ConnectionStatusChanged
is fired by the connection manager. When we sense a connection change, we fire our
own ConnectionStatusChanged event using the built-in event mechanism:
</p>
        <blockquote>
          <pre class="code">[<span style="COLOR: #2b91af">EventPublication</span>(<span style="COLOR: #2b91af">EventTopicNames</span>.OnlineOfflineUpdate,<span style="COLOR: #2b91af">PublicationScope</span>.Global)] <span style="COLOR: blue">public
event </span><span style="COLOR: #2b91af">EventHandler</span>&lt;<span style="COLOR: #2b91af">EventArgs</span>&lt;<span style="COLOR: blue">bool</span>&gt;&gt;
ConnectionStatusChanged;</pre>
        </blockquote>
        <p>
But this doesn't solve the problem completely. Why not? The webservice status is only
updated in the event of a connection status change as fired by the IConnectionMonitor.
So, how do we make sure the webservice status is updated periodically, even if the
connection status doesn't change? One solution is to use a thread timer in the service
to make periodic calls to the webservice. We can implement this by taking advantage
of our IBuilderAware methods:
</p>
        <blockquote>
          <pre class="code">
            <span style="COLOR: blue">public void </span>OnBuiltUp(<span style="COLOR: blue">string </span>id)
{ _connectionCheckTimer = <span style="COLOR: blue">new </span>System.Threading.<span style="COLOR: #2b91af">Timer</span>(<span style="COLOR: blue">new </span>System.Threading.<span style="COLOR: #2b91af">TimerCallback</span>(Tick), <span style="COLOR: blue">null</span>,
0, PingDelay); } <span style="COLOR: blue">public void </span>OnTearingDown() { <span style="COLOR: blue">if </span>(<span style="COLOR: blue">null </span>!=
_connectionCheckTimer) { _connectionCheckTimer.Dispose(); _connectionCheckTimer = <span style="COLOR: blue">null</span>;
} }</pre>
        </blockquote>
        <p>
There are the basic steps for producing a webservice monitor within the SCSF. I'm
sure there are better ways of solving the problem, but this one works pretty well
for my needs. Of course, subscribing to the service is as easy as getting a reference
to the service or subscribing to the global event:
</p>
        <blockquote>
          <pre class="code">[<span style="COLOR: #2b91af">EventSubscription</span>(<span style="COLOR: #2b91af">EventTopicNames</span>.OnlineOfflineUpdate, <span style="COLOR: #2b91af">ThreadOption</span>.UserInterface)] <span style="COLOR: blue">public
void </span>OnlineOfflineUpdateHandler(<span style="COLOR: blue">object </span>sender, <span style="COLOR: #2b91af">EventArgs</span>&lt;<span style="COLOR: blue">bool</span>&gt;
e) { _onlineOfflineLabel.Text = e.Data ? <span style="COLOR: #a31515">"Online" </span>: <span style="COLOR: #a31515">"Offline"</span>;
}</pre>
        </blockquote>
        <p>
Hope this helps.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=e23b3b4e-84e3-448c-8acd-5ed18a63f930" />
      </body>
      <title>Windows Media Player Remote Control - 7a - Online / Offline Detection with the SCSF</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,e23b3b4e-84e3-448c-8acd-5ed18a63f930.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/07/09/WindowsMediaPlayerRemoteControl7aOnlineOfflineDetectionWithTheSCSF.aspx</link>
      <pubDate>Wed, 09 Jul 2008 11:44:04 GMT</pubDate>
      <description>&lt;p&gt;
&lt;strong&gt;Update &lt;/strong&gt;- The source for this article is available at &lt;a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote7a.zip"&gt;http://www.cavinconsulting.com/Code/MediaPlayerRemote7a.zip&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
The current version of the Smart Client Software Factory comes with a clever WCF service
proxy recipe called the Disconnected Service Agent recipe. This recipe is a much nicer
version of the webservice proxy shipped with the prior version of the toolkit. One
of the nice parts of this recipe is the automatic online/offline detection capabilities.
At its root, the recipe uses a RequestManager to queue up and dispatch webservice
requests. Attached to the RequestManager is an IConnectionMonitor. By default, this
connection monitor automatically keeps track of a client's connection status.
&lt;/p&gt;
&lt;p&gt;
Unfortunately, this only determines if a client has a connection to the Internet,
not whether the client can actually call the webservice of interest. What we want
is to make sure the client is really "Online" with respect to the webservice it is
calling. There are a couple of ways we can do this. The toolkit allows us to plug
in our own service that implements IConnecitionMonitor. We could implement IConnectionMonitor
in our own custom service and add an attribute to the ConnectionMonitor tag in the
app.config file that would make the framework spin up our own, custom definition of
what it means to be "online". That's probably the right way to do things, but I decided
to implement a WebserviceMonitor service that simply polls the desired webservice
to make sure it is available.
&lt;/p&gt;
&lt;p&gt;
I added IConnectionMonitor.cs to Infrastructure.Interface/Services as an interface
with a single, read only property -- IsConnected, and a single event -- ConnectionStatusChanged.
Then, I added ConnectionMonitor.cs to Infrastructure.Module/Services as a class that
implements both IConnectionMonitor and IBuilderAware:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class=code&gt;&lt;span style="COLOR: blue"&gt;public class &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;WebserviceMonitor &lt;/span&gt;: &lt;span style="COLOR: #2b91af"&gt;IWebserviceMonitor&lt;/span&gt;, &lt;span style="COLOR: #2b91af"&gt;IBuilderAware &lt;/span&gt;{
... }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
The constructor of the class uses the existing IConnectionMonitor as a service dependency:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class=code&gt;&lt;span style="COLOR: blue"&gt;private &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;IConnectionMonitor &lt;/span&gt;_connectionMonitor; &lt;span style="COLOR: blue"&gt;public &lt;/span&gt;WebserviceMonitor([&lt;span style="COLOR: #2b91af"&gt;ServiceDependency&lt;/span&gt;] &lt;span style="COLOR: #2b91af"&gt;IConnectionMonitor &lt;/span&gt;connectionMonitor)
{ _connectionMonitor = connectionMonitor; _connectionMonitor.ConnectionStatusChanged
+= &lt;span style="COLOR: blue"&gt;new &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;EventHandler&lt;/span&gt;(connectionMonitor_ConnectionStatusChanged);
}&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
The IConnectionMonitor manages whether the machine is online or offline. So, we need
to manage the other half (whether we can get to the webservice). So, we implement
a member method to answer the question: 
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class=code&gt;&lt;span style="COLOR: blue"&gt;private void &lt;/span&gt;UpdateConnectedStatus()
{ &lt;span style="COLOR: blue"&gt;bool &lt;/span&gt;wasConnected = _connected; _connected = _connectionMonitor.IsConnected
&amp;amp;&amp;amp; WebserviceAvailable(); &lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(wasConnected
!= _connected) OnConnectionStatusChanged(_connected); }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
With that, we can call UpdateConnectedStatus on creation as well as any time ConnectionStatusChanged
is fired by the connection manager. When we sense a connection change, we fire our
own ConnectionStatusChanged event using the built-in event mechanism:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class=code&gt;[&lt;span style="COLOR: #2b91af"&gt;EventPublication&lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;EventTopicNames&lt;/span&gt;.OnlineOfflineUpdate,&lt;span style="COLOR: #2b91af"&gt;PublicationScope&lt;/span&gt;.Global)] &lt;span style="COLOR: blue"&gt;public
event &lt;/span&gt;&lt;span style="COLOR: #2b91af"&gt;EventHandler&lt;/span&gt;&amp;lt;&lt;span style="COLOR: #2b91af"&gt;EventArgs&lt;/span&gt;&amp;lt;&lt;span style="COLOR: blue"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt;
ConnectionStatusChanged;&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
But this doesn't solve the problem completely. Why not? The webservice status is only
updated in the event of a connection status change as fired by the IConnectionMonitor.
So, how do we make sure the webservice status is updated periodically, even if the
connection status doesn't change? One solution is to use a thread timer in the service
to make periodic calls to the webservice. We can implement this by taking advantage
of our IBuilderAware methods:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class=code&gt;&lt;span style="COLOR: blue"&gt;public void &lt;/span&gt;OnBuiltUp(&lt;span style="COLOR: blue"&gt;string &lt;/span&gt;id)
{ _connectionCheckTimer = &lt;span style="COLOR: blue"&gt;new &lt;/span&gt;System.Threading.&lt;span style="COLOR: #2b91af"&gt;Timer&lt;/span&gt;(&lt;span style="COLOR: blue"&gt;new &lt;/span&gt;System.Threading.&lt;span style="COLOR: #2b91af"&gt;TimerCallback&lt;/span&gt;(Tick), &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;,
0, PingDelay); } &lt;span style="COLOR: blue"&gt;public void &lt;/span&gt;OnTearingDown() { &lt;span style="COLOR: blue"&gt;if &lt;/span&gt;(&lt;span style="COLOR: blue"&gt;null &lt;/span&gt;!=
_connectionCheckTimer) { _connectionCheckTimer.Dispose(); _connectionCheckTimer = &lt;span style="COLOR: blue"&gt;null&lt;/span&gt;;
} }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
There are the basic steps for producing a webservice monitor within the SCSF. I'm
sure there are better ways of solving the problem, but this one works pretty well
for my needs. Of course, subscribing to the service is as easy as getting a reference
to the service or subscribing to the global event:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class=code&gt;[&lt;span style="COLOR: #2b91af"&gt;EventSubscription&lt;/span&gt;(&lt;span style="COLOR: #2b91af"&gt;EventTopicNames&lt;/span&gt;.OnlineOfflineUpdate, &lt;span style="COLOR: #2b91af"&gt;ThreadOption&lt;/span&gt;.UserInterface)] &lt;span style="COLOR: blue"&gt;public
void &lt;/span&gt;OnlineOfflineUpdateHandler(&lt;span style="COLOR: blue"&gt;object &lt;/span&gt;sender, &lt;span style="COLOR: #2b91af"&gt;EventArgs&lt;/span&gt;&amp;lt;&lt;span style="COLOR: blue"&gt;bool&lt;/span&gt;&amp;gt;
e) { _onlineOfflineLabel.Text = e.Data ? &lt;span style="COLOR: #a31515"&gt;"Online" &lt;/span&gt;: &lt;span style="COLOR: #a31515"&gt;"Offline"&lt;/span&gt;;
}&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Hope this helps.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=e23b3b4e-84e3-448c-8acd-5ed18a63f930" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,e23b3b4e-84e3-448c-8acd-5ed18a63f930.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=61f11d1f-bc88-4117-9ec9-bc3d46c9d964</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,61f11d1f-bc88-4117-9ec9-bc3d46c9d964.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,61f11d1f-bc88-4117-9ec9-bc3d46c9d964.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=61f11d1f-bc88-4117-9ec9-bc3d46c9d964</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
After using version 1.5 in the real world, I've realized it's time to make the solution
more robust, with higher performance. The 1.5 implementation is so bad, in fact, that
I'm not going to offer the source code as promised -- it just isn't release (even
alpha) quality. As implemented, if the server goes down or there is a momentary network
outage, I have to restart the client (the WCF channel faults and no longer functions).
What I really need is a way to make the communication channel more fault tolerant.
I can approach this several ways, but by drawing on the toolkits I know best, I have
decided to use the Smart Client Software Factory as a base implementation framework
for the product. This is probably overkill for what I'm doing, but I really like the
automatic offline/online detection and the modular nature of the services layers.
</p>
        <p>
Since we already have something resembling a UI, the next thing is to take a serious
look at the business / data access layers. They're pretty co-mingled right now, and
experts in the field tell me that isn't a good idea. For the Data Access layer, I
see two different approaches: 1) Direct webservice access (like we've done in our
previous examples) using the Disconnected Service Agent block provided by the SCSF,
or 2) employing the services of 1) for real-time information (now playing) and handling
the large volume of media library information via a local, cached data store, regularly
updated via ADO.NET synchronization services.
</p>
        <p>
Of course, 2) is my favorite, but we'll start with 1) and move to 2). The nice bit
about the SCSF in this case is that changing the data access layer at a later time
should have minimal impact on either the business layer or the UI. So long as the
data access layer continues to implement the same service interface, the actual implementation
shouldn't matter.
</p>
        <p>
So, here goes. We'll start by downloading and installing the most recent version of <a href="http://www.codeplex.com/smartclient">SCSF</a>, <a href="http://www.microsoft.com/downloads/details.aspx?familyid=DF79C099-4753-4A59-91E3-5020D9714E4E&amp;displaylang=en">Guidance
Automation Extensions (GAX)</a>, and <a href="http://www.microsoft.com/downloads/details.aspx?familyid=4C557C63-708F-4280-8F0C-637481C31718&amp;displaylang=en">Enterprise
Library</a> for VS2008.
</p>
        <p>
With that out of the way, we start with a brand new smart client project with WPF
UI components enabled. By default, if you want to enable WPF UI components, it creates
a WinForms application that allows WPF parts to be hosted. I'm not sure I like this
hybrid solution, and may look into using the techniques in the <a href="http://www.codeplex.com/scsfcontrib">SCSFContrib</a> CodePlex
project to get a truly WPF application at the end of the day.
</p>
        <p>
Here's the plan of attack:
</p>
        <ol>
          <li>
Implement the Data Access layer as an online/offline fault tolerant service. 
</li>
          <li>
Implement some form of business layer using a yet-to-be-determined approach. 
</li>
          <li>
Drop in the existing front-row clone as a UI layer for the time being. 
</li>
          <li>
Implement a client-side cache for the media library (seldom changing) data. 
</li>
          <li>
Replace the UI with a purely WPF implementation, possibly using the SCSFContrib libraries.</li>
        </ol>
        <p>
Sounds simple. Rather than walking through the entire solution, I'll post the areas
where I have problems and (possibly) some solutions to these problems.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=61f11d1f-bc88-4117-9ec9-bc3d46c9d964" />
      </body>
      <title>Windows Media Player Remote Control - 7</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,61f11d1f-bc88-4117-9ec9-bc3d46c9d964.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl7.aspx</link>
      <pubDate>Tue, 03 Jun 2008 16:50:56 GMT</pubDate>
      <description>&lt;p&gt;
After using version 1.5 in the real world, I've realized it's time to make the solution
more robust, with higher performance. The 1.5 implementation is so bad, in fact, that
I'm not going to offer the source code as promised -- it just isn't release (even
alpha) quality. As implemented, if the server goes down or there is a momentary network
outage, I have to restart the client (the WCF channel faults and no longer functions).
What I really need is a way to make the communication channel more fault tolerant.
I can approach this several ways, but by drawing on the toolkits I know best, I have
decided to use the Smart Client Software Factory as a base implementation framework
for the product. This is probably overkill for what I'm doing, but I really like the
automatic offline/online detection and the modular nature of the services layers.
&lt;/p&gt;
&lt;p&gt;
Since we already have something resembling a UI, the next thing is to take a serious
look at the business / data access layers. They're pretty co-mingled right now, and
experts in the field tell me that isn't a good idea. For the Data Access layer, I
see two different approaches: 1) Direct webservice access (like we've done in our
previous examples) using the Disconnected Service Agent block provided by the SCSF,
or 2) employing the services of 1) for real-time information (now playing) and handling
the large volume of media library information via a local, cached data store, regularly
updated via ADO.NET synchronization services.
&lt;/p&gt;
&lt;p&gt;
Of course, 2) is my favorite, but we'll start with 1) and move to 2). The nice bit
about the SCSF in this case is that changing the data access layer at a later time
should have minimal impact on either the business layer or the UI. So long as the
data access layer continues to implement the same service interface, the actual implementation
shouldn't matter.
&lt;/p&gt;
&lt;p&gt;
So, here goes. We'll start by downloading and installing the most recent version of &lt;a href="http://www.codeplex.com/smartclient"&gt;SCSF&lt;/a&gt;, &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=DF79C099-4753-4A59-91E3-5020D9714E4E&amp;amp;displaylang=en"&gt;Guidance
Automation Extensions (GAX)&lt;/a&gt;, and &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=4C557C63-708F-4280-8F0C-637481C31718&amp;amp;displaylang=en"&gt;Enterprise
Library&lt;/a&gt; for VS2008.
&lt;/p&gt;
&lt;p&gt;
With that out of the way, we start with a brand new smart client project with WPF
UI components enabled. By default, if you want to enable WPF UI components, it creates
a WinForms application that allows WPF parts to be hosted. I'm not sure I like this
hybrid solution, and may look into using the techniques in the &lt;a href="http://www.codeplex.com/scsfcontrib"&gt;SCSFContrib&lt;/a&gt; CodePlex
project to get a truly WPF application at the end of the day.
&lt;/p&gt;
&lt;p&gt;
Here's the plan of attack:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
Implement the Data Access layer as an online/offline fault tolerant service. 
&lt;li&gt;
Implement some form of business layer using a yet-to-be-determined approach. 
&lt;li&gt;
Drop in the existing front-row clone as a UI layer for the time being. 
&lt;li&gt;
Implement a client-side cache for the media library (seldom changing) data. 
&lt;li&gt;
Replace the UI with a purely WPF implementation, possibly using the SCSFContrib libraries.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Sounds simple. Rather than walking through the entire solution, I'll post the areas
where I have problems and (possibly) some solutions to these problems.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=61f11d1f-bc88-4117-9ec9-bc3d46c9d964" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,61f11d1f-bc88-4117-9ec9-bc3d46c9d964.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=b2026707-d132-41a9-830c-dc7c7c75ad4b</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,b2026707-d132-41a9-830c-dc7c7c75ad4b.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,b2026707-d132-41a9-830c-dc7c7c75ad4b.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=b2026707-d132-41a9-830c-dc7c7c75ad4b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
In segment <strike>3</strike><strike>4</strike><a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx">here</a> of
this series, I discovered a distinct problem with Visual Studio's treatment of WCF
Library projects. Specifically, any WCF Library project in Visual Studio is automatically
hosted in a test harness during a debug session -- even if you have explicitly told
visual studio not to start that particular project or deleted any reference to WcfSvcHost.exe
in any of the project files! 
</p>
        <p>
This caused problems when I was explicitly hosting my service in an outside application
(like my WinForm app). If I had the service, service host, and client application
in the same VS solution (and who wouldn't?), I couldn't use the same configuration
information in the WCF host library as the WinForms host. If I did, one of two would
fail to initialize, and it was always my hosting application that started up after
the WcfSvcHost.exe application that failed. But, changing port numbers between the
projects meant that I couldn't use the automatic "Update Service Reference" tool within
Visual Studio without manually changing port numbers before I updated. Convincing
VS that this wasn't a WCF Library (by removing the project type guid) meant that the
automatic update tool wasn't even an option. 
</p>
        <p>
The solution was a side effect of my attempt to re-architect my application for re-use.
The "Update Service Reference" tool uses the App.Config file within the project <em><u>where
the service reference lives</u></em>. The applications use the App.Config within the
project <em><u>where the applications live</u></em>. So, the simple solution is to
extract the service references into a different .dll from the client application like
this: 
<table cellspacing="0" cellpadding="2" width="562" border="0"><tbody><tr><td valign="top" width="90">
Project 
</td><td valign="top" width="137">
WCF Host Application 
</td><td valign="top" width="83">
WCF Library 
</td><td valign="top" width="123">
Service Access .dll 
</td><td valign="top" width="127">
Client Application 
</td></tr><tr><td valign="top" width="90">
App.Config 
</td><td valign="top" width="137">
Port 3132 
</td><td valign="top" width="83">
Port 3131 
</td><td valign="top" width="123">
Port 3131 
</td><td valign="top" width="127">
Port 3132</td></tr></tbody></table></p>
        <p>
If you do that, then you can change the port numbers in the host application and client
application projects without disturbing the port numbers in the WCF Library or the
Service Access library. So, the "Update Service Reference" tool continues to work.
The WCF service is still spun up twice on a debug session, but only once on the ports
listed in the host application's app.config.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=b2026707-d132-41a9-830c-dc7c7c75ad4b" />
      </body>
      <title>Windows Media Player Remote Control - 6e - Solving the WcfScvHost.exe Problem Without Losing Auto-Update</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,b2026707-d132-41a9-830c-dc7c7c75ad4b.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/26/WindowsMediaPlayerRemoteControl6eSolvingTheWcfScvHostexeProblemWithoutLosingAutoUpdate.aspx</link>
      <pubDate>Sat, 26 Jan 2008 23:46:31 GMT</pubDate>
      <description>&lt;p&gt;
In segment &lt;strike&gt;3&lt;/strike&gt; &lt;strike&gt;4&lt;/strike&gt; &lt;a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx"&gt;here&lt;/a&gt; of
this series, I discovered a distinct problem with Visual Studio's treatment of WCF
Library projects. Specifically, any WCF Library project in Visual Studio is automatically
hosted in a test harness during a debug session -- even if you have explicitly told
visual studio not to start that particular project or deleted any reference to WcfSvcHost.exe
in any of the project files! 
&lt;p&gt;
This caused problems when I was explicitly hosting my service in an outside application
(like my WinForm app). If I had the service, service host, and client application
in the same VS solution (and who wouldn't?), I couldn't use the same configuration
information in the WCF host library as the WinForms host. If I did, one of two would
fail to initialize, and it was always my hosting application that started up after
the WcfSvcHost.exe application that failed. But, changing port numbers between the
projects meant that I couldn't use the automatic "Update Service Reference" tool within
Visual Studio without manually changing port numbers before I updated. Convincing
VS that this wasn't a WCF Library (by removing the project type guid) meant that the
automatic update tool wasn't even an option. 
&lt;p&gt;
The solution was a side effect of my attempt to re-architect my application for re-use.
The "Update Service Reference" tool uses the App.Config file within the project &lt;em&gt;&lt;u&gt;where
the service reference lives&lt;/u&gt;&lt;/em&gt;. The applications use the App.Config within the
project &lt;em&gt;&lt;u&gt;where the applications live&lt;/u&gt;&lt;/em&gt;. So, the simple solution is to
extract the service references into a different .dll from the client application like
this: 
&lt;table cellspacing="0" cellpadding="2" width="562" border="0"&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td valign="top" width="90"&gt;
Project 
&lt;td valign="top" width="137"&gt;
WCF Host Application 
&lt;td valign="top" width="83"&gt;
WCF Library 
&lt;td valign="top" width="123"&gt;
Service Access .dll 
&lt;td valign="top" width="127"&gt;
Client Application 
&lt;tr&gt;
&lt;td valign="top" width="90"&gt;
App.Config 
&lt;td valign="top" width="137"&gt;
Port 3132 
&lt;td valign="top" width="83"&gt;
Port 3131 
&lt;td valign="top" width="123"&gt;
Port 3131 
&lt;td valign="top" width="127"&gt;
Port 3132&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;
If you do that, then you can change the port numbers in the host application and client
application projects without disturbing the port numbers in the WCF Library or the
Service Access library. So, the "Update Service Reference" tool continues to work.
The WCF service is still spun up twice on a debug session, but only once on the ports
listed in the host application's app.config.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=b2026707-d132-41a9-830c-dc7c7c75ad4b" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,b2026707-d132-41a9-830c-dc7c7c75ad4b.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=c18d9dce-257f-4a56-8abc-da79a94704a5</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,c18d9dce-257f-4a56-8abc-da79a94704a5.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,c18d9dce-257f-4a56-8abc-da79a94704a5.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=c18d9dce-257f-4a56-8abc-da79a94704a5</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This one may seem a little rudimentary, but it caused me to think a little about the
right pattern for handling background worker threads. That is, in .NET 2.0, I could
take advantage of the BackgroundWorker control. This control did a nice job of spawning
a thread to do some work and alerting the application (on the UI thread) when it was
complete. It also got Disposed when the containing control got disposed, alleviating
the need for any end of life thread synchronization. In WPF, however, this control
doesn't exist, but a class called BackgroundWorker does.
</p>
        <p>
My usual approach to something like this is to create a class level ManualResetEvent
and then initialize the BackgroundWorker in the constructor with something like this:
</p>
        <blockquote>
          <pre class="code">_backgroundWorker = <span style="color: blue">new </span><span style="color: #2b91af">BackgroundWorker</span>();
_threadStopEvent = <span style="color: blue">new </span><span style="color: #2b91af">ManualResetEvent</span>(<span style="color: blue">false</span>);
_backgroundWorker.DoWork += <span style="color: blue">new </span><span style="color: #2b91af">DoWorkEventHandler</span>(GetNowPlaying);
_backgroundWorker.WorkerSupportsCancellation = <span style="color: blue">true</span>;
_backgroundWorker.RunWorkerAsync();</pre>
        </blockquote>
        <p>
Then, have the periodic worker do a timed wait on the ManualResetEvent. When the wait
times out, perform the action, and when the wait is triggered, exit the loop (ending
the worker thread). This usually looks something like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">private void </span>GetNowPlaying()
{ <span style="color: blue">while </span>(!_threadStopEvent.WaitOne(500,<span style="color: blue">false</span>))
{ <span style="color: green">// Do some work</span> } } </pre>
        </blockquote>
        <p>
In the normal case, I tell the thread to stop when the owning object's dispose method
is called like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">protected void </span>Dispose(<span style="color: blue">bool </span>disposing)
{ <span style="color: blue">if </span>(disposing) { <span style="color: blue">if </span>(!_disposed)
{ _threadStopEvent.Set(); _disposed = <span style="color: blue">true</span>; } } }</pre>
        </blockquote>
        <p>
This didn't seem to work in our case. Another alternative was to call the BackgroundWorkder's
CancelAsync() method. That didn't work either. The reason? Our Factory has a static
NowPlaying object. So, when should we dispose our NowPlaying object? There are many
instances of the Factory class created. We don't want each instance to have its own
copy of the media library, so we share it across all instances. But, how do we know
when to dispose of it?
</p>
        <p>
It turns out, it doesn't really matter. The BackgroundWorker class does a pretty good
job of cleaning up after itself. So, we can just get rid of the Dispose altogether.
The BackgroundWorker takes care of terminating all of our background threads automatically.
Best Practice? I'm not sure. It seems like we're not doing a very nice job of disposing
of our resources, but it's pretty slick.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=c18d9dce-257f-4a56-8abc-da79a94704a5" />
      </body>
      <title>Windows Media Player Remote Control - 6d - Managing the Background NowPlaying Thread</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,c18d9dce-257f-4a56-8abc-da79a94704a5.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/25/WindowsMediaPlayerRemoteControl6dManagingTheBackgroundNowPlayingThread.aspx</link>
      <pubDate>Fri, 25 Jan 2008 23:46:01 GMT</pubDate>
      <description>&lt;p&gt;
This one may seem a little rudimentary, but it caused me to think a little about the
right pattern for handling background worker threads. That is, in .NET 2.0, I could
take advantage of the BackgroundWorker control. This control did a nice job of spawning
a thread to do some work and alerting the application (on the UI thread) when it was
complete. It also got Disposed when the containing control got disposed, alleviating
the need for any end of life thread synchronization. In WPF, however, this control
doesn't exist, but a class called BackgroundWorker does.
&lt;/p&gt;
&lt;p&gt;
My usual approach to something like this is to create a class level ManualResetEvent
and then initialize the BackgroundWorker in the constructor with something like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;_backgroundWorker = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;BackgroundWorker&lt;/span&gt;();
_threadStopEvent = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;ManualResetEvent&lt;/span&gt;(&lt;span style="color: blue"&gt;false&lt;/span&gt;);
_backgroundWorker.DoWork += &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DoWorkEventHandler&lt;/span&gt;(GetNowPlaying);
_backgroundWorker.WorkerSupportsCancellation = &lt;span style="color: blue"&gt;true&lt;/span&gt;;
_backgroundWorker.RunWorkerAsync();&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Then, have the periodic worker do a timed wait on the ManualResetEvent. When the wait
times out, perform the action, and when the wait is triggered, exit the loop (ending
the worker thread). This usually looks something like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;GetNowPlaying()
{ &lt;span style="color: blue"&gt;while &lt;/span&gt;(!_threadStopEvent.WaitOne(500,&lt;span style="color: blue"&gt;false&lt;/span&gt;))
{ &lt;span style="color: green"&gt;// Do some work&lt;/span&gt; } } &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
In the normal case, I tell the thread to stop when the owning object's dispose method
is called like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;protected void &lt;/span&gt;Dispose(&lt;span style="color: blue"&gt;bool &lt;/span&gt;disposing)
{ &lt;span style="color: blue"&gt;if &lt;/span&gt;(disposing) { &lt;span style="color: blue"&gt;if &lt;/span&gt;(!_disposed)
{ _threadStopEvent.Set(); _disposed = &lt;span style="color: blue"&gt;true&lt;/span&gt;; } } }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
This didn't seem to work in our case. Another alternative was to call the BackgroundWorkder's
CancelAsync() method. That didn't work either. The reason? Our Factory has a static
NowPlaying object. So, when should we dispose our NowPlaying object? There are many
instances of the Factory class created. We don't want each instance to have its own
copy of the media library, so we share it across all instances. But, how do we know
when to dispose of it?
&lt;/p&gt;
&lt;p&gt;
It turns out, it doesn't really matter. The BackgroundWorker class does a pretty good
job of cleaning up after itself. So, we can just get rid of the Dispose altogether.
The BackgroundWorker takes care of terminating all of our background threads automatically.
Best Practice? I'm not sure. It seems like we're not doing a very nice job of disposing
of our resources, but it's pretty slick.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=c18d9dce-257f-4a56-8abc-da79a94704a5" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,c18d9dce-257f-4a56-8abc-da79a94704a5.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=802fea74-be0b-417e-96d6-15023dc7c7b7</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,802fea74-be0b-417e-96d6-15023dc7c7b7.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,802fea74-be0b-417e-96d6-15023dc7c7b7.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=802fea74-be0b-417e-96d6-15023dc7c7b7</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
While producing my new, pretty WMP remote control, I wanted to have clever navigation
animations similar to those found in FrontRow. The example I used (<a href="http://www.mperfect.net/backRow/">/backRow</a>)
accomplished this in a pretty ugly way.  All of the controls were set up off-screen
and flown on-screen according to some animation trigger. This worked, but it made
it impossible to edit the contents of the pages with Expression Blend or the Visual
Studio editor. So, I decided to use page navigation instead.
</p>
        <p>
The trick was to figure out how to change the look and feel of the page navigation.
By default, windows just appear over the old windows with no magical transitional
WPF-ness. In comes the <a href="http://www.codeplex.com/AnimationBehaviors">AnimationBehaviors</a> Project
on CodePlex. This clever little project allows me to control how a window is loaded
and unloaded. So, in our case, we can define a page, the contents of which are an
AnimationBehaviorHost, and set the AnimationBehaviorHost.LoadedBehavior to LoadedBehavior.SlideInFromRight. 
</p>
        <p>
That worked great, except that everything slide in from the right even if we were
navigating backwards! It just didn't look right. What would be great is if the LoadedBehavior
dynamically changed based on the direction of navigation. Sounds like a great used
of Binding.
</p>
        <p>
The first thing to do was to create a place to store the current animation behavior:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">public class </span>
            <span style="color: #2b91af">NavigationAnimation </span>: <span style="color: #2b91af">INotifyPropertyChanged </span>{ <span style="color: green">//
Singleton class </span><span style="color: blue">private </span>NavigationAnimation()
{ } <span style="color: blue">public enum </span><span style="color: #2b91af">NavigationDirection </span>{
Forward, Backward }; <span style="color: blue">private static </span><span style="color: #2b91af">NavigationAnimation </span>_instance
= <span style="color: blue">new </span><span style="color: #2b91af">NavigationAnimation</span>(); <span style="color: blue">public
static </span><span style="color: #2b91af">NavigationAnimation </span>Instance { <span style="color: blue">get </span>{ <span style="color: blue">return </span><span style="color: #2b91af">NavigationAnimation</span>._instance;
} <span style="color: blue">set </span>{ <span style="color: #2b91af">NavigationAnimation</span>._instance
= <span style="color: blue">value</span>; } } <span style="color: blue">public static
void </span>SetNavigationDirection(<span style="color: #2b91af">NavigationDirection </span>direction)
{ <span style="color: blue">if</span>(<span style="color: #2b91af">NavigationDirection</span>.Forward==direction)
{ Instance.AnimationBehavior = <span style="color: #2b91af">LoadedBehavior</span>.SlideInFromRight;
} <span style="color: blue">else </span>{ Instance.AnimationBehavior = <span style="color: #2b91af">LoadedBehavior</span>.SlideInFromLeft;
} } <span style="color: blue">private </span><span style="color: #2b91af">LoadedBehavior </span>_animationBehavior
= <span style="color: #2b91af">LoadedBehavior</span>.SlideInFromRight; <span style="color: blue">public </span><span style="color: #2b91af">LoadedBehavior </span>AnimationBehavior
{ <span style="color: blue">get </span>{ <span style="color: blue">return </span>_animationBehavior;
} <span style="color: blue">set </span>{ _animationBehavior = <span style="color: blue">value</span>;
OnPropertyChanged(<span style="color: #a31515">"AnimationBehavior"</span>); } } <span style="color: blue">private
void </span>OnPropertyChanged(<span style="color: blue">string </span>propertyName)
{ <span style="color: blue">if </span>(<span style="color: blue">null </span>!= PropertyChanged)
{ <span style="color: #2b91af">PropertyChangedEventArgs </span>e = <span style="color: blue">new </span><span style="color: #2b91af">PropertyChangedEventArgs</span>(propertyName);
PropertyChanged(<span style="color: blue">this</span>,e); } } <span style="color: blue">public
event </span><span style="color: #2b91af">PropertyChangedEventHandler </span>PropertyChanged;
}</pre>
        </blockquote>
        <p>
Next, we need to change the animation behavior based on our navigation state so we
add an event handler to the NavigationFrame's Navigating event that looks something
like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">private void </span>OnNavigating(<span style="color: blue">object </span>sender, <span style="color: #2b91af">NavigatingCancelEventArgs </span>e)
{ <span style="color: green"></span><span style="color: blue">if </span>(e.NavigationMode
== <span style="color: #2b91af">NavigationMode</span>.Back) { <span style="color: #2b91af">NavigationAnimation</span>.SetNavigationDirection(<span style="color: #2b91af">NavigationAnimation</span>.<span style="color: #2b91af">NavigationDirection</span>.Backward);
} <span style="color: blue">else </span>{ <span style="color: #2b91af">NavigationAnimation</span>.SetNavigationDirection(<span style="color: #2b91af">NavigationAnimation</span>.<span style="color: #2b91af">NavigationDirection</span>.Forward);
} }</pre>
        </blockquote>
        <p>
Finally, we bind our AnimationBehaviorHost.LoadedBehavior to our current animation
behavior.
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">private void </span>OnNavigating(<span style="color: blue">object </span>sender, <span style="color: #2b91af">NavigatingCancelEventArgs </span>e)
{ <span style="color: green"></span><span style="color: blue">if </span>(e.NavigationMode
== <span style="color: #2b91af">NavigationMode</span>.Back) { <span style="color: #2b91af">NavigationAnimation</span>.SetNavigationDirection(<span style="color: #2b91af">NavigationAnimation</span>.<span style="color: #2b91af">NavigationDirection</span>.Backward);
} <span style="color: blue">else </span>{ <span style="color: #2b91af">NavigationAnimation</span>.SetNavigationDirection(<span style="color: #2b91af">NavigationAnimation</span>.<span style="color: #2b91af">NavigationDirection</span>.Forward);
} }</pre>
        </blockquote>
        <p>
That's it! Navigating forward slides the windows in from the right, while navigating
backward slides the windows in from the left. I may finally be getting the hang of
this stuff!
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=802fea74-be0b-417e-96d6-15023dc7c7b7" />
      </body>
      <title>Windows Media Player Remote Control - 6c - The AnimationBehaviors Project</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,802fea74-be0b-417e-96d6-15023dc7c7b7.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/24/WindowsMediaPlayerRemoteControl6cTheAnimationBehaviorsProject.aspx</link>
      <pubDate>Thu, 24 Jan 2008 23:45:17 GMT</pubDate>
      <description>&lt;p&gt;
While producing my new, pretty WMP remote control, I wanted to have clever navigation
animations similar to those found in FrontRow. The example I used (&lt;a href="http://www.mperfect.net/backRow/"&gt;/backRow&lt;/a&gt;)
accomplished this in a pretty ugly way.&amp;nbsp; All of the controls were set up off-screen
and flown on-screen according to some animation trigger. This worked, but it made
it impossible to edit the contents of the pages with Expression Blend or the Visual
Studio editor. So, I decided to use page navigation instead.
&lt;/p&gt;
&lt;p&gt;
The trick was to figure out how to change the look and feel of the page navigation.
By default, windows just appear over the old windows with no magical transitional
WPF-ness. In comes the &lt;a href="http://www.codeplex.com/AnimationBehaviors"&gt;AnimationBehaviors&lt;/a&gt; Project
on CodePlex. This clever little project allows me to control how a window is loaded
and unloaded. So, in our case, we can define a page, the contents of which are an
AnimationBehaviorHost, and set the AnimationBehaviorHost.LoadedBehavior to LoadedBehavior.SlideInFromRight. 
&lt;/p&gt;
&lt;p&gt;
That worked great, except that everything slide in from the right even if we were
navigating backwards! It just didn't look right. What would be great is if the LoadedBehavior
dynamically changed based on the direction of navigation. Sounds like a great used
of Binding.
&lt;/p&gt;
&lt;p&gt;
The first thing to do was to create a place to store the current animation behavior:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigationAnimation &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;INotifyPropertyChanged &lt;/span&gt;{ &lt;span style="color: green"&gt;//
Singleton class &lt;/span&gt;&lt;span style="color: blue"&gt;private &lt;/span&gt;NavigationAnimation()
{ } &lt;span style="color: blue"&gt;public enum &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigationDirection &lt;/span&gt;{
Forward, Backward }; &lt;span style="color: blue"&gt;private static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigationAnimation &lt;/span&gt;_instance
= &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;(); &lt;span style="color: blue"&gt;public
static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigationAnimation &lt;/span&gt;Instance { &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;&lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;._instance;
} &lt;span style="color: blue"&gt;set &lt;/span&gt;{ &lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;._instance
= &lt;span style="color: blue"&gt;value&lt;/span&gt;; } } &lt;span style="color: blue"&gt;public static
void &lt;/span&gt;SetNavigationDirection(&lt;span style="color: #2b91af"&gt;NavigationDirection &lt;/span&gt;direction)
{ &lt;span style="color: blue"&gt;if&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;NavigationDirection&lt;/span&gt;.Forward==direction)
{ Instance.AnimationBehavior = &lt;span style="color: #2b91af"&gt;LoadedBehavior&lt;/span&gt;.SlideInFromRight;
} &lt;span style="color: blue"&gt;else &lt;/span&gt;{ Instance.AnimationBehavior = &lt;span style="color: #2b91af"&gt;LoadedBehavior&lt;/span&gt;.SlideInFromLeft;
} } &lt;span style="color: blue"&gt;private &lt;/span&gt;&lt;span style="color: #2b91af"&gt;LoadedBehavior &lt;/span&gt;_animationBehavior
= &lt;span style="color: #2b91af"&gt;LoadedBehavior&lt;/span&gt;.SlideInFromRight; &lt;span style="color: blue"&gt;public &lt;/span&gt;&lt;span style="color: #2b91af"&gt;LoadedBehavior &lt;/span&gt;AnimationBehavior
{ &lt;span style="color: blue"&gt;get &lt;/span&gt;{ &lt;span style="color: blue"&gt;return &lt;/span&gt;_animationBehavior;
} &lt;span style="color: blue"&gt;set &lt;/span&gt;{ _animationBehavior = &lt;span style="color: blue"&gt;value&lt;/span&gt;;
OnPropertyChanged(&lt;span style="color: #a31515"&gt;"AnimationBehavior"&lt;/span&gt;); } } &lt;span style="color: blue"&gt;private
void &lt;/span&gt;OnPropertyChanged(&lt;span style="color: blue"&gt;string &lt;/span&gt;propertyName)
{ &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;null &lt;/span&gt;!= PropertyChanged)
{ &lt;span style="color: #2b91af"&gt;PropertyChangedEventArgs &lt;/span&gt;e = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventArgs&lt;/span&gt;(propertyName);
PropertyChanged(&lt;span style="color: blue"&gt;this&lt;/span&gt;,e); } } &lt;span style="color: blue"&gt;public
event &lt;/span&gt;&lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler &lt;/span&gt;PropertyChanged;
}&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Next, we need to change the animation behavior based on our navigation state so we
add an event handler to the NavigationFrame's Navigating event that looks something
like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;OnNavigating(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;NavigatingCancelEventArgs &lt;/span&gt;e)
{ &lt;span style="color: green"&gt; &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(e.NavigationMode
== &lt;span style="color: #2b91af"&gt;NavigationMode&lt;/span&gt;.Back) { &lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.SetNavigationDirection(&lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.&lt;span style="color: #2b91af"&gt;NavigationDirection&lt;/span&gt;.Backward);
} &lt;span style="color: blue"&gt;else &lt;/span&gt;{ &lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.SetNavigationDirection(&lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.&lt;span style="color: #2b91af"&gt;NavigationDirection&lt;/span&gt;.Forward);
} }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Finally, we bind our AnimationBehaviorHost.LoadedBehavior to our current animation
behavior.
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;OnNavigating(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;NavigatingCancelEventArgs &lt;/span&gt;e)
{ &lt;span style="color: green"&gt; &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;(e.NavigationMode
== &lt;span style="color: #2b91af"&gt;NavigationMode&lt;/span&gt;.Back) { &lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.SetNavigationDirection(&lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.&lt;span style="color: #2b91af"&gt;NavigationDirection&lt;/span&gt;.Backward);
} &lt;span style="color: blue"&gt;else &lt;/span&gt;{ &lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.SetNavigationDirection(&lt;span style="color: #2b91af"&gt;NavigationAnimation&lt;/span&gt;.&lt;span style="color: #2b91af"&gt;NavigationDirection&lt;/span&gt;.Forward);
} }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
That's it! Navigating forward slides the windows in from the right, while navigating
backward slides the windows in from the left. I may finally be getting the hang of
this stuff!
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=802fea74-be0b-417e-96d6-15023dc7c7b7" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,802fea74-be0b-417e-96d6-15023dc7c7b7.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=622d656f-1142-4dcd-8d71-eb7d0270af90</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,622d656f-1142-4dcd-8d71-eb7d0270af90.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,622d656f-1142-4dcd-8d71-eb7d0270af90.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=622d656f-1142-4dcd-8d71-eb7d0270af90</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Once I figured out how to update data-bound collections from a background thread,
things progressed rather smoothly. But, when it was time to implement the "Now Playing"
pane, I wasn't working with a collection of items anymore. No worry, just implement
INotifyPropertyChanged the same way we did INotifyCollectionChanged (with the SynchronizationContext
"hack") and all was well. Or so I thought. 
</p>
        <p>
The NowPlayingService exposes the album art for the media item currently being played
as a System.Bitmap. I chose that because it appeared to navigate nicely across WCF
services. While that is true, they don't bind very nicely to any property of a WPF
Image control. As far as I can tell, there are a few options to solve this problem:
implement a System.Bitmap to System.Windows.Media.Imaging.BitmapSource TypeConverter.
dig through the documented converter classes to see if there might actually be one
implemented for you (still possible, but I couldn't find one), or just do the conversion
in the business object and expose the image property as the appropriate System.Windows.Media.Imaging.BitmapSource. 
</p>
        <p>
I decided the last option was easiest. So, I exposed a BitmapSource property called
AlbumArt and assigned it from the System.Bitmap with something like this: 
</p>
        <blockquote>
          <pre>
            <span style="color: blue">private </span>System.Windows.Media.Imaging.<span style="color: #2b91af">BitmapSource </span>FromBitmap(System.Drawing.<span style="color: #2b91af">Bitmap </span>bitmap)
{ <span style="color: blue">return </span>System.Windows.Interop.<span style="color: #2b91af">Imaging</span>.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(), <span style="color: #2b91af">IntPtr</span>.Zero, System.Windows.<span style="color: #2b91af">Int32Rect</span>.Empty,
System.Windows.Media.Imaging.<span style="color: #2b91af">BitmapSizeOptions</span>.FromEmptyOptions());
}</pre>
        </blockquote>
        <p>
That worked great, synchronously. When I started updating it in the background thread
(on a periodic timer), I got a "System.Windows.Xaml.XamlParseException: System.Windows.Data.BindingExpression'
value cannot be assigned to property 'Source' of object 'System.Windows.Controls.Image'.
The calling thread cannot access this object because a different thread owns it. 
Error at object 'System.Windows.Data.Binding' in markup file ...". What? I'm marshalling
across threads correctly. Everything else works. What could be going on here, and
why? 
</p>
        <blockquote>
          <p>
            <em>Non sequitur - In a previous life, I was a C++, Win32, COM, and ATL developer.
I was also an ESRI ArcObjects (a pretty large COM API for automating ESRI ArcMap)
developer. As soon as I started working with .NET, I grabbed a copy of Adam Nathan's <a href="http://www.amazon.com/NET-COM-Complete-Interoperability-Guide/dp/067232170X">excellent
book on COM Interop</a>. With that, I sought to understand as much as I could regarding
the interoperability between COM and .NET for I wanted to take advantage of the .NET
UI from within my COM business model.</em>
          </p>
        </blockquote>
        <p>
The inclusion of things like .Interop. in the namespace and GetHbitmap() in the arguments
immediately led me to the potential that the returned BitmapSource reference was a
simple wrapper around the HBITMAP in the System.Bitmap reference. By the fact that
the UI is complaining about accessing an object in a different thread, I surmise that
the HBITMAP of the System.Bitmap is in Thread Local Storage rather than global memory.
So, I altered the conversion process to something like this: 
</p>
        <blockquote>
          <pre>
            <span style="color: blue">private </span>System.Windows.Media.Imaging.<span style="color: #2b91af">BitmapSource </span>BitmapSourceFromImage(System.Drawing.<span style="color: #2b91af">Image </span>img)
{ System.IO.<span style="color: #2b91af">MemoryStream </span>memStream = <span style="color: blue">new </span>System.IO.<span style="color: #2b91af">MemoryStream</span>(); <span style="color: green"></span>img.Save(memStream,
System.Drawing.Imaging.<span style="color: #2b91af">ImageFormat</span>.Png); <span style="color: green"></span>System.Windows.Media.Imaging.<span style="color: #2b91af">PngBitmapDecoder </span>decoder
= <span style="color: blue">new </span>System.Windows.Media.Imaging.<span style="color: #2b91af">PngBitmapDecoder</span>(
memStream, System.Windows.Media.Imaging.<span style="color: #2b91af">BitmapCreateOptions</span>.PreservePixelFormat,
System.Windows.Media.Imaging.<span style="color: #2b91af">BitmapCacheOption</span>.Default); <span style="color: green"></span><span style="color: blue">return </span>decoder.Frames[0];
}</pre>
        </blockquote>
        <p>
With the business object exposing a copy of the bitmap, all is well. However, I am
finding myself, once again, questioning whether it should be the job of the business
object to know whether it's being used from a different thread. I guess it's a question
of determining who is responsible for ensuring thread safety. Ultimately, it was the
business object's fault for exposing a wrapper around thread local storage rather
than heap storage.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=622d656f-1142-4dcd-8d71-eb7d0270af90" />
      </body>
      <title>Windows Media Player Remote Control - 6b - System.Bitmap and the Background Thread</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,622d656f-1142-4dcd-8d71-eb7d0270af90.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/23/WindowsMediaPlayerRemoteControl6bSystemBitmapAndTheBackgroundThread.aspx</link>
      <pubDate>Wed, 23 Jan 2008 23:44:40 GMT</pubDate>
      <description>&lt;p&gt;
Once I figured out how to update data-bound collections from a background thread,
things progressed rather smoothly. But, when it was time to implement the "Now Playing"
pane, I wasn't working with a collection of items anymore. No worry, just implement
INotifyPropertyChanged the same way we did INotifyCollectionChanged (with the SynchronizationContext
"hack") and all was well. Or so I thought. 
&lt;p&gt;
The NowPlayingService exposes the album art for the media item currently being played
as a System.Bitmap. I chose that because it appeared to navigate nicely across WCF
services. While that is true, they don't bind very nicely to any property of a WPF
Image control. As far as I can tell, there are a few options to solve this problem:
implement a System.Bitmap to System.Windows.Media.Imaging.BitmapSource TypeConverter.
dig through the documented converter classes to see if there might actually be one
implemented for you (still possible, but I couldn't find one), or just do the conversion
in the business object and expose the image property as the appropriate System.Windows.Media.Imaging.BitmapSource. 
&lt;p&gt;
I decided the last option was easiest. So, I exposed a BitmapSource property called
AlbumArt and assigned it from the System.Bitmap with something like this: &lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: blue"&gt;private &lt;/span&gt;System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;BitmapSource &lt;/span&gt;FromBitmap(System.Drawing.&lt;span style="color: #2b91af"&gt;Bitmap &lt;/span&gt;bitmap)
{ &lt;span style="color: blue"&gt;return &lt;/span&gt;System.Windows.Interop.&lt;span style="color: #2b91af"&gt;Imaging&lt;/span&gt;.CreateBitmapSourceFromHBitmap(
bitmap.GetHbitmap(), &lt;span style="color: #2b91af"&gt;IntPtr&lt;/span&gt;.Zero, System.Windows.&lt;span style="color: #2b91af"&gt;Int32Rect&lt;/span&gt;.Empty,
System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;BitmapSizeOptions&lt;/span&gt;.FromEmptyOptions());
}&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
That worked great, synchronously. When I started updating it in the background thread
(on a periodic timer), I got a "System.Windows.Xaml.XamlParseException: System.Windows.Data.BindingExpression'
value cannot be assigned to property 'Source' of object 'System.Windows.Controls.Image'.
The calling thread cannot access this object because a different thread owns it.&amp;nbsp;
Error at object 'System.Windows.Data.Binding' in markup file ...". What? I'm marshalling
across threads correctly. Everything else works. What could be going on here, and
why? &lt;blockquote&gt; 
&lt;p&gt;
&lt;em&gt;Non sequitur - In a previous life, I was a C++, Win32, COM, and ATL developer.
I was also an ESRI ArcObjects (a pretty large COM API for automating ESRI ArcMap)
developer. As soon as I started working with .NET, I grabbed a copy of Adam Nathan's &lt;a href="http://www.amazon.com/NET-COM-Complete-Interoperability-Guide/dp/067232170X"&gt;excellent
book on COM Interop&lt;/a&gt;. With that, I sought to understand as much as I could regarding
the interoperability between COM and .NET for I wanted to take advantage of the .NET
UI from within my COM business model.&lt;/em&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
The inclusion of things like .Interop. in the namespace and GetHbitmap() in the arguments
immediately led me to the potential that the returned BitmapSource reference was a
simple wrapper around the HBITMAP in the System.Bitmap reference. By the fact that
the UI is complaining about accessing an object in a different thread, I surmise that
the HBITMAP of the System.Bitmap is in Thread Local Storage rather than global memory.
So, I altered the conversion process to something like this: &lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: blue"&gt;private &lt;/span&gt;System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;BitmapSource &lt;/span&gt;BitmapSourceFromImage(System.Drawing.&lt;span style="color: #2b91af"&gt;Image &lt;/span&gt;img)
{ System.IO.&lt;span style="color: #2b91af"&gt;MemoryStream &lt;/span&gt;memStream = &lt;span style="color: blue"&gt;new &lt;/span&gt;System.IO.&lt;span style="color: #2b91af"&gt;MemoryStream&lt;/span&gt;(); &lt;span style="color: green"&gt; &lt;/span&gt;img.Save(memStream,
System.Drawing.Imaging.&lt;span style="color: #2b91af"&gt;ImageFormat&lt;/span&gt;.Png); &lt;span style="color: green"&gt; &lt;/span&gt;System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;PngBitmapDecoder &lt;/span&gt;decoder
= &lt;span style="color: blue"&gt;new &lt;/span&gt;System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;PngBitmapDecoder&lt;/span&gt;(
memStream, System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;BitmapCreateOptions&lt;/span&gt;.PreservePixelFormat,
System.Windows.Media.Imaging.&lt;span style="color: #2b91af"&gt;BitmapCacheOption&lt;/span&gt;.Default); &lt;span style="color: green"&gt; &lt;/span&gt;&lt;span style="color: blue"&gt;return &lt;/span&gt;decoder.Frames[0];
}&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
With the business object exposing a copy of the bitmap, all is well. However, I am
finding myself, once again, questioning whether it should be the job of the business
object to know whether it's being used from a different thread. I guess it's a question
of determining who is responsible for ensuring thread safety. Ultimately, it was the
business object's fault for exposing a wrapper around thread local storage rather
than heap storage.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=622d656f-1142-4dcd-8d71-eb7d0270af90" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,622d656f-1142-4dcd-8d71-eb7d0270af90.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=6f370665-4125-4322-8c6c-e4651e4f6048</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,6f370665-4125-4322-8c6c-e4651e4f6048.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,6f370665-4125-4322-8c6c-e4651e4f6048.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=6f370665-4125-4322-8c6c-e4651e4f6048</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the eighth in a series, but the numbering is getting confusing, so I'm going
to stop counting. 
</p>
        <p>
The first step I took in creating my pretty WMP remote control UI was to <strike>steal</strike> design
the pretty UI. Once I had the UI, it was a matter of binding the media library entries
to the appropriate WPF elements (a listbox). I used some pretty standard dataset creation
/ binding logic I found somewhere that makes use of the ObjectDataProvider. To implement
this, I created a MediaLibrary and Factory class that looked something like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">public class </span>
            <span style="color: #2b91af">MediaLibrary </span>: <span style="color: #2b91af">ObservableCollection</span>&lt;<span style="color: #2b91af">Song</span>&gt;
{ <span style="color: blue">public </span>MediaLibrary() { GetSongs(); } <span style="color: blue">private
void </span>GetSongs() { <span style="color: #2b91af">IMediaLibraryService </span>mediaLibrary
= <span style="color: blue">new </span><span style="color: #2b91af">MediaLibraryServiceClient</span>(); <span style="color: blue">int </span>librarySize
= mediaLibrary.GetSongCount(); <span style="color: blue">int </span>i = 0; <span style="color: blue">while </span>(i
&lt; (librarySize + _pageSize)) { <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
currentIds = mediaLibrary.GetSongs(i, _pageSize); <span style="color: blue">foreach </span>(<span style="color: #2b91af">Guid </span>id <span style="color: blue">in </span>currentIds)
{ <span style="color: #2b91af">Song </span>currentItem = mediaLibrary.GetMediaInfo(id); <span style="color: blue">if </span>(<span style="color: blue">null </span>!=
currentItem) { <span style="color: blue">this</span>.Add(currentItem); } } i += _pageSize;
} } }</pre>
          <pre class="code">
            <span style="color: blue">public class </span>
            <span style="color: #2b91af">Factory </span>{ <span style="color: gray">///
&lt;summary&gt; /// /// &lt;/summary&gt; </span><span style="color: blue">static </span>Factory()
{ Songs = <span style="color: blue">new </span><span style="color: #2b91af">MediaLibrary</span>();
} <span style="color: gray"></span><span style="color: blue">public static </span><span style="color: #2b91af">MediaLibrary </span>Songs
{ <span style="color: blue">get</span>; <span style="color: blue">private set</span>;
} }</pre>
        </blockquote>
        <p>
And I bound the contents to the UI using syntax like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">&lt;</span>
            <span style="color: #a31515">Grid</span>
            <span style="color: blue">&gt;
&lt;</span>
            <span style="color: #a31515">Grid.Resources</span>
            <span style="color: blue">&gt;
&lt;</span>
            <span style="color: #a31515">ObjectDataProvider </span>
            <span style="color: red">x</span>
            <span style="color: blue">:</span>
            <span style="color: red">Key</span>
            <span style="color: blue">="FactoryDS" </span>
            <span style="color: red">ObjectType</span>
            <span style="color: blue">="{</span>
            <span style="color: #a31515">x</span>
            <span style="color: blue">:</span>
            <span style="color: #a31515">Type </span>
            <span style="color: red">local</span>
            <span style="color: blue">:</span>
            <span style="color: red">Factory</span>
            <span style="color: blue">}"/&gt;
&lt;</span>
            <span style="color: #a31515">DataTemplate </span>
            <span style="color: red">x</span>
            <span style="color: blue">:</span>
            <span style="color: red">Key</span>
            <span style="color: blue">="SongTemplate"&gt;
&lt;</span>
            <span style="color: #a31515">StackPanel</span>
            <span style="color: blue">&gt;
&lt;</span>
            <span style="color: #a31515">TextBlock </span>
            <span style="color: red">Text</span>
            <span style="color: blue">="{</span>
            <span style="color: #a31515">Binding </span>
            <span style="color: red">Title</span>
            <span style="color: blue">}"/&gt;
&lt;/</span>
            <span style="color: #a31515">StackPanel</span>
            <span style="color: blue">&gt;
&lt;/</span>
            <span style="color: #a31515">DataTemplate</span>
            <span style="color: blue">&gt;
&lt;/</span>
            <span style="color: #a31515">Grid.Resources</span>
            <span style="color: blue">&gt;
&lt;</span>
            <span style="color: #a31515">ListBox </span>
            <span style="color: red">x</span>
            <span style="color: blue">:</span>
            <span style="color: red">Name</span>
            <span style="color: blue">="songListBox" </span>
            <span style="color: red">ItemsSource</span>
            <span style="color: blue">="{</span>
            <span style="color: #a31515">Binding </span>
            <span style="color: red">Songs</span>
            <span style="color: blue">, </span>
            <span style="color: red">Mode</span>
            <span style="color: blue">=Default, </span>
            <span style="color: red">Source</span>
            <span style="color: blue">={</span>
            <span style="color: #a31515">StaticResource </span>
            <span style="color: red">FactoryDS</span>
            <span style="color: blue">}}" </span>
            <span style="color: red">RenderTransformOrigin</span>
            <span style="color: blue">="0.5,0.5" </span>
            <span style="color: red">DisplayMemberPath</span>
            <span style="color: blue">="Title"
/&gt; &lt;/</span>
            <span style="color: #a31515">Grid</span>
            <span style="color: blue">&gt;</span>
          </pre>
        </blockquote>
        <p>
That worked great -- synchronously. But, as we already found out, a synchronous call
to the media library webservice isn't the best option (we'd rather page through the
results asynchronously, updating the UI while we go). So, I add a background thread,
changing the constructor to something like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">public </span>MediaLibrary()
{ System.Threading.<span style="color: #2b91af">Thread </span>thread = <span style="color: blue">new </span>System.Threading.<span style="color: #2b91af">Thread</span>(<span style="color: blue">new </span>System.Threading.<span style="color: #2b91af">ThreadStart</span>(GetSongs));
thread.Priority = <span style="color: #2b91af">ThreadPriority</span>.BelowNormal;
thread.Start(); } </pre>
        </blockquote>
        <p>
Run this, and you get a nasty cross-thread exception: "System.NotSupportedException:
This type of CollectionView does not support changes to its SourceCollection from
a thread different from the Dispatcher thread." Huh? What does my business layer need
to know about threading? I'm just updating a collection. But, not to be intimidated
easily, I try other options. How about implementing INotifyCollectionChanged rather
than inheriting from ObservableCollection? Same problem. So, Google reveals a nice
discussion by <a href="http://www.claassen.net/geek/blog/labels/INotifyPropertyChanged.html">ILoggable</a>.
He's as frustrated as I am. Really, should my data access layer know whether it's
running on the UI thread? I don't think so. Shouldn't the Binding mechanism in WPF
assume that I will be updating my business objects in background threads? After all,
what's the cost of a 4 core processor nowadays?
</p>
        <p>
I found a bunch of solutions to this problem that relied on explicitly making calls
to Application.Current.Dispatcher.BeginInvoke. That seems sleazy to me. One, slightly
less sleazy solution I found was to pass in a SynchronizationContext to the MediaLibrary
class. This still sounds like the business objects need to know too much about the
runtime, but at least SynchronizationContext is in the System.Windows.Threading namespace,
so it doesn't completely destroy my hopes of separating UI, business, and data.
</p>
        <p>
The solution I finally came up with (borrowed heavily from <a href="http://andyclymer.blogspot.com/2006/10/synchronizationcontext-assists.html">here</a>)
was a MediaLibrary with these changes:
</p>
        <blockquote>
          <p>
   <span style="color: blue">public class</span><span style="color: #2b91af">MediaLibrary </span>: <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Song</span>&gt;, <span style="color: #2b91af">INotifyCollectionChanged<br />
   </span>{<br />
        <span style="color: blue">private const
int </span>_pageSize = 5;<br />
        <span style="color: blue">private</span><span style="color: #2b91af">IMediaLibraryService </span>_mediaLibrary
= <span style="color: blue">new</span><span style="color: #2b91af">MediaLibraryServiceClient</span>();<br />
        <span style="color: blue">private</span><span style="color: #2b91af">SynchronizationContext </span>_synchronizationContext;<br /><br />
        <span style="color: gray">/// &lt;summary&gt;<br />
        /// 
<br />
        /// &lt;/summary&gt;<br />
        </span><span style="color: blue">public</span>MediaLibrary(<span style="color: #2b91af">SynchronizationContext </span>sync)<br />
        {<br />
            _synchronizationContext
= sync;<br />
            System.Threading.<span style="color: #2b91af">Thread</span>thread
= 
<br />
                <span style="color: blue">new</span>System.Threading.<span style="color: #2b91af">Thread</span>(<span style="color: blue">new</span>System.Threading.<span style="color: #2b91af">ThreadStart</span>(GetSongs));<br />
            thread.Priority
= <span style="color: #2b91af">ThreadPriority</span>.BelowNormal;<br />
            thread.Start();<br />
        }<br />
        <span style="color: blue">private void</span>GetSongs()<br />
        {<br />
            <span style="color: #2b91af">IMediaLibraryService </span>mediaLibrary
= <span style="color: blue">new</span><span style="color: #2b91af">MediaLibraryServiceClient</span>();<br />
            <span style="color: blue">int </span>librarySize
= mediaLibrary.GetSongCount();<br />
            <span style="color: blue">int </span>i
= 0;<br />
            <span style="color: blue">while</span>(i
&lt; (librarySize + _pageSize))<br />
            {<br />
                <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
currentIds = mediaLibrary.GetSongs(i, _pageSize);<br />
                <span style="color: blue">foreach </span>(<span style="color: #2b91af">Guid </span>id <span style="color: blue">in</span>currentIds)<br />
               
{<br />
                    <span style="color: #2b91af">Song</span>currentItem
= mediaLibrary.GetMediaInfo(id);<br />
                    <span style="color: blue">if</span>(<span style="color: blue">null</span>!=
currentItem)<br />
                   
{<br />
                        <span style="color: blue">this</span>.Add(currentItem);<br />
                       
SafeCollectionChangedNotification(currentItem);<br />
                   
}<br />
               
}<br />
               
i += _pageSize;<br />
            }<br />
        }<br /><br />
        <span style="color: blue">private void</span>SafeCollectionChangedNotification(<span style="color: #2b91af">Song</span>currentItem)<br />
        {<br />
            <span style="color: blue">if</span>(_synchronizationContext
!= <span style="color: blue">null</span>)<br />
            {<br />
               
_synchronizationContext.Post(<span style="color: blue">delegate<br />
               </span>{<br />
                   
OnCollectionChanged(currentItem);<br />
               
}, <span style="color: blue">null</span>);<br />
            }<br />
            <span style="color: blue">else<br />
           </span>{<br />
               
OnCollectionChanged(currentItem);<br />
            }<br />
        }<br /><br />
        <span style="color: blue">private void</span>OnCollectionChanged(<span style="color: #2b91af">Song</span>currentItem)<br />
        {<br />
            <span style="color: blue">if</span>(<span style="color: blue">null</span>!=
CollectionChanged)<br />
            {<br />
               
CollectionChanged(<span style="color: blue">this</span>, <span style="color: blue">new</span><span style="color: #2b91af">NotifyCollectionChangedEventArgs</span>(<br />
                    <span style="color: #2b91af">NotifyCollectionChangedAction</span>.Add,
currentItem));<br />
            }<br />
        }<br /><br />
        <span style="color: blue">#region</span>INotifyCollectionChanged
Members<br /><br />
        <span style="color: blue">public event</span><span style="color: #2b91af">NotifyCollectionChangedEventHandler </span>CollectionChanged;<br /><br />
        <span style="color: blue">#endregion</span></p>
        </blockquote>
        <p>
and passing in the context from the factory:
</p>
        <blockquote>
          <pre class="code">Songs = <span style="color: blue">new </span><span style="color: #2b91af">MediaLibrary</span>( <span style="color: blue">new </span>System.Windows.Threading.<span style="color: #2b91af">DispatcherSynchronizationContext</span>(
System.Windows.<span style="color: #2b91af">Application</span>.Current.Dispatcher)); </pre>
        </blockquote>
        <p>
Of course, this means the factory needs to know what context to pass in, but I wasn't
convinced the factory needed to be in the service layer anyway. Really, it's just
there so WPF has some form of static class to bind to. 
</p>
        <p>
I'm still not sure what I think about this approach. While it works, and can even
be used within a WinForms application (and probably even in ASP.NET), it seems like
we're putting the onus on the event producer rather than the even consumer (who is,
after all, the one who knows whether the event should be caught on a particular thread).
I guess that is one of the things I like about the event model in the Smart Client
Software Factory (SCSF). The producer just raises the even. If the consumer has specific
thread constraints on consuming that event, they declare them explicitly. Hmm. Maybe
I should start looking at using the SCSF to implement this thing...
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=6f370665-4125-4322-8c6c-e4651e4f6048" />
      </body>
      <title>Windows Media Player Remote Control - 6a - Cross-Threading Exceptions</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,6f370665-4125-4322-8c6c-e4651e4f6048.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/22/WindowsMediaPlayerRemoteControl6aCrossThreadingExceptions.aspx</link>
      <pubDate>Tue, 22 Jan 2008 23:43:45 GMT</pubDate>
      <description>&lt;p&gt;
This is the eighth in a series, but the numbering is getting confusing, so I'm going
to stop counting. 
&lt;p&gt;
The first step I took in creating my pretty WMP remote control UI was to &lt;strike&gt;steal&lt;/strike&gt; design
the pretty UI. Once I had the UI, it was a matter of binding the media library entries
to the appropriate WPF elements (a listbox). I used some pretty standard dataset creation
/ binding logic I found somewhere that makes use of the ObjectDataProvider. To implement
this, I created a MediaLibrary and Factory class that looked something like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibrary &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;ObservableCollection&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;
{ &lt;span style="color: blue"&gt;public &lt;/span&gt;MediaLibrary() { GetSongs(); } &lt;span style="color: blue"&gt;private
void &lt;/span&gt;GetSongs() { &lt;span style="color: #2b91af"&gt;IMediaLibraryService &lt;/span&gt;mediaLibrary
= &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibraryServiceClient&lt;/span&gt;(); &lt;span style="color: blue"&gt;int &lt;/span&gt;librarySize
= mediaLibrary.GetSongCount(); &lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; &lt;span style="color: blue"&gt;while &lt;/span&gt;(i
&amp;lt; (librarySize + _pageSize)) { &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
currentIds = mediaLibrary.GetSongs(i, _pageSize); &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;id &lt;span style="color: blue"&gt;in &lt;/span&gt;currentIds)
{ &lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;currentItem = mediaLibrary.GetMediaInfo(id); &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;null &lt;/span&gt;!=
currentItem) { &lt;span style="color: blue"&gt;this&lt;/span&gt;.Add(currentItem); } } i += _pageSize;
} } }&lt;/pre&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public class &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Factory &lt;/span&gt;{ &lt;span style="color: gray"&gt;///
&amp;lt;summary&amp;gt; /// /// &amp;lt;/summary&amp;gt; &lt;/span&gt;&lt;span style="color: blue"&gt;static &lt;/span&gt;Factory()
{ Songs = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibrary&lt;/span&gt;();
} &lt;span style="color: gray"&gt; &lt;/span&gt;&lt;span style="color: blue"&gt;public static &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibrary &lt;/span&gt;Songs
{ &lt;span style="color: blue"&gt;get&lt;/span&gt;; &lt;span style="color: blue"&gt;private set&lt;/span&gt;;
} }&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
And I bound the contents to the UI using syntax like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Grid&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;Grid.Resources&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ObjectDataProvider &lt;/span&gt;&lt;span style="color: red"&gt;x&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: red"&gt;Key&lt;/span&gt;&lt;span style="color: blue"&gt;="FactoryDS" &lt;/span&gt;&lt;span style="color: red"&gt;ObjectType&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;x&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: #a31515"&gt;Type &lt;/span&gt;&lt;span style="color: red"&gt;local&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: red"&gt;Factory&lt;/span&gt;&lt;span style="color: blue"&gt;}"/&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataTemplate &lt;/span&gt;&lt;span style="color: red"&gt;x&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: red"&gt;Key&lt;/span&gt;&lt;span style="color: blue"&gt;="SongTemplate"&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;StackPanel&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;TextBlock &lt;/span&gt;&lt;span style="color: red"&gt;Text&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;Title&lt;/span&gt;&lt;span style="color: blue"&gt;}"/&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;StackPanel&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;DataTemplate&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Grid.Resources&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;
&amp;lt;&lt;/span&gt;&lt;span style="color: #a31515"&gt;ListBox &lt;/span&gt;&lt;span style="color: red"&gt;x&lt;/span&gt;&lt;span style="color: blue"&gt;:&lt;/span&gt;&lt;span style="color: red"&gt;Name&lt;/span&gt;&lt;span style="color: blue"&gt;="songListBox" &lt;/span&gt;&lt;span style="color: red"&gt;ItemsSource&lt;/span&gt;&lt;span style="color: blue"&gt;="{&lt;/span&gt;&lt;span style="color: #a31515"&gt;Binding &lt;/span&gt;&lt;span style="color: red"&gt;Songs&lt;/span&gt;&lt;span style="color: blue"&gt;, &lt;/span&gt;&lt;span style="color: red"&gt;Mode&lt;/span&gt;&lt;span style="color: blue"&gt;=Default, &lt;/span&gt;&lt;span style="color: red"&gt;Source&lt;/span&gt;&lt;span style="color: blue"&gt;={&lt;/span&gt;&lt;span style="color: #a31515"&gt;StaticResource &lt;/span&gt;&lt;span style="color: red"&gt;FactoryDS&lt;/span&gt;&lt;span style="color: blue"&gt;}}" &lt;/span&gt;&lt;span style="color: red"&gt;RenderTransformOrigin&lt;/span&gt;&lt;span style="color: blue"&gt;="0.5,0.5" &lt;/span&gt;&lt;span style="color: red"&gt;DisplayMemberPath&lt;/span&gt;&lt;span style="color: blue"&gt;="Title"
/&amp;gt; &amp;lt;/&lt;/span&gt;&lt;span style="color: #a31515"&gt;Grid&lt;/span&gt;&lt;span style="color: blue"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
That worked great -- synchronously. But, as we already found out, a synchronous call
to the media library webservice isn't the best option (we'd rather page through the
results asynchronously, updating the UI while we go). So, I add a background thread,
changing the constructor to something like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;public &lt;/span&gt;MediaLibrary()
{ System.Threading.&lt;span style="color: #2b91af"&gt;Thread &lt;/span&gt;thread = &lt;span style="color: blue"&gt;new &lt;/span&gt;System.Threading.&lt;span style="color: #2b91af"&gt;Thread&lt;/span&gt;(&lt;span style="color: blue"&gt;new &lt;/span&gt;System.Threading.&lt;span style="color: #2b91af"&gt;ThreadStart&lt;/span&gt;(GetSongs));
thread.Priority = &lt;span style="color: #2b91af"&gt;ThreadPriority&lt;/span&gt;.BelowNormal;
thread.Start(); } &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Run this, and you get a nasty cross-thread exception: "System.NotSupportedException:
This type of CollectionView does not support changes to its SourceCollection from
a thread different from the Dispatcher thread." Huh? What does my business layer need
to know about threading? I'm just updating a collection. But, not to be intimidated
easily, I try other options. How about implementing INotifyCollectionChanged rather
than inheriting from ObservableCollection? Same problem. So, Google reveals a nice
discussion by &lt;a href="http://www.claassen.net/geek/blog/labels/INotifyPropertyChanged.html"&gt;ILoggable&lt;/a&gt;.
He's as frustrated as I am. Really, should my data access layer know whether it's
running on the UI thread? I don't think so. Shouldn't the Binding mechanism in WPF
assume that I will be updating my business objects in background threads? After all,
what's the cost of a 4 core processor nowadays?
&lt;/p&gt;
&lt;p&gt;
I found a bunch of solutions to this problem that relied on explicitly making calls
to Application.Current.Dispatcher.BeginInvoke. That seems sleazy to me. One, slightly
less sleazy solution I found was to pass in a SynchronizationContext to the MediaLibrary
class. This still sounds like the business objects need to know too much about the
runtime, but at least SynchronizationContext is in the System.Windows.Threading namespace,
so it doesn't completely destroy my hopes of separating UI, business, and data.
&lt;/p&gt;
&lt;p&gt;
The solution I finally came up with (borrowed heavily from &lt;a href="http://andyclymer.blogspot.com/2006/10/synchronizationcontext-assists.html"&gt;here&lt;/a&gt;)
was a MediaLibrary with these changes:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public class&lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibrary &lt;/span&gt;: &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;, &lt;span style="color: #2b91af"&gt;INotifyCollectionChanged&lt;br&gt;
&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private const
int &lt;/span&gt;_pageSize = 5;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMediaLibraryService &lt;/span&gt;_mediaLibrary
= &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibraryServiceClient&lt;/span&gt;();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt;&lt;span style="color: #2b91af"&gt;SynchronizationContext &lt;/span&gt;_synchronizationContext;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: gray"&gt;/// &amp;lt;summary&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: blue"&gt;public&lt;/span&gt;MediaLibrary(&lt;span style="color: #2b91af"&gt;SynchronizationContext &lt;/span&gt;sync)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; _synchronizationContext
= sync;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; System.Threading.&lt;span style="color: #2b91af"&gt;Thread&lt;/span&gt;thread
= 
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;new&lt;/span&gt;System.Threading.&lt;span style="color: #2b91af"&gt;Thread&lt;/span&gt;(&lt;span style="color: blue"&gt;new&lt;/span&gt;System.Threading.&lt;span style="color: #2b91af"&gt;ThreadStart&lt;/span&gt;(GetSongs));&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thread.Priority
= &lt;span style="color: #2b91af"&gt;ThreadPriority&lt;/span&gt;.BelowNormal;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thread.Start();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private void&lt;/span&gt;GetSongs()&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;IMediaLibraryService &lt;/span&gt;mediaLibrary
= &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibraryServiceClient&lt;/span&gt;();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int &lt;/span&gt;librarySize
= mediaLibrary.GetSongCount();&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;int &lt;/span&gt;i
= 0;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;while&lt;/span&gt;(i
&amp;lt; (librarySize + _pageSize))&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
currentIds = mediaLibrary.GetSongs(i, _pageSize);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;id &lt;span style="color: blue"&gt;in&lt;/span&gt;currentIds)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;currentItem
= mediaLibrary.GetMediaInfo(id);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt;(&lt;span style="color: blue"&gt;null&lt;/span&gt;!=
currentItem)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.Add(currentItem);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
SafeCollectionChangedNotification(currentItem);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
}&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
i += _pageSize;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private void&lt;/span&gt;SafeCollectionChangedNotification(&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;currentItem)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt;(_synchronizationContext
!= &lt;span style="color: blue"&gt;null&lt;/span&gt;)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
_synchronizationContext.Post(&lt;span style="color: blue"&gt;delegate&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
OnCollectionChanged(currentItem);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
}, &lt;span style="color: blue"&gt;null&lt;/span&gt;);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;else&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;{&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
OnCollectionChanged(currentItem);&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private void&lt;/span&gt;OnCollectionChanged(&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;currentItem)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt;(&lt;span style="color: blue"&gt;null&lt;/span&gt;!=
CollectionChanged)&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
CollectionChanged(&lt;span style="color: blue"&gt;this&lt;/span&gt;, &lt;span style="color: blue"&gt;new&lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedEventArgs&lt;/span&gt;(&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;NotifyCollectionChangedAction&lt;/span&gt;.Add,
currentItem));&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;#region&lt;/span&gt;INotifyCollectionChanged
Members&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public event&lt;/span&gt;&lt;span style="color: #2b91af"&gt;NotifyCollectionChangedEventHandler &lt;/span&gt;CollectionChanged;&lt;br&gt;
&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;#endregion&lt;/span&gt;
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
and passing in the context from the factory:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;Songs = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;MediaLibrary&lt;/span&gt;( &lt;span style="color: blue"&gt;new &lt;/span&gt;System.Windows.Threading.&lt;span style="color: #2b91af"&gt;DispatcherSynchronizationContext&lt;/span&gt;(
System.Windows.&lt;span style="color: #2b91af"&gt;Application&lt;/span&gt;.Current.Dispatcher)); &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Of course, this means the factory needs to know what context to pass in, but I wasn't
convinced the factory needed to be in the service layer anyway. Really, it's just
there so WPF has some form of static class to bind to. 
&lt;/p&gt;
&lt;p&gt;
I'm still not sure what I think about this approach. While it works, and can even
be used within a WinForms application (and probably even in ASP.NET), it seems like
we're putting the onus on the event producer rather than the even consumer (who is,
after all, the one who knows whether the event should be caught on a particular thread).
I guess that is one of the things I like about the event model in the Smart Client
Software Factory (SCSF). The producer just raises the even. If the consumer has specific
thread constraints on consuming that event, they declare them explicitly. Hmm. Maybe
I should start looking at using the SCSF to implement this thing...
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=6f370665-4125-4322-8c6c-e4651e4f6048" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,6f370665-4125-4322-8c6c-e4651e4f6048.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=a04fc2fb-b5f6-41e1-bcda-bf307e64e6de</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,a04fc2fb-b5f6-41e1-bcda-bf307e64e6de.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,a04fc2fb-b5f6-41e1-bcda-bf307e64e6de.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=a04fc2fb-b5f6-41e1-bcda-bf307e64e6de</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the seventh in a series. 
</p>
        <ul>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx">Part
0</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx">Part
1</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx">Part
2</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx">Part
3</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/31/WindowsMediaPlayerRemoteControl4.aspx">Part
4</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2008/01/03/WindowsMediaPlayerRemoteControl5.aspx">Part
5</a>
          </li>
        </ul>
        <p>
As of Part 5, we had a functional end to end solution (let's call it version 1.0)
that I deployed across my <strike>enterprise</strike> household. So, what's next?
As with any product, we know things don't stop here -- the clients have additional
expectations for functionality, the developers find new technology that would be cool
to use, and the QA team finds bugs. Now that it is deployed, however, I'll have to
pay special attention to version handling within our data and operation contracts.
</p>
        <p>
Before making many changes, I decided it might be nice to have some unit tests to
make sure I didn't break anything when rolling out new versions. A few tests later
and I was glad I did. It turns out, I didn't write perfect code during my initial
creation (shocking, I know). There were a few off by one errors, some stupid copy
and paste errors, and a couple of functions that were just plain wrong. So, even though
I didn't do test driven design, per say, I did gain the benefits of a module with
reasonable unit test coverage.
</p>
        <p>
So far, the biggest <strike>complaint</strike> observation from the user base has
been that the client application sucks. While it's functional, it certainly isn't
pretty. Additionally, it isn't the most robust implementation. For example, if you
close the server application and start it back up, the client never reconnects. This
is because, once a WCF service proxy faults, it stays faulted until you do something
about it. So, the next phase will be to write a more robust, prettier version of the
desktop client. Let's start with pretty.
</p>
        <p>
The first step in creating a prettier application is, as is standard in our industry,
to poach someone else's look and feel. While I certainly make my living within the
Microsoft camp, the innovative UI solutions fall solidly within the Macintosh camp.
So, let's take a look at Front Row. There's a great WPF implementation based on some
of the Front Row functionality in a "tutorial" called <a href="http://www.mperfect.net/backRow/">/backRow</a>.
It's been a while since the author updated the article, and the Macintosh camp could
do nothing but complain about the features that were missing. But, I'm no artist,
so I figure I'll start with the look and feel as presented in his article but with
a slightly different animation implementation. More on that later.
</p>
        <p>
Source for this article will be available as it becomes ready. The next few segments
will cover some of the challenges I ran into while developing the newer, prettier
UI. In the mean time, here are a couple of screen shots:
</p>
        <p>
          <a href="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/MusicLibrary_2.jpg">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="MusicLibrary" src="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/MusicLibrary_thumb.jpg" width="637" border="0" />
          </a>
        </p>
        <p>
          <a href="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/NowPlaying_2.jpg">
            <img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="NowPlaying" src="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/NowPlaying_thumb.jpg" width="637" border="0" />
          </a>
        </p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=a04fc2fb-b5f6-41e1-bcda-bf307e64e6de" />
      </body>
      <title>Windows Media Player Remote Control - 6</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,a04fc2fb-b5f6-41e1-bcda-bf307e64e6de.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/22/WindowsMediaPlayerRemoteControl6.aspx</link>
      <pubDate>Tue, 22 Jan 2008 23:42:11 GMT</pubDate>
      <description>&lt;p&gt;
This is the seventh in a series. 
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx"&gt;Part
0&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx"&gt;Part
1&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx"&gt;Part
2&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx"&gt;Part
3&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/31/WindowsMediaPlayerRemoteControl4.aspx"&gt;Part
4&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2008/01/03/WindowsMediaPlayerRemoteControl5.aspx"&gt;Part
5&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
As of Part 5, we had a functional end to end solution (let's call it version 1.0)
that I deployed across my &lt;strike&gt;enterprise&lt;/strike&gt; household. So, what's next?
As with any product, we know things don't stop here -- the clients have additional
expectations for functionality, the developers find new technology that would be cool
to use, and the QA team finds bugs. Now that it is deployed, however, I'll have to
pay special attention to version handling within our data and operation contracts.
&lt;/p&gt;
&lt;p&gt;
Before making many changes, I decided it might be nice to have some unit tests to
make sure I didn't break anything when rolling out new versions. A few tests later
and I was glad I did. It turns out, I didn't write perfect code during my initial
creation (shocking, I know). There were a few off by one errors, some stupid copy
and paste errors, and a couple of functions that were just plain wrong. So, even though
I didn't do test driven design, per say, I did gain the benefits of a module with
reasonable unit test coverage.
&lt;/p&gt;
&lt;p&gt;
So far, the biggest &lt;strike&gt;complaint&lt;/strike&gt; observation from the user base has
been that the client application sucks. While it's functional, it certainly isn't
pretty. Additionally, it isn't the most robust implementation. For example, if you
close the server application and start it back up, the client never reconnects. This
is because, once a WCF service proxy faults, it stays faulted until you do something
about it. So, the next phase will be to write a more robust, prettier version of the
desktop client. Let's start with pretty.
&lt;/p&gt;
&lt;p&gt;
The first step in creating a prettier application is, as is standard in our industry,
to poach someone else's look and feel. While I certainly make my living within the
Microsoft camp, the innovative UI solutions fall solidly within the Macintosh camp.
So, let's take a look at Front Row. There's a great WPF implementation based on some
of the Front Row functionality in a "tutorial" called &lt;a href="http://www.mperfect.net/backRow/"&gt;/backRow&lt;/a&gt;.
It's been a while since the author updated the article, and the Macintosh camp could
do nothing but complain about the features that were missing. But, I'm no artist,
so I figure I'll start with the look and feel as presented in his article but with
a slightly different animation implementation. More on that later.
&lt;/p&gt;
&lt;p&gt;
Source for this article will be available as it becomes ready. The next few segments
will cover some of the challenges I ran into while developing the newer, prettier
UI. In the mean time, here are a couple of screen shots:
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/MusicLibrary_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="MusicLibrary" src="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/MusicLibrary_thumb.jpg" width="637" border="0"&gt;&lt;/a&gt; 
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/NowPlaying_2.jpg"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="484" alt="NowPlaying" src="http://www.cavinconsulting.com/Colby/content/binary/WindowsLiveWriter/WindowsMediaPlayerRemoteControl6_C308/NowPlaying_thumb.jpg" width="637" border="0"&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=a04fc2fb-b5f6-41e1-bcda-bf307e64e6de" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,a04fc2fb-b5f6-41e1-bcda-bf307e64e6de.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=0a32e3a7-3392-4508-af74-949817e6ffff</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,0a32e3a7-3392-4508-af74-949817e6ffff.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,0a32e3a7-3392-4508-af74-949817e6ffff.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=0a32e3a7-3392-4508-af74-949817e6ffff</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the sixth in a series. 
</p>
        <ul>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx">Part
0</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx">Part
1</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx">Part
2</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx">Part
3</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/31/WindowsMediaPlayerRemoteControl4.aspx">Part
4</a>
          </li>
        </ul>
        <p>
With the completion of the previous article, I finally have a media player remote
control that allows a client to do most of the things set out in the original requirements
specification. So, what happened when I deployed it to my production server? Clicking
on the Playlist button causes all sorts of problems. Why? Unlike my test environment,
my production environment has several thousand songs in its media library. So, the
call to GetMediaLibrary() fails spectacularly. Even if it didn't fail completely,
an individual call to GetMediaInfo for each song would take prohibitively long if
I had a sizeable media library.
</p>
        <p>
Chris Sells wrote a wonderful article series on the benefits of multithreading in
WinForms version 1 (<a href="http://msdn2.microsoft.com/en-us/library/ms951089.aspx">here</a>, <a href="http://msdn2.microsoft.com/en-us/library/ms951109.aspx">here</a>,
and <a href="http://msdn2.microsoft.com/en-us/library/ms993020.aspx">here</a>). While
these methods are still applicable, multithreading has gotten easier in version 2
by using the BackgroundWorker component and a few other approaches outlined in Chris'
excellent book <a href="http://www.amazon.com/Windows-Forms-Programming-Microsoft-Development/dp/0321267966">Windows
Forms 2.0 Programming</a>. Additionally, the service reference I added to our client
application has asynchronous calls built-in, so I may be able to make use of those
to keep from freezing the UI.
</p>
        <p>
As far as I can tell, there are two popular ways to solve our problem: 1) take care
of paging in the UI, 2) take care of paging at the service level. There is a nice
discussion of some reasons for each <a href="http://davidpallmann.spaces.live.com/Blog/cns!E95EF9DC3FDB978E!275.entry">here</a>. 
</p>
        <p>
So, what's the answer? Our original goal was to allow client applications to run on
a variety of platforms, including via a web page. So, not all of our clients will
be able to solve the problem by multithreading the UI or using asynchronous calls.
I guess I have to figure out how to implement a service which will allow paging to
the client. That will allow us to solve the client responsiveness issue in whatever
way is most apparent for the client. Our WinForms application can call a huge get-all
type of solution in a background thread while showing a please wait message, 
our web application can page the current n records to the display, and our WPF front-end
can change animations and button themes by directly databinding to the service connection
state by injecting dependency objects into its visualization tree (or whatever it
is that the WPF kids are doing these days).
</p>
        <p>
That means changing our MediaLibraryService contract to look something like this:
</p>
        <blockquote>
          <pre class="code">[<span style="color: #2b91af">ServiceContract</span>(Namespace=<span style="color: #a31515">"http://www.cavinconsulting.com/MediaPlayerRemote/"</span>)] <span style="color: blue">public
interface </span><span style="color: #2b91af">IMediaLibraryService </span>{ [<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
GetMediaLibrary(); [<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">int </span>GetSongCount();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
GetSongs(<span style="color: blue">int </span>startRow, <span style="color: blue">int </span>rowCount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
GetSongsByAlbum(<span style="color: blue">string </span>albumID, <span style="color: blue">int </span>startRow, <span style="color: blue">int </span>rowCount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
GetSongsByGenre(<span style="color: blue">string </span>genre, <span style="color: blue">int </span>startRow, <span style="color: blue">int </span>rowCount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
GetSongsByArtist(<span style="color: blue">string </span>artist, <span style="color: blue">int </span>startRow, <span style="color: blue">int </span>rowCount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">Song </span>GetMediaInfo(<span style="color: #2b91af">Guid </span>songID);
} </pre>
        </blockquote>
        <p>
I've left the GetMediaLibrary() method to support the non-paged version of getting
all of the songs from our library. Also, I switched the song ID type from <span style="color: blue">string </span>to <span style="color: #2b91af">Guid</span> since
they will pass nicely across a WCF ServiceContract and DataContract. Lastly, I have
omitted some potentially useful methods such as GetGenres and GetArtists. That is
because the underlying media library doesn't really support this easily. We may add
this later, depending on the requirements of our client applications, but it will
be less than trivial.
</p>
        <p>
The implementation of the paged back-end was relatively straight forward, though the
implementation I came up with may not be the fastest. Now, we can take a look at how
make use of them from the BackgroundWorker control. Here's what I did: drop a BackgroundWorker
control on the form, add a DoWork event handler, add a DoWorkAsync call to the form
load. Here's what I ended up with for the DoWork event handler:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">private void </span>_mediaLibraryBackgroundWorker_DoWork(<span style="color: blue">object </span>sender, <span style="color: #2b91af">DoWorkEventArgs </span>e)
{ <span style="color: green">// Populate the library </span><span style="color: blue">int </span>librarySize
= _mediaLibraryService.GetSongCount(); <span style="color: blue">int </span>i = 0; <span style="color: blue">while </span>(i
&lt; (librarySize + _pageSize)) { <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Guid</span>&gt;
currentIds = _mediaLibraryService.GetSongs(i, _pageSize); <span style="color: blue">foreach </span>(<span style="color: #2b91af">Guid </span>id <span style="color: blue">in </span>currentIds)
{ <span style="color: #2b91af">Song </span>currentItem = _mediaLibraryService.GetMediaInfo(id); <span style="color: blue">if </span>(<span style="color: blue">null </span>!=
currentItem) { AddSong(currentItem); } } i += _pageSize; } } </pre>
        </blockquote>
        <p>
Where the AddSong() method looks something like this:
</p>
        <blockquote>
          <pre class="code">
            <span style="color: blue">private delegate void </span>
            <span style="color: #2b91af">AddSongDelegate</span>(<span style="color: #2b91af">Song </span>song); <span style="color: blue">private
void </span>AddSong(<span style="color: #2b91af">Song </span>song) { <span style="color: blue">if </span>(InvokeRequired)
{ <span style="color: green">// Invoke AddSong on the UI thread (since this gets called
from the worker thread) </span><span style="color: blue">this</span>.BeginInvoke(<span style="color: blue">new </span><span style="color: #2b91af">AddSongDelegate</span>(AddSong), <span style="color: blue">new
object</span>[] { song }); } <span style="color: blue">else </span>{ <span style="color: blue">if </span>(<span style="color: blue">null </span>!=
song) { _mediaLibrary.Add(song); <span style="color: green">// {... Add the appropriate
TreeNodes to the TreeView ...} </span> } } }</pre>
          <a href="http://11011.net/software/vspaste">
          </a>
        </blockquote>
        <p>
That's it. Now, the playlist UI comes up immediately and the library pane is updated
a few songs at a time, while still remaining responsive to the user. One thing to
note -- the only time we access our member collection (_mediaLibrary) is after we
know we're on the UI thread. So, we shouldn't have any problems with concurrent access
to the collection (reader / writer problem). As a result, we don't have to mess around
with locking the collection or using the SynchronizedCollection&lt;Song&gt; class.
Of course, I could be wrong, and often am.
</p>
        <p>
The source for this version is available <a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote5.zip">here</a>.
Now that things are functional (i.e., we've proven the concept), it's probably time
to revisit the design and implementation with an eye for error handling, testing,
usability, etc. Since the service layer is the foundation for a potentially large
number of clients, we should probably start there.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=0a32e3a7-3392-4508-af74-949817e6ffff" />
      </body>
      <title>Windows Media Player Remote Control - 5</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,0a32e3a7-3392-4508-af74-949817e6ffff.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2008/01/03/WindowsMediaPlayerRemoteControl5.aspx</link>
      <pubDate>Thu, 03 Jan 2008 23:05:20 GMT</pubDate>
      <description>&lt;p&gt;
This is the sixth in a series. 
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx"&gt;Part
0&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx"&gt;Part
1&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx"&gt;Part
2&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx"&gt;Part
3&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/31/WindowsMediaPlayerRemoteControl4.aspx"&gt;Part
4&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
With the completion of the previous article, I finally have a media player remote
control that allows a client to do most of the things set out in the original requirements
specification. So, what happened when I deployed it to my production server? Clicking
on the Playlist button causes all sorts of problems. Why? Unlike my test environment,
my production environment has several thousand songs in its media library. So, the
call to GetMediaLibrary() fails spectacularly. Even if it didn't fail completely,
an individual call to GetMediaInfo for each song would take prohibitively long if
I had a sizeable media library.
&lt;/p&gt;
&lt;p&gt;
Chris Sells wrote a wonderful article series on the benefits of multithreading in
WinForms version 1 (&lt;a href="http://msdn2.microsoft.com/en-us/library/ms951089.aspx"&gt;here&lt;/a&gt;, &lt;a href="http://msdn2.microsoft.com/en-us/library/ms951109.aspx"&gt;here&lt;/a&gt;,
and &lt;a href="http://msdn2.microsoft.com/en-us/library/ms993020.aspx"&gt;here&lt;/a&gt;). While
these methods are still applicable, multithreading has gotten easier in version 2
by using the BackgroundWorker component and a few other approaches outlined in Chris'
excellent book &lt;a href="http://www.amazon.com/Windows-Forms-Programming-Microsoft-Development/dp/0321267966"&gt;Windows
Forms 2.0 Programming&lt;/a&gt;. Additionally, the service reference I added to our client
application has asynchronous calls built-in, so I may be able to make use of those
to keep from freezing the UI.
&lt;/p&gt;
&lt;p&gt;
As far as I can tell, there are two popular ways to solve our problem: 1) take care
of paging in the UI, 2) take care of paging at the service level. There is a nice
discussion of some reasons for each &lt;a href="http://davidpallmann.spaces.live.com/Blog/cns!E95EF9DC3FDB978E!275.entry"&gt;here&lt;/a&gt;. 
&lt;/p&gt;
&lt;p&gt;
So, what's the answer? Our original goal was to allow client applications to run on
a variety of platforms, including via a web page. So, not all of our clients will
be able to solve the problem by multithreading the UI or using asynchronous calls.
I guess I have to figure out how to implement a service which will allow paging to
the client. That will allow us to solve the client responsiveness issue in whatever
way is most apparent for the client. Our WinForms application can call a huge get-all
type of solution in a background thread while showing a please wait message,&amp;nbsp;
our web application can page the current n records to the display, and our WPF front-end
can change animations and button themes by directly databinding to the service connection
state by injecting dependency objects into its visualization tree (or whatever it
is that the WPF kids are doing these days).
&lt;/p&gt;
&lt;p&gt;
That means changing our MediaLibraryService contract to look something like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;(Namespace=&lt;span style="color: #a31515"&gt;"http://www.cavinconsulting.com/MediaPlayerRemote/"&lt;/span&gt;)] &lt;span style="color: blue"&gt;public
interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMediaLibraryService &lt;/span&gt;{ [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
GetMediaLibrary(); [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;int &lt;/span&gt;GetSongCount();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
GetSongs(&lt;span style="color: blue"&gt;int &lt;/span&gt;startRow, &lt;span style="color: blue"&gt;int &lt;/span&gt;rowCount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
GetSongsByAlbum(&lt;span style="color: blue"&gt;string &lt;/span&gt;albumID, &lt;span style="color: blue"&gt;int &lt;/span&gt;startRow, &lt;span style="color: blue"&gt;int &lt;/span&gt;rowCount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
GetSongsByGenre(&lt;span style="color: blue"&gt;string &lt;/span&gt;genre, &lt;span style="color: blue"&gt;int &lt;/span&gt;startRow, &lt;span style="color: blue"&gt;int &lt;/span&gt;rowCount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
GetSongsByArtist(&lt;span style="color: blue"&gt;string &lt;/span&gt;artist, &lt;span style="color: blue"&gt;int &lt;/span&gt;startRow, &lt;span style="color: blue"&gt;int &lt;/span&gt;rowCount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;GetMediaInfo(&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;songID);
} &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
I've left the GetMediaLibrary() method to support the non-paged version of getting
all of the songs from our library. Also, I switched the song ID type from &lt;span style="color: blue"&gt;string &lt;/span&gt;to &lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt; since
they will pass nicely across a WCF ServiceContract and DataContract. Lastly, I have
omitted some potentially useful methods such as GetGenres and GetArtists. That is
because the underlying media library doesn't really support this easily. We may add
this later, depending on the requirements of our client applications, but it will
be less than trivial.
&lt;/p&gt;
&lt;p&gt;
The implementation of the paged back-end was relatively straight forward, though the
implementation I came up with may not be the fastest. Now, we can take a look at how
make use of them from the BackgroundWorker control. Here's what I did: drop a BackgroundWorker
control on the form, add a DoWork event handler, add a DoWorkAsync call to the form
load. Here's what I ended up with for the DoWork event handler:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private void &lt;/span&gt;_mediaLibraryBackgroundWorker_DoWork(&lt;span style="color: blue"&gt;object &lt;/span&gt;sender, &lt;span style="color: #2b91af"&gt;DoWorkEventArgs &lt;/span&gt;e)
{ &lt;span style="color: green"&gt;// Populate the library &lt;/span&gt;&lt;span style="color: blue"&gt;int &lt;/span&gt;librarySize
= _mediaLibraryService.GetSongCount(); &lt;span style="color: blue"&gt;int &lt;/span&gt;i = 0; &lt;span style="color: blue"&gt;while &lt;/span&gt;(i
&amp;lt; (librarySize + _pageSize)) { &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Guid&lt;/span&gt;&amp;gt;
currentIds = _mediaLibraryService.GetSongs(i, _pageSize); &lt;span style="color: blue"&gt;foreach &lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Guid &lt;/span&gt;id &lt;span style="color: blue"&gt;in &lt;/span&gt;currentIds)
{ &lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;currentItem = _mediaLibraryService.GetMediaInfo(id); &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;null &lt;/span&gt;!=
currentItem) { AddSong(currentItem); } } i += _pageSize; } } &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Where the AddSong() method looks something like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;private delegate void &lt;/span&gt;&lt;span style="color: #2b91af"&gt;AddSongDelegate&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;song); &lt;span style="color: blue"&gt;private
void &lt;/span&gt;AddSong(&lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;song) { &lt;span style="color: blue"&gt;if &lt;/span&gt;(InvokeRequired)
{ &lt;span style="color: green"&gt;// Invoke AddSong on the UI thread (since this gets called
from the worker thread) &lt;/span&gt;&lt;span style="color: blue"&gt;this&lt;/span&gt;.BeginInvoke(&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;AddSongDelegate&lt;/span&gt;(AddSong), &lt;span style="color: blue"&gt;new
object&lt;/span&gt;[] { song }); } &lt;span style="color: blue"&gt;else &lt;/span&gt;{ &lt;span style="color: blue"&gt;if &lt;/span&gt;(&lt;span style="color: blue"&gt;null &lt;/span&gt;!=
song) { _mediaLibrary.Add(song); &lt;span style="color: green"&gt;// {... Add the appropriate
TreeNodes to the TreeView ...} &lt;/span&gt; } } }&lt;/pre&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;/blockquote&gt; 
&lt;p&gt;
That's it. Now, the playlist UI comes up immediately and the library pane is updated
a few songs at a time, while still remaining responsive to the user. One thing to
note -- the only time we access our member collection (_mediaLibrary) is after we
know we're on the UI thread. So, we shouldn't have any problems with concurrent access
to the collection (reader / writer problem). As a result, we don't have to mess around
with locking the collection or using the SynchronizedCollection&amp;lt;Song&amp;gt; class.
Of course, I could be wrong, and often am.
&lt;/p&gt;
&lt;p&gt;
The source for this version is available &lt;a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote5.zip"&gt;here&lt;/a&gt;.
Now that things are functional (i.e., we've proven the concept), it's probably time
to revisit the design and implementation with an eye for error handling, testing,
usability, etc. Since the service layer is the foundation for a potentially large
number of clients, we should probably start there.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=0a32e3a7-3392-4508-af74-949817e6ffff" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,0a32e3a7-3392-4508-af74-949817e6ffff.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=74179238-696c-4c79-808c-1776b159d82b</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,74179238-696c-4c79-808c-1776b159d82b.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,74179238-696c-4c79-808c-1776b159d82b.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=74179238-696c-4c79-808c-1776b159d82b</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the fifth in a series. 
</p>
        <ul>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx">Part
0</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx">Part
1</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx">Part
2</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx">Part
3</a>
          </li>
        </ul>
        <p>
This time, let's concentrate on the manipulations a user will want to do on the media
library (retrieving songs, genres, artists, etc.). For this, we'll add another WCF
Service to the MediaPlayerRemoteListener project called MediaLibraryService. The service
contract for this will looks something like:
</p>
        <blockquote>
          <pre class="code">[<span style="color: #2b91af">ServiceContract</span>] <span style="color: blue">public
interface </span><span style="color: #2b91af">IMediaLibraryService </span>{ [<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Song</span>&gt;
GetMediaLibrary(); } </pre>
        </blockquote>
        <p>
With that, all we need to do is plug in the implementation on the server side and
start making use of it on the client side. Of course, this is were things get difficult.
</p>
        <p>
Once again, I find myself at odds with the tools. I've labeled both service contracts
with the "ServiceContract" attribute. I've also been very careful to use the "DataContract"
attribute for any data items returned from our service (in this case, the Song data
contract). However, when adding references from the client via the Add Service Reference
option, I am faced with two copies of the Song data contract on the client -- one
in the MediaLibrary namespace, and one in the NowPlaying namespace. So, if I get a
List&lt;Song&gt; from my MediaLibrary service, and I want to send them to the Play()
method of the NowPlaying service, I have to convert the MediaLibrary.Song to a NowPlaying.Song.
This leads to a large number of mapper classes (or one cleverly designed generic mapper
that uses reflection). I recall similar difficulties with the old .NET 2.0 webservices,
and I had hoped this challenge had been overcome in the new tool set. Apparently not.
</p>
        <p>
I supposed it's prudent to talk about the idea of a data contract. Should separate
services need to share the exact same data definition as an input or an output? One
could argue that if they're so similar, they should be a part of the same service.
However, the simple truth is that it happens quite often in the real world. For example
I'd like to host one interface for read only access and one interface for read/write
access. This allows separate levels of permissions / authentication / protocol for
each interface.
</p>
        <p>
One solution is to revert to command line tools with the new /shareTypes parameter
to wsdl.exe (via <a title="http://www.theserverside.net/tt/blogs/showblog.tss?id=WSStrikesBackP6" href="http://www.theserverside.net/tt/blogs/showblog.tss?id=WSStrikesBackP6">http://www.theserverside.net/tt/blogs/showblog.tss?id=WSStrikesBackP6</a>).
But, this makes the already tedious task of updating our service reference all the
more tedious. Every time I change my contract (which has happened several times so
far), I have to run the hosted version of my service library, escape to the command
line and run a batch file refreshing the service reference in our client application.
Of course, now that I write it down, it's not that much more difficult than changing
the port numbers in my app.config and running the built-in refresh command.
</p>
        <p>
Here's another option. Given our current implementation, we may be able to change
the interfaces to remove any need to share data contracts. Does the Play method really
need the entire song, or just some form of unique identifier to allow the media player
to add it to the play list? It seems like we may be able to get by with a single GetMediaInfo
method returning all of the Song information, and simply passing around some form
of unique identifier for all of the rest of the methods. So we end up with interfaces
like this:
</p>
        <blockquote>
          <pre class="code">[<span style="color: #2b91af">ServiceContract</span>(Namespace
= <span style="color: #a31515">"http://www.cavinconsulting.com/MediaPlayerRemote/"</span>)] <span style="color: blue">public
interface </span><span style="color: #2b91af">INowPlayingService </span>{ [<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">PlayState </span>GetPlayState();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">string </span>GetCurrentSong();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;
GetCurrentPlaylist(); [<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>VolumeUp(<span style="color: blue">int </span>amount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>VolumeDown(<span style="color: blue">int </span>amount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetVolume(<span style="color: blue">int </span>volume);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>MoveNext();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>MovePrevious();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>MoveToSong(<span style="color: blue">string </span>song);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>Play();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>Pause();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>Stop();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetRandom(<span style="color: blue">bool </span>random);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetRepeat(<span style="color: blue">bool </span>repeat);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetMute(<span style="color: blue">bool </span>mute);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>PlayPlaylist(<span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;
playlist, <span style="color: blue">bool </span>appendToCurrentPlaylist); }</pre>
          <pre class="code">[<span style="color: #2b91af">ServiceContract</span>(Namespace=<span style="color: #a31515">"http://www.cavinconsulting.com/MediaPlayerRemote/"</span>)] <span style="color: blue">public
interface </span><span style="color: #2b91af">IMediaLibraryService </span>{ [<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: blue">string</span>&gt;
GetMediaLibrary(); [<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">Song </span>GetMediaInfo(<span style="color: blue">string </span>song);
} </pre>
        </blockquote>
        <p>
This has the advantage of sending around significantly less data than our previous
version. It has the downside of passing primary keys around as strings (I think WMP
uses a 128 bit GUID). This isn't exactly what I had in mind for a solution, but it
seems to be the direction the tools are pushing me. I'm still not sure this makes
sense from a practical standpoint, but we'll keep on following this path for a while
longer.
</p>
        <p>
The source for this post is available <a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote4.zip">here</a>.
There is a really bad implementation of a ListBox that supports being a DragDrop source
as well as destination, and a horrible implementation of displaying a media library
in a TreeView (BTW, Drag and Drop on playlists only works for songs in this example).
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=74179238-696c-4c79-808c-1776b159d82b" />
      </body>
      <title>Windows Media Player Remote Control - 4</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,74179238-696c-4c79-808c-1776b159d82b.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2007/12/31/WindowsMediaPlayerRemoteControl4.aspx</link>
      <pubDate>Mon, 31 Dec 2007 23:02:51 GMT</pubDate>
      <description>&lt;p&gt;
This is the fifth in a series. 
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx"&gt;Part
0&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx"&gt;Part
1&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx"&gt;Part
2&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx"&gt;Part
3&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
This time, let's concentrate on the manipulations a user will want to do on the media
library (retrieving songs, genres, artists, etc.). For this, we'll add another WCF
Service to the MediaPlayerRemoteListener project called MediaLibraryService. The service
contract for this will looks something like:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;] &lt;span style="color: blue"&gt;public
interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMediaLibraryService &lt;/span&gt;{ [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;
GetMediaLibrary(); } &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
With that, all we need to do is plug in the implementation on the server side and
start making use of it on the client side. Of course, this is were things get difficult.
&lt;/p&gt;
&lt;p&gt;
Once again, I find myself at odds with the tools. I've labeled both service contracts
with the "ServiceContract" attribute. I've also been very careful to use the "DataContract"
attribute for any data items returned from our service (in this case, the Song data
contract). However, when adding references from the client via the Add Service Reference
option, I am faced with two copies of the Song data contract on the client -- one
in the MediaLibrary namespace, and one in the NowPlaying namespace. So, if I get a
List&amp;lt;Song&amp;gt; from my MediaLibrary service, and I want to send them to the Play()
method of the NowPlaying service, I have to convert the MediaLibrary.Song to a NowPlaying.Song.
This leads to a large number of mapper classes (or one cleverly designed generic mapper
that uses reflection). I recall similar difficulties with the old .NET 2.0 webservices,
and I had hoped this challenge had been overcome in the new tool set. Apparently not.
&lt;/p&gt;
&lt;p&gt;
I supposed it's prudent to talk about the idea of a data contract. Should separate
services need to share the exact same data definition as an input or an output? One
could argue that if they're so similar, they should be a part of the same service.
However, the simple truth is that it happens quite often in the real world. For example
I'd like to host one interface for read only access and one interface for read/write
access. This allows separate levels of permissions / authentication / protocol for
each interface.
&lt;/p&gt;
&lt;p&gt;
One solution is to revert to command line tools with the new /shareTypes parameter
to wsdl.exe (via &lt;a title="http://www.theserverside.net/tt/blogs/showblog.tss?id=WSStrikesBackP6" href="http://www.theserverside.net/tt/blogs/showblog.tss?id=WSStrikesBackP6"&gt;http://www.theserverside.net/tt/blogs/showblog.tss?id=WSStrikesBackP6&lt;/a&gt;).
But, this makes the already tedious task of updating our service reference all the
more tedious. Every time I change my contract (which has happened several times so
far), I have to run the hosted version of my service library, escape to the command
line and run a batch file refreshing the service reference in our client application.
Of course, now that I write it down, it's not that much more difficult than changing
the port numbers in my app.config and running the built-in refresh command.
&lt;/p&gt;
&lt;p&gt;
Here's another option. Given our current implementation, we may be able to change
the interfaces to remove any need to share data contracts. Does the Play method really
need the entire song, or just some form of unique identifier to allow the media player
to add it to the play list? It seems like we may be able to get by with a single GetMediaInfo
method returning all of the Song information, and simply passing around some form
of unique identifier for all of the rest of the methods. So we end up with interfaces
like this:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;(Namespace
= &lt;span style="color: #a31515"&gt;"http://www.cavinconsulting.com/MediaPlayerRemote/"&lt;/span&gt;)] &lt;span style="color: blue"&gt;public
interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;INowPlayingService &lt;/span&gt;{ [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;PlayState &lt;/span&gt;GetPlayState();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;string &lt;/span&gt;GetCurrentSong();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
GetCurrentPlaylist(); [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;VolumeUp(&lt;span style="color: blue"&gt;int &lt;/span&gt;amount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;VolumeDown(&lt;span style="color: blue"&gt;int &lt;/span&gt;amount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetVolume(&lt;span style="color: blue"&gt;int &lt;/span&gt;volume);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;MoveNext();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;MovePrevious();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;MoveToSong(&lt;span style="color: blue"&gt;string &lt;/span&gt;song);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;Play();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;Pause();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;Stop();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetRandom(&lt;span style="color: blue"&gt;bool &lt;/span&gt;random);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetRepeat(&lt;span style="color: blue"&gt;bool &lt;/span&gt;repeat);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetMute(&lt;span style="color: blue"&gt;bool &lt;/span&gt;mute);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;PlayPlaylist(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
playlist, &lt;span style="color: blue"&gt;bool &lt;/span&gt;appendToCurrentPlaylist); }&lt;/pre&gt;&lt;pre class="code"&gt;[&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;(Namespace=&lt;span style="color: #a31515"&gt;"http://www.cavinconsulting.com/MediaPlayerRemote/"&lt;/span&gt;)] &lt;span style="color: blue"&gt;public
interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;IMediaLibraryService &lt;/span&gt;{ [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;
GetMediaLibrary(); [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;GetMediaInfo(&lt;span style="color: blue"&gt;string &lt;/span&gt;song);
} &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
This has the advantage of sending around significantly less data than our previous
version. It has the downside of passing primary keys around as strings (I think WMP
uses a 128 bit GUID). This isn't exactly what I had in mind for a solution, but it
seems to be the direction the tools are pushing me. I'm still not sure this makes
sense from a practical standpoint, but we'll keep on following this path for a while
longer.
&lt;/p&gt;
&lt;p&gt;
The source for this post is available &lt;a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote4.zip"&gt;here&lt;/a&gt;.
There is a really bad implementation of a ListBox that supports being a DragDrop source
as well as destination, and a horrible implementation of displaying a media library
in a TreeView (BTW, Drag and Drop on playlists only works for songs in this example).
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=74179238-696c-4c79-808c-1776b159d82b" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,74179238-696c-4c79-808c-1776b159d82b.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=ed7c986b-1628-445a-9739-46daffea1008</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,ed7c986b-1628-445a-9739-46daffea1008.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,ed7c986b-1628-445a-9739-46daffea1008.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=ed7c986b-1628-445a-9739-46daffea1008</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the fourth in a series. 
</p>
        <ul>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx">Part
0</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx">Part
1</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx">Part
2</a>
          </li>
        </ul>
        <p>
With our "design" out of the way, we can start digging in to the actual implementation.
Our first draft will be somewhat exploratory in nature. Given my limited knowledge
of the Windows Media Player plug-in architecture, I have decided to start by hosting
the WMP ActiveX control in a standalone WinForms application, and have this WinForms
application host a WCF service. So, here goes: 
</p>
        <p>
We'll start off by designing the communication contract through which our client controls
and queries our media player. For now, we'll concentrate on controlling the media
player. For this, we'll use a WCF contract called INowPlayingService: 
</p>
        <blockquote>
          <pre>[<span style="color: #2b91af">ServiceContract</span>] <span style="color: blue">public
interface </span><span style="color: #2b91af">INowPlayingService </span>{ [<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">PlayState </span>GetPlayState();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">Song </span>GetCurrentSong();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Song</span>&gt;
GetCurrentPlaylist(); [<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>VolumeUp(<span style="color: blue">int </span>amount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>VolumeDown(<span style="color: blue">int </span>amount);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetVolume(<span style="color: blue">int </span>volume);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>MoveNext();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>MovePrevious();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>Play();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>Pause();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>Stop();
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetRandom(<span style="color: blue">bool </span>random);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetRepeat(<span style="color: blue">bool </span>repeat);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>SetMute(<span style="color: blue">bool </span>mute);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Song</span>&gt;
AddToCurrentPlaylist(<span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Song</span>&gt;
playlist); [<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>PlayInPlaylist(<span style="color: #2b91af">Song </span>song);
[<span style="color: #2b91af">OperationContract</span>] <span style="color: blue">void </span>ReplaceCurrentPlaylist(<span style="color: #2b91af">List</span>&lt;<span style="color: #2b91af">Song</span>&gt;
playlist); } </pre>
        </blockquote>
        <p>
That looks like a pretty comprehensive list of operations we would want to perform
on a media player. So, let's get down to the business of actually implementing this
in Visual Studio 2008. I start a new solution and add three projects, a WinForms host
application, a WinForms Client application, and WCF Service Library. I add a project
reference from the host application to the service library. Then, I notice I can add
a service reference from the client application to the service library. Right click
on the project, click add service reference, click discover-&gt;services in this solution,
and choose the service of interest. Nice! Or, so I thought. 
</p>
        <p>
Here's where the first problem arises. Remember, I'm using this as an exercise to
get my head around the new technologies. The WCF service library project type does
a nice job of housing the service components as well as publishing the appropriate
meta data for things like adding service references. However, when I go to debug this
application, VS automatically spins up the WcfSvcHost process to host our service
library. But, remember, I want to host the WCF endpoint within my host WinForms application.
No matter what projects you tell VS to start up (or not start up) on debug, it ALWAYS
runs the WcfSvcHost application and starts hosting my service library. 
</p>
        <p>
It turns out, I'm not the first person to have this problem: <a title="Visual Studio 2008, WCF Service Libraries, and CTRL-F5" href="http://www.pluralsight.com/blogs/aaron/archive/2007/11/15/49165.aspx">Visual
Studio 2008, WCF Service Libraries, and CTRL-F5</a>. It appears that the solution
is to "remove the project type GUID" that tells VS that it's a WCF Service Library.
What? So, in order to host a WCF service library in my own application, I have to
disable all of the helpful aspects of VS regarding WCF endpoints (like, say, updating
my service reference as the contract changes over time). Ridiculous. 
</p>
        <p>
Here's how I finally resolved it. Leave it as a WCF service library, but change the
port values in the app.conf sections so my host uses a different port than the WCF
service library. That way, in the course of normal debugging, the client points to
the ports opened by my host. When I need to update the reference, I change the port
to the VS host port, update the reference, and then change it back. It's a nasty bit
of kludgery, but it works for my needs. It seems like I must be making a habit of
doing things Microsoft doesn't expect. First, I expected a standard windows application
to be simple in WPF, now this. 
</p>
        <p>
Anyway, source code (so far) is available <a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote3.zip">here</a>.
You'll want to change the URL property of the media player control in the host application.
You'll also want to set the startup projects so that the host and the client are both
started. It's a pretty basic remote control with standard navigation utilities. Next,
we'll flesh out some of the media library functionality so we can change what gets
played.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=ed7c986b-1628-445a-9739-46daffea1008" />
      </body>
      <title>Windows Media Player Remote Control - 3</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,ed7c986b-1628-445a-9739-46daffea1008.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2007/12/21/WindowsMediaPlayerRemoteControl3.aspx</link>
      <pubDate>Fri, 21 Dec 2007 22:56:46 GMT</pubDate>
      <description>&lt;p&gt;
This is the fourth in a series. 
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx"&gt;Part
0&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx"&gt;Part
1&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx"&gt;Part
2&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
With our "design" out of the way, we can start digging in to the actual implementation.
Our first draft will be somewhat exploratory in nature. Given my limited knowledge
of the Windows Media Player plug-in architecture, I have decided to start by hosting
the WMP ActiveX control in a standalone WinForms application, and have this WinForms
application host a WCF service. So, here goes: 
&lt;p&gt;
We'll start off by designing the communication contract through which our client controls
and queries our media player. For now, we'll concentrate on controlling the media
player. For this, we'll use a WCF contract called INowPlayingService: &lt;blockquote&gt;&lt;pre&gt;[&lt;span style="color: #2b91af"&gt;ServiceContract&lt;/span&gt;] &lt;span style="color: blue"&gt;public
interface &lt;/span&gt;&lt;span style="color: #2b91af"&gt;INowPlayingService &lt;/span&gt;{ [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;PlayState &lt;/span&gt;GetPlayState();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;GetCurrentSong();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;
GetCurrentPlaylist(); [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;VolumeUp(&lt;span style="color: blue"&gt;int &lt;/span&gt;amount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;VolumeDown(&lt;span style="color: blue"&gt;int &lt;/span&gt;amount);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetVolume(&lt;span style="color: blue"&gt;int &lt;/span&gt;volume);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;MoveNext();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;MovePrevious();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;Play();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;Pause();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;Stop();
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetRandom(&lt;span style="color: blue"&gt;bool &lt;/span&gt;random);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetRepeat(&lt;span style="color: blue"&gt;bool &lt;/span&gt;repeat);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;SetMute(&lt;span style="color: blue"&gt;bool &lt;/span&gt;mute);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;
AddToCurrentPlaylist(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;
playlist); [&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;PlayInPlaylist(&lt;span style="color: #2b91af"&gt;Song &lt;/span&gt;song);
[&lt;span style="color: #2b91af"&gt;OperationContract&lt;/span&gt;] &lt;span style="color: blue"&gt;void &lt;/span&gt;ReplaceCurrentPlaylist(&lt;span style="color: #2b91af"&gt;List&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;Song&lt;/span&gt;&amp;gt;
playlist); } &lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
That looks like a pretty comprehensive list of operations we would want to perform
on a media player. So, let's get down to the business of actually implementing this
in Visual Studio 2008. I start a new solution and add three projects, a WinForms host
application, a WinForms Client application, and WCF Service Library. I add a project
reference from the host application to the service library. Then, I notice I can add
a service reference from the client application to the service library. Right click
on the project, click add service reference, click discover-&amp;gt;services in this solution,
and choose the service of interest. Nice! Or, so I thought. 
&lt;p&gt;
Here's where the first problem arises. Remember, I'm using this as an exercise to
get my head around the new technologies. The WCF service library project type does
a nice job of housing the service components as well as publishing the appropriate
meta data for things like adding service references. However, when I go to debug this
application, VS automatically spins up the WcfSvcHost process to host our service
library. But, remember, I want to host the WCF endpoint within my host WinForms application.
No matter what projects you tell VS to start up (or not start up) on debug, it ALWAYS
runs the WcfSvcHost application and starts hosting my service library. 
&lt;p&gt;
It turns out, I'm not the first person to have this problem: &lt;a title="Visual Studio 2008, WCF Service Libraries, and CTRL-F5" href="http://www.pluralsight.com/blogs/aaron/archive/2007/11/15/49165.aspx"&gt;Visual
Studio 2008, WCF Service Libraries, and CTRL-F5&lt;/a&gt;. It appears that the solution
is to "remove the project type GUID" that tells VS that it's a WCF Service Library.
What? So, in order to host a WCF service library in my own application, I have to
disable all of the helpful aspects of VS regarding WCF endpoints (like, say, updating
my service reference as the contract changes over time). Ridiculous. 
&lt;p&gt;
Here's how I finally resolved it. Leave it as a WCF service library, but change the
port values in the app.conf sections so my host uses a different port than the WCF
service library. That way, in the course of normal debugging, the client points to
the ports opened by my host. When I need to update the reference, I change the port
to the VS host port, update the reference, and then change it back. It's a nasty bit
of kludgery, but it works for my needs. It seems like I must be making a habit of
doing things Microsoft doesn't expect. First, I expected a standard windows application
to be simple in WPF, now this. 
&lt;p&gt;
Anyway, source code (so far) is available &lt;a href="http://www.cavinconsulting.com/Code/MediaPlayerRemote3.zip"&gt;here&lt;/a&gt;.
You'll want to change the URL property of the media player control in the host application.
You'll also want to set the startup projects so that the host and the client are both
started. It's a pretty basic remote control with standard navigation utilities. Next,
we'll flesh out some of the media library functionality so we can change what gets
played.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=ed7c986b-1628-445a-9739-46daffea1008" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,ed7c986b-1628-445a-9739-46daffea1008.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=1cfd0e62-e780-4bb3-af85-56fb6009fe75</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,1cfd0e62-e780-4bb3-af85-56fb6009fe75.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,1cfd0e62-e780-4bb3-af85-56fb6009fe75.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=1cfd0e62-e780-4bb3-af85-56fb6009fe75</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the third in a series.
</p>
        <ul>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx">Part
0</a>
          </li>
          <li>
            <a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx">Part
1</a>
          </li>
        </ul>
        <h2>Design
</h2>
        <p>
As with any good development effort, we begin by designing the solution, complete
with an assessment of the pros and cons of each option. Of course, as with any good
development effort, we begin with every intention of designing the solution, but we
usually skip right past this to writing the code since designs are never any fun.
Design: There is a server and there are 0 or more clients that want to control what
the server spits out the sound card.
</p>
        <p>
Right. With the design done, let's talk about implementation options:
</p>
        <p>
As I see it, there are two options for implementing the functionality as exhaustively
enumerated in Part 0 of our series: 1) A standalone application in which we host and
automate a Windows Media Player control, 2) A plug-in to the existing standalone Windows
Media Player in which we automate the instance of Windows Media Player in which we
are hosted.
</p>
        <p>
So, which of these approaches is better? I have no idea. So, we'll design the approach
in such a way that the end user (client machine) doesn't care. How? SOA, WCF, and
other TLA's. I figure I can hide my media playing component/service/application behind
a WCF connection point. Then, if hosting the ActiveX control fails miserably or creating
the WMP plug-in doesn't play nicely with .NET, then I'll always be able to call some
arcane WIN32 function to dump directly to the sound card or convert to Linux, convert
all of my WMA's to raw .au files and just cat [file.au] &gt; /dev/audio.
</p>
        <p>
Of course, that's an exaggeration. I'm sure one of the two approaches will work fine.
I just don't know which. So, hiding the solution behind a WCF connection point should
give me the flexibility to try both approaches without rewriting the clients.
</p>
        <p>
At this point, I find that there are a couple of interesting questions to which I
do not know the answer. This, of course, will not keep me from plunging headlong into
the implementation. They're just questions.
</p>
        <ul>
          <li>
If I host an instance of the WMP ActiveX control, does it still do all of the clever
background work of sniffing media information from the Internet, listening for changes
in my media library, and downloading album art or is it just a numb playback machine
using the existing media library? 
</li>
          <li>
What are the multi-threading characteristics of the WMP library? Will I have to perform
the read/write locks, or will WMP take care of that for me?</li>
        </ul>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=1cfd0e62-e780-4bb3-af85-56fb6009fe75" />
      </body>
      <title>Windows Media Player Remote Control - 2</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,1cfd0e62-e780-4bb3-af85-56fb6009fe75.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2007/12/14/WindowsMediaPlayerRemoteControl2.aspx</link>
      <pubDate>Fri, 14 Dec 2007 22:54:53 GMT</pubDate>
      <description>&lt;p&gt;
This is the third in a series.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2008/06/03/WindowsMediaPlayerRemoteControl0.aspx"&gt;Part
0&lt;/a&gt; 
&lt;li&gt;
&lt;a href="http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx"&gt;Part
1&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Design
&lt;/h2&gt;
&lt;p&gt;
As with any good development effort, we begin by designing the solution, complete
with an assessment of the pros and cons of each option. Of course, as with any good
development effort, we begin with every intention of designing the solution, but we
usually skip right past this to writing the code since designs are never any fun.
Design: There is a server and there are 0 or more clients that want to control what
the server spits out the sound card.
&lt;/p&gt;
&lt;p&gt;
Right. With the design done, let's talk about implementation options:
&lt;/p&gt;
&lt;p&gt;
As I see it, there are two options for implementing the functionality as exhaustively
enumerated in Part 0 of our series: 1) A standalone application in which we host and
automate a Windows Media Player control, 2) A plug-in to the existing standalone Windows
Media Player in which we automate the instance of Windows Media Player in which we
are hosted.
&lt;/p&gt;
&lt;p&gt;
So, which of these approaches is better? I have no idea. So, we'll design the approach
in such a way that the end user (client machine) doesn't care. How? SOA, WCF, and
other TLA's. I figure I can hide my media playing component/service/application behind
a WCF connection point. Then, if hosting the ActiveX control fails miserably or creating
the WMP plug-in doesn't play nicely with .NET, then I'll always be able to call some
arcane WIN32 function to dump directly to the sound card or convert to Linux, convert
all of my WMA's to raw .au files and just cat [file.au] &amp;gt; /dev/audio.
&lt;/p&gt;
&lt;p&gt;
Of course, that's an exaggeration. I'm sure one of the two approaches will work fine.
I just don't know which. So, hiding the solution behind a WCF connection point should
give me the flexibility to try both approaches without rewriting the clients.
&lt;/p&gt;
&lt;p&gt;
At this point, I find that there are a couple of interesting questions to which I
do not know the answer. This, of course, will not keep me from plunging headlong into
the implementation. They're just questions.
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
If I host an instance of the WMP ActiveX control, does it still do all of the clever
background work of sniffing media information from the Internet, listening for changes
in my media library, and downloading album art or is it just a numb playback machine
using the existing media library? 
&lt;li&gt;
What are the multi-threading characteristics of the WMP library? Will I have to perform
the read/write locks, or will WMP take care of that for me?&lt;/li&gt;
&lt;/ul&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=1cfd0e62-e780-4bb3-af85-56fb6009fe75" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,1cfd0e62-e780-4bb3-af85-56fb6009fe75.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=e1097cc0-da08-46e8-8e22-073e44e5e627</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,e1097cc0-da08-46e8-8e22-073e44e5e627.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,e1097cc0-da08-46e8-8e22-073e44e5e627.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=e1097cc0-da08-46e8-8e22-073e44e5e627</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Build or Buy decision 
</p>
        <p>
This is the second in a series. The overview is <a href="http://www.cavinconsulting.com/Colby/2007/12/10/WindowsMediaPlayerRemoteControl0.aspx">here</a>. 
</p>
        <p>
State of the industry: 
</p>
        <p>
So far, I can find a bunch of solutions to stream media to a client. That is, given
a server containing a bunch of media, Spit it out to a client machine (PC, cell phone,
television, etc.) so you can consume it wherever you are. This doesn't cut it for
our purposes. Instead, we want the media to play at the source, but be able to change
the behavior of the media player at the host from a client somewhere. 
</p>
        <p>
Items of interest: 
</p>
        <ul>
          <li>
            <a title="http://pocketpccentral.net/software/remote2.htm" href="http://pocketpccentral.net/software/remote2.htm">http://pocketpccentral.net/software/remote2.htm</a> -
semi-functional 
</li>
          <li>
            <a title="http://msdn2.microsoft.com/en-us/library/ms973247.aspx" href="http://msdn2.microsoft.com/en-us/library/ms973247.aspx">http://msdn2.microsoft.com/en-us/library/ms973247.aspx</a> -
educational, but not entirely functional for our purposes (makes use of .net remoting
which isn't my favorite solution, not sure why) 
</li>
          <li>
            <a title="http://www.alloysoft.com/" href="http://www.alloysoft.com/">http://www.alloysoft.com/</a> -
Might be great if I had an iPhone 
</li>
          <li>
            <a title="http://www.x10.com/entertainment/remote_controls.html" href="http://www.x10.com/entertainment/remote_controls.html">http://www.x10.com/entertainment/remote_controls.html</a> -
might have something of interest if I were an X10 household</li>
        </ul>
        <p>
So far, that's all I have. So, if I want a remote control to work on a laptop, pocket
pc, smartphone, (and maybe a website), it looks like I'm out of luck in the commercial
market. So, it looks like the build option is the one for me. 
</p>
        <p>
Of course, that's what I expected to choose. Otherwise, this would have been a really
short series.
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=e1097cc0-da08-46e8-8e22-073e44e5e627" />
      </body>
      <title>Windows Media Player Remote Control - 1</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,e1097cc0-da08-46e8-8e22-073e44e5e627.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2007/12/11/WindowsMediaPlayerRemoteControl1.aspx</link>
      <pubDate>Tue, 11 Dec 2007 22:51:22 GMT</pubDate>
      <description>&lt;p&gt;
Build or Buy decision 
&lt;p&gt;
This is the second in a series. The overview is &lt;a href="http://www.cavinconsulting.com/Colby/2007/12/10/WindowsMediaPlayerRemoteControl0.aspx"&gt;here&lt;/a&gt;. 
&lt;p&gt;
State of the industry: 
&lt;p&gt;
So far, I can find a bunch of solutions to stream media to a client. That is, given
a server containing a bunch of media, Spit it out to a client machine (PC, cell phone,
television, etc.) so you can consume it wherever you are. This doesn't cut it for
our purposes. Instead, we want the media to play at the source, but be able to change
the behavior of the media player at the host from a client somewhere. 
&lt;p&gt;
Items of interest: 
&lt;ul&gt;
&lt;li&gt;
&lt;a title="http://pocketpccentral.net/software/remote2.htm" href="http://pocketpccentral.net/software/remote2.htm"&gt;http://pocketpccentral.net/software/remote2.htm&lt;/a&gt; -
semi-functional 
&lt;li&gt;
&lt;a title="http://msdn2.microsoft.com/en-us/library/ms973247.aspx" href="http://msdn2.microsoft.com/en-us/library/ms973247.aspx"&gt;http://msdn2.microsoft.com/en-us/library/ms973247.aspx&lt;/a&gt; -
educational, but not entirely functional for our purposes (makes use of .net remoting
which isn't my favorite solution, not sure why) 
&lt;li&gt;
&lt;a title="http://www.alloysoft.com/" href="http://www.alloysoft.com/"&gt;http://www.alloysoft.com/&lt;/a&gt; -
Might be great if I had an iPhone 
&lt;li&gt;
&lt;a title="http://www.x10.com/entertainment/remote_controls.html" href="http://www.x10.com/entertainment/remote_controls.html"&gt;http://www.x10.com/entertainment/remote_controls.html&lt;/a&gt; -
might have something of interest if I were an X10 household&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
So far, that's all I have. So, if I want a remote control to work on a laptop, pocket
pc, smartphone, (and maybe a website), it looks like I'm out of luck in the commercial
market. So, it looks like the build option is the one for me. 
&lt;p&gt;
Of course, that's what I expected to choose. Otherwise, this would have been a really
short series.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=e1097cc0-da08-46e8-8e22-073e44e5e627" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,e1097cc0-da08-46e8-8e22-073e44e5e627.aspx</comments>
      <category>Windows Media Player</category>
    </item>
    <item>
      <trackback:ping>http://www.cavinconsulting.com/Colby/Trackback.aspx?guid=ebe42044-0707-4dd5-b9de-c91d1da38b86</trackback:ping>
      <pingback:server>http://www.cavinconsulting.com/Colby/pingback.aspx</pingback:server>
      <pingback:target>http://www.cavinconsulting.com/Colby/PermaLink,guid,ebe42044-0707-4dd5-b9de-c91d1da38b86.aspx</pingback:target>
      <dc:creator>Colby</dc:creator>
      <wfw:comment>http://www.cavinconsulting.com/Colby/CommentView,guid,ebe42044-0707-4dd5-b9de-c91d1da38b86.aspx</wfw:comment>
      <wfw:commentRss>http://www.cavinconsulting.com/Colby/SyndicationService.asmx/GetEntryCommentsRss?guid=ebe42044-0707-4dd5-b9de-c91d1da38b86</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
This is the beginning in a series of unknown length regarding controlling the Windows
Media Player from remote machines. So far, I'm at the requirements phase. Next will
come industry research (buy or build), but I'm pretty sure I'm going to build something
anyway (even if there are perfectly usable buy options -- I'm just stubborn that way). 
</p>
        <p>
Here are the requirements in no particular format or order: 
</p>
        <ul>
          <li>
I have a Server 2003 machine running with its audio output hooked up to the whole
house audio system (okay, it's just two speakers in a different room, but there's
a volume control in there, so I can call it what I want). The server houses the media
collection and runs a uPnP server (TwonkyMedia) for the rest of the machines in the
house to stream. 
</li>
          <li>
I can play audio through the server if I remote terminal to the server, run media
player, and choose some songs. That, of course, completely fails the Wife Acceptance
Factor (<a href="http://en.wikipedia.org/wiki/Woman_acceptance_factor">WAF</a>). 
</li>
          <li>
What I would like is a service or application running on the server to be ready to
play at all times, and have the rest of the machines (including handheld and smartphone)
be able to dynamically change the playlist, start, stop, fast forward (most important)
and rewind. 
</li>
          <li>
I'd like this to run as part of Media Player. I'm not sure why, since SOA dictates
that we're just exposing a service, not a particular technology. I think it's mainly
because I'm used to maintaining the media library in WMP and I don't want to change. 
</li>
          <li>
An added bonus is if there were a sidebar gadget for my wife's Vista machine (yes,
I'm still on XP until some of the performance issues are worked out), and a 10' UI
for the media center PC in the family room. 
</li>
          <li>
Since the uPnP server streams media to all of the important places (laptop and media
center), there's no reason to mess around with streaming the actual audio to the remote
control client, though the now-playing art would be nice. 
</li>
        </ul>
        <p>
That's it. In those few, short paragraphs, I have managed to cut out a lot of work
for myself. I'm looking for a media player with remote controls that run on smartphone,
pda, xp, and as a sidebar gadget. I'd like it to run on server 2003 every time it
starts up, be multi-remote control robust, and extremely fault tolerant. 
</p>
        <p>
Now, to the buy or build comparisons...
</p>
        <img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=ebe42044-0707-4dd5-b9de-c91d1da38b86" />
      </body>
      <title>Windows Media Player Remote Control - 0</title>
      <guid isPermaLink="false">http://www.cavinconsulting.com/Colby/PermaLink,guid,ebe42044-0707-4dd5-b9de-c91d1da38b86.aspx</guid>
      <link>http://www.cavinconsulting.com/Colby/2007/12/10/WindowsMediaPlayerRemoteControl0.aspx</link>
      <pubDate>Mon, 10 Dec 2007 15:48:37 GMT</pubDate>
      <description>&lt;p&gt;
This is the beginning in a series of unknown length regarding controlling the Windows
Media Player from remote machines. So far, I'm at the requirements phase. Next will
come industry research (buy or build), but I'm pretty sure I'm going to build something
anyway (even if there are perfectly usable buy options -- I'm just stubborn that way). 
&lt;p&gt;
Here are the requirements in no particular format or order: 
&lt;ul&gt;
&lt;li&gt;
I have a Server 2003 machine running with its audio output hooked up to the whole
house audio system (okay, it's just two speakers in a different room, but there's
a volume control in there, so I can call it what I want). The server houses the media
collection and runs a uPnP server (TwonkyMedia) for the rest of the machines in the
house to stream. 
&lt;li&gt;
I can play audio through the server if I remote terminal to the server, run media
player, and choose some songs. That, of course, completely fails the Wife Acceptance
Factor (&lt;a href="http://en.wikipedia.org/wiki/Woman_acceptance_factor"&gt;WAF&lt;/a&gt;). 
&lt;li&gt;
What I would like is a service or application running on the server to be ready to
play at all times, and have the rest of the machines (including handheld and smartphone)
be able to dynamically change the playlist, start, stop, fast forward (most important)
and rewind. 
&lt;li&gt;
I'd like this to run as part of Media Player. I'm not sure why, since SOA dictates
that we're just exposing a service, not a particular technology. I think it's mainly
because I'm used to maintaining the media library in WMP and I don't want to change. 
&lt;li&gt;
An added bonus is if there were a sidebar gadget for my wife's Vista machine (yes,
I'm still on XP until some of the performance issues are worked out), and a 10' UI
for the media center PC in the family room. 
&lt;li&gt;
Since the uPnP server streams media to all of the important places (laptop and media
center), there's no reason to mess around with streaming the actual audio to the remote
control client, though the now-playing art would be nice. 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
That's it. In those few, short paragraphs, I have managed to cut out a lot of work
for myself. I'm looking for a media player with remote controls that run on smartphone,
pda, xp, and as a sidebar gadget. I'd like it to run on server 2003 every time it
starts up, be multi-remote control robust, and extremely fault tolerant. 
&lt;p&gt;
Now, to the buy or build comparisons...
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.cavinconsulting.com/Colby/aggbug.ashx?id=ebe42044-0707-4dd5-b9de-c91d1da38b86" /&gt;</description>
      <comments>http://www.cavinconsulting.com/Colby/CommentView,guid,ebe42044-0707-4dd5-b9de-c91d1da38b86.aspx</comments>
      <category>Windows Media Player</category>
    </item>
  </channel>
</rss>