Feed Icon  

Contact

  • Bryant Likes
  • Send mail to the author(s) E-mail
  • twitter
  • View Bryant Likes's profile on LinkedIn
  • del.icio.us
Get Microsoft Silverlight
by clicking "Install Microsoft Silverlight" you accept the
Silverlight license agreement

Hosting By

Hot Topics

Tags

Open Source Projects

Archives

Ads

WPF Patterns

Posted in WPF at Wednesday, September 27, 2006 6:30 AM Pacific Daylight Time

If you're doing WPF development, you really need to check out Dan Crevier's series on DataModel-View-ViewModel. Right now there is no easy way to read through all his posts on the subject without navigating through them using the calendar control on his blog. So for my own reference (and for yours as well) here is the list of links in the series:

  1. DataModel-View-ViewModel pattern: 1
  2. DataModel-View-ViewModel pattern: 2
  3. DM-V-VM part 3: A sample DataModel
  4. DM-V-VM part 4: Unit testing the DataModel
  5. DM-V-VM part 5: Commands
  6. DM-V-VM part 6: Revisiting the data model
  7. DM-M-VM part 7: Encapsulating commands*
  8. DM-M-VM part 8: View Models*

In addition to Dan's work, John Gossman's work on the Model-View-ViewModel pattern which is pretty similar and is also important when it comes to understanding how to design a WPF application. He has several posts on this pattern which I've collected below:

I think they are both saying pretty much the same thing. From my limited experience with designing WPF application I'd say what they are saying is correct. You really do need the kind of seperation they are talking about to make your WPF app work well. If you hard-code the click event in the XAML code-behind, how do you extend that to the context menu, the short-cut key, etc. without making things tightly coupled?

I'm currently working on updating my Contacts Sample to be more in line with DM-V-VM and I'll be adding a few more posts to the series as soon as I get it working. In the meantime, if you want to get a good education in WPF patterns that work, read through the links above.

* I'm pretty sure the title has a typo, these are still talking about DM-V-VM.

Technorati Tags: WPF

Enabling WPF Magic Using WCF - Part 3

Posted in Sql and Xml | WCF | WPF at Thursday, September 21, 2006 6:45 AM Pacific Daylight Time

In Part 1 we created a simple WPF application that demonstrated WPF's ability to automatically update bindings and in Part 2 we extended the application to use WCF by using callbacks to notify WPF of the changes. In this part we will get rid of the XML file and move our application to use a SQL Server 2005 database for storage. In doing so we will replace the file system watcher with a SQL Notification. In order to learn about SQL Notifications I would suggest this article for a good overview and this article for code examples.

The first thing we will do is create our database. To do this I used VS Database Professional which is currently at CTP5. Below are the steps to create this database in VSDP:

  1. Create a new SQL Server 2005 project called ContactData
  2. In the project properties check the box for "Enable Service Broker"
  3. Add a new table called Contact (definition shown below)

The contact table is very similar to our contact XML data:

create table [dbo].[Contact]
(
    ContactID int identity(1,1) primary key not null, 
    FirstName nvarchar(50) not null,
    LastName nvarchar(50) not null,
    Phone nvarchar(15) not null
);

In the project I also edited the Scripts\Post-Deployment\Script.PostDeployment.sql script to add in our default contacts:

insert into Contact values ('Tom', 'Jones', '800-333-1111')
insert into Contact values ('Jill', 'Smith', '800-222-1111')
insert into Contact values ('Ed', 'Baker', '877-666-1111')
insert into Contact values ('Mary', 'Johnson', '866-777-1111')

Now we just right click our database project and select "Deploy". The database should get created and our table should get created and populated. Note: if you're not using VSDP you can still manually create the database and table and enable service broker following the instructions in the first article.

Now that we have a database to connect to we need to update our app.config file for our WCF service with the connection string. Below is the updated config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
    <add name="cDB" 
       connectionString="Database=ContactData;Server=(local);
Integrated Security=SSPI;"
       providerName="System.Data.SqlClient"/>
  </connectionStrings>
  <system.serviceModel>...</system.serviceModel>
</configuration>

After we've added the connection string to the database we can reference it in our ContactProvider class as follows:

private static readonly string ConnStr = 
  ConfigurationManager.ConnectionStrings["cDB"].ConnectionString;

Now that we have a connection string we can pull the contacts from the database and return them to the client. To do this we will create a new method called GetClientsFromDb as shown below:

private List<Contact> GetContactsFromDb()
{
  List<Contact> contacts = new List<Contact>();
  using (SqlConnection conn = new SqlConnection(ConnStr))
  {
    SqlCommand cmd = new SqlCommand(
      "select ContactID, FirstName, LastName, Phone from dbo.Contact", 
      conn);
 
    conn.Open();
    IDataReader dr = cmd.ExecuteReader();
 
    while (dr.Read())
    {
      Contact c = new Contact();
      c.FirstName = dr.GetString(1);
      c.LastName = dr.GetString(2);
      c.Phone = dr.GetString(3);
      contacts.Add(c);
    }
  }
  return contacts;
}

Normally we would use something like Enterprise Library to deal with the data access, but since this is a very simple example I just used the standard SqlClient objects. All we are doing is pulling all the contacts from the database and returning them as a list of Contact objects. Notice that the t-sql is very specific with column naming and table referencing, this will be important later when we add our Sql Dependency object. At this point we could return this to the client by changing GetContacts to use this method instead of the GetContactsFromFile method. However, let's continue to move forward and add in our Sql Dependency now. Below is the updated class definition for the ContactProvider class:

namespace ContactService
{
  public class ContactProvider : IContactProvider, IDisposable
  {
    private static readonly string ConnStr = ...        
    private SqlDependency _sqlDep;
    private List<Contact> _contacts;
 
    public ContactProvider()
    {
      SqlDependency.Start(ConnStr);
    }
 
    private static List<IListChangedCallback> _callbacks = ...
 
    public List<Contact> GetContacts()
    {
      ... 
      if (_contacts == null)
      {
        _contacts = GetContactsFromDb();
      }
 
      return _contacts;
    }
 
    private List<Contact> GetContactsFromDb()
    {
      ...
      SqlCommand cmd = new SqlCommand(...);
 
      _sqlDep = new SqlDependency(cmd);
      _sqlDep.OnChange += OnListChanged;
 
      conn.Open();
      ...
    }
 
    private void OnListChanged(object sender, EventArgs e)
    {
      if (_callbacks.Count > 0)
      {
        _contacts = GetContactsFromDb();
        Action<IListChangedCallback> invoke =
          delegate(IListChangedCallback callback)
          {
            callback.OnCallback(_contacts.ToArray());
          };
        _callbacks.ForEach(invoke);
      }
    }
 
    public void Dispose()
    {
      SqlDependency.Stop(ConnStr);
    }
  }
}

I've highlighted the changed in bold, hopefully you can see them. The first thing to note is that the class now implements IDisposable. This is to enable use to call SqlDependency.Start when the class is contructed and to call SqlDependency.Stop when the class is disposed. This is done, to quote Sanchan Sahai Saxena in the article above, to "create the necessary queue, service and procedure and starts a listener to monitor the queue".

The next item to note is that when we get our initial list of contacts we are creating the dependency object using the same command. This ensures us that when any item in our list of contacts changes the dependency will be fired. We are also storing the list of contacts locally to avoid hitting the database multiple times. The dependency object's Change event is then wired to our OnListChanged event handler.

Finally we update our OnListChanged method to pull the contacts from the database and make the callback to the client with the updated list of contacts. To test the application fire up the service and then one or more of the client applications. Then open the table using SQL Server Management Studio and update/insert/delete records in the table. The results should be reflected almost instantly in the client applications. That's it!

Hopefully this has been a helpful series that demonstrates some of the cool features in both WCF and WPF (and SQL Server 2005). It has been a good learning experience for me. As we progress on our real application using some of these techniques I will try to add to this example.

Technorati Tags: WPF WCF Sql Server

Enabling WPF Magic Using WCF - Part 2

Posted in WCF | WPF at Wednesday, September 20, 2006 11:13 AM Pacific Daylight Time

In part 1 we created a very simple application that actually didn't even use WCF. The next step in the process is to migrate our ContactProvider from an in-proc class to be a WCF service. We will then use WCF callbacks to notify the application that the contact list has changed. In order to learn WCF and specifically how to use call backs I used two resources: this MSDN Magazine Article and this Rough Cuts Book, both by Juval Löwy.

The first thing to do is create a new console application and add references to System.ServiceModel and System.Runtime.Serialization. Next we will recreate both our Contact class and the ContactProvider class and interface. First, here is our new Contact class as defined in our ContactService console project:

namespace ContactService
{
  [DataContract(Namespace="ContactService")]
  public class Contact

    [DataMember]
    public string FirstName;

    [DataMember]
    public string LastName;

    [DataMember]
    public string Phone;
  }
}

The first thing you will probably notice is the DataContract/DataMember attributes. If you don't know what these are then I would suggest reading a WCF primer like the book mentioned above. The other thing is that I've changed the properties to fields and no longer implement INotifyPropertyChanged. I've switched to fields because really this is just a structure from the services point of view. The INotifyPropertyChanged will be taken care of later on. Next we create our interface as shown below:

namespace ContactService
{
  [ServiceContract]
  public interface IContactProvider
  {
    [OperationContract]
    List<Contact> GetContacts();
  }
}

This defines the WCF contract that we will be implementing to provide a list of contacts to our application. Next we need to create the ContactProvider implementation:

namespace ContactService
{
  public class ContactProvider : IContactProvider
  {
    private static readonly string Filepath = 
      ConfigurationManager.AppSettings["contacts"];

    public ContactProvider()
    {}

    public List<Contact> GetContacts() 
    { 
      using (FileStream fs = new FileStream(Filepath, FileMode.Open)) 
      { 
        DataContractSerializer dcs = 
          new DataContractSerializer(typeof(List<Contact>)); 
        return (List<Contact>)dcs.ReadObject(fs); 
      } 
    } 
  } 
}

This class looks very similar to our previous ContactProvider class. However, since this is running on the server side we don't allow the client to pass in the path to the file, we just use a value from the config file. We are also using the DataContractSerializer instead of the XmlSerializer class. This is a new serializer that is part of WCF and is more appropriate in this case because we are deserializing an object that is a DataContract. However, because we are using this class we need to add a default namespace to our XML as shown below:

<ArrayOfContact xmlns="ContactService">...</ArrayOfContact>

Now we are ready to create our host. Our host is very simple since we are using a config file to manage all the WCF settings:

namespace ContactService
{
  class Program
  {
    static void Main(string[] args)
    {
      ServiceHost host = new ServiceHost(typeof(ContactProvider));
      
      host.Open();
      Console.WriteLine("Ready to accept connections...");
      Console.ReadLine();
      host.Close();

    }
  }
}

If you run the console application you should get an error since we have not configured anything at this point. We will add an App.config file to the project and fill it up with all the settings shown below:

<?xml version="1.0" encoding="utf-8" ?>
  <configuration>
      <appSettings>
          <add key="contacts" value="c:\dev\ContactSample\contacts.xml"/>
      </appSettings>
      <system.serviceModel>
          <services>
              <service name="ContactService.ContactProvider" 
                       behaviorConfiguration="MEXGET">
                  <host>
                      <baseAddresses>
                          <add baseAddress="net.tcp://localhost:8001/"/>
                      </baseAddresses>
                  </host>
                  <endpoint
                      address="contacts"
                      binding="netTcpBinding"
                      contract="ContactService.IContactProvider" />
                  <endpoint
                      address="MEX"
                      binding="mexTcpBinding"
                      contract="IMetadataExchange" />
              </service>
          </services>
          <behaviors>
              <serviceBehaviors>
                  <behavior name="MEXGET">
                      <serviceMetadata />
                  </behavior>
              </serviceBehaviors>
          </behaviors>
      </system.serviceModel>
  </configuration>

In this file we have defined our service along with two endpoints and a behavior. The behavior enabled the metadata exchange to occur which we will use to build our client proxy. There is one endpoint for the metadata exchange interface and another for our client to connect to via TCP. At this point we should be able to start our console application and it should run. With the service running, open a command prompt in the ContactApp folder and run the following command (note: you will need to have (1) installed the Windows SDK for RC1 and (2) added the SDK bin folder to your path for this to work):

svcutil net.tcp://localhost:8001/MEX /edb /config:app.config /async /out:Contact.g.cs

This will generate two files which we will need to add to our WPF project: app.config and Contact.g.cs. Note that Contact.g.cs contains the new contact definition (I use Contact.g.cs to so that it is clear the file is generated). If you look at the definition you will notice that the generated class implements INotifyPropertyChanged. The file also contains the service contract interface and proxy class. Our next step will be to plug in these new classes to our application. First remove the Contact.cs, IContactProvider.cs, and ContactProvider.cs files from the project. Next open the ContactDataModel and add the following constructor:

public class ContactDataModel : ObservableCollection<Contact>
{
  public ContactDataModel(Contact[] contacts) : base(new List<Contact>(contacts))
  { } 

  ... 
}

We will need this constructor since our new proxy class doesn't return a generic list of contacts but an array of contacts. We could edit the generated file to change this and it would work, but I prefer to not edit generated files. Next we need to update our ContactViewModel class to use the new proxy class. In this case we will also add the IDisposable interface to our class so that we can call the Close method on the proxy. Below is the updated code for our class:

namespace ContactApp
{

    public class ContactViewModel : IDisposable
    {
        private ContactProviderClient _proxy;
        private ContactDataModel _contacts;
        private Dispatcher _dispatcher;

        public ContactViewModel()
        {

            _proxy = new ContactProviderClient();
            _dispatcher = Dispatcher.CurrentDispatcher;
            _contacts = new ContactDataModel(_proxy.GetContacts());
        }

        public ContactDataModel Contacts
        {
            get { return _contacts; }
        }

        public void Dispose()
        {
            _proxy.Close();

        }
    }
}

This is very similar to our previous ContactViewModel, but this time we are getting our list of contacts via WCF instead of loading them in-proc. You can ignore the Dispatcher for now, but we will be using it shortly. The last change we need to make before our application will work is to modify our Window1.xaml.cs file as follows:

public Window1()
{
  InitializeComponent();

  _content.Content = new ContactViewModel();

}

All we did was to remove the ContactProvider object in the constructor since the new constructor is empty. At this point you should be able to fire up the console app and then once you get the "ready" message on the console you can fire up the WPF application. You should get a list of contacts as before, but again we've removed the updating feature. So if you edit the contacts.xml file the change will not be reflected in the WPF application unless you reload it.

The next step will be to build in the notification of a change to the file into the service. When this was hosted in-proc we did this using an event. However, we are no longer in-proc so we must do things the WCF way which is a client callback. I recommend you read the MSDN article referenced above prior to continuing since this might not make sense otherwise.

The first step is to create our callback contract interface. It is important to note that this contract will be implemented by the client, not the service. Since we are reporting a change to the list of changes, our interface will pass the updated list to the client. Below is the interface:

namespace ContactService
{ 
  interface IListChangedCallback 
  { 
    [OperationContract(IsOneWay = true)] 
    void OnCallback(Contact[] contacts); 
  } 
}

Next we need to reference this contract in our original contract as a callback:

[ServiceContract(CallbackContract = typeof(IListChangedCallback))]
public interface IContactProvider
{...}

Now that we have all the proper contracts defined we can implement them in our service. Since we're still using a simple file we can just reuse our code from our previous ContactProvider (with a few changes). The first thing we need is to define the file system watcher variable and initialize it when we create our ContactProvider:

  private FileSystemWatcher _fileWatch;


  public ContactProvider()
  {
    _fileWatch = new FileSystemWatcher(
      Path.GetDirectoryName(Filepath),
      Path.GetFileName(Filepath)
      );

    _fileWatch.Changed += new FileSystemEventHandler(OnListChanged);

    _fileWatch.EnableRaisingEvents = true;
  }

When the file changes our (currently undefined) OnListChanged method will be called. The trick is that when this method is called we will need to call back to the client. Before we can call back to the client we need some kind of reference to the client's callback. In order to do this we need to grab that callback from the first call to our service (GetContacts). In order to do this we create a list to store the callbacks and we grab them during the first call using the OperationContext. I've also refactored the actual call to get the contacts out of this method for reasons that will be apparent soon. Below is our new GetContacts method and GetContactsFromFile method:

  private static List<IListChangedCallback> _callbacks = 
    new List<IListChangedCallback>();

  public List<Contact> GetContacts()
  {
     IListChangedCallback callback = 
         OperationContext.Current.GetCallbackChannel<IListChangedCallback>();

     if (_callbacks.Contains(callback) == false)
     {
         _callbacks.Add(callback);
     }

     return GetContactsFromFile();
  }  

  private List<Contact> GetContactsFromFile()
  {
     using (FileStream fs = new FileStream(Filepath, FileMode.Open))
     {
        DataContractSerializer dcs = 
            new DataContractSerializer(typeof(List<Contact>));

        return (List<Contact>)dcs.ReadObject(fs);
     }
  }

Now when the first call to GetContacts comes in we will grab the client's callback from the OperationContext which we will make use of when the file changed event is fired. Below is our OnListChanged method:

private void OnListChanged(object sender, FileSystemEventArgs e)
  {
    if (_callbacks.Count > 0)
    {
        List<Contact> contacts = GetContactsFromFile();
        Action<IListChangedCallback> invoke =
          delegate(IListChangedCallback callback)
          {
             callback.OnCallback(contacts.ToArray());
          };
        _callbacks.ForEach(invoke);
    }
  }

Of course, passing this entire list back anytime anything changes might not be the smartest move, but for this example it works. A real implementation would probably spend some time figuring out what changed and only send back the changes. Now that we've implemented everything on the server side the next step is to update the client. However, before we can do that we need to regenerate our proxy files. Start up the console application and the run the svcutil command shown above again.

The updated generated file will contain the new callback interface that we defined. The next step is to implement this interface in our ContactViewModel so that the service can call back to us. Below is the updated code with changes in bold:

namespace ContactApp
  {
      public class ContactViewModel : IContactProviderCallback, IDisposable
      {
          private ContactProviderClient _proxy;
          private ContactDataModel _contacts;
          private Dispatcher _dispatcher;
   
          public ContactViewModel()
          {
              _proxy = new ContactProviderClient(new InstanceContext(this));
              _dispatcher = Dispatcher.CurrentDispatcher;
              _contacts = new ContactDataModel(_proxy.GetContacts());
          }
   

          public ContactDataModel Contacts
          {
              get { return _contacts; }
          }
   

          public void OnCallback(Contact[] contacts)
          {
              _dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,
                      new ThreadStart(delegate
                          {
                              _contacts.Clear();
                              foreach (Contact contact in contacts)
                                  _contacts.Add(contact);
                          }));
          }
   
          public IAsyncResult BeginOnCallback(Contact[] contacts, AsyncCallback callback, object asyncState)
          {
              throw new Exception("The method or operation is not implemented.");
          }
   
          public void EndOnCallback(IAsyncResult result)
          {
              throw new Exception("The method or operation is not implemented.");
          }
   
          public void Dispose()
          {
              _proxy.Close();
          }
      }
  }

When the contact list is updated the service will call the OnCallback method and pass us the new list of contacts. That is all there is to it. Now you get to see the magic. :)

Fire up the console app, wait for the "Ready" message, and then fire up the WPF application. Now make a change to the contacts.xml file and save your changes. Magic! The changes are reflected almost instantly.

So what's next? While storing contacts in a file might work in some situations, you're probably going to use a database in the real world. In part 3 I will demonstrate how to apply the same magic using SQL Server 2005 and query notifications.

Technorati Tags: WPF WCF

Enabling WPF Magic Using WCF - Part 1

Posted in WCF | WPF at Wednesday, September 20, 2006 6:25 AM Pacific Daylight Time

One of the magical features of WPF is the way that data bindings automagically refresh when they are bound to an object that implements INotifyPropertyChanged. You can also get this same magic by binding to a collection of objects (which implement INotifyPropertyChanged) by making the collection an ObservableCollection. This means that you can build a WPF application that is bound to a list of objects that will automatically refresh itself whenever that list changes.

But how do you keep the list itself up-to-date? One example is given in Dan Crevier's excellent series on the DataModel - View - ViewModel design pattern for WPF (starts here). In part 6, Dan uses a Timer to ping the data service to see if there is new data. While this works great for examples, in real life you probably don't want to be constantly pinging to see if there is new information. Since I'm currently working on building a WPF application that will need this kind of functionality I thought I would work through how this might work out in a real application and how what this might look like using WCF (this will be in part 2).

In order to walk before we run, let's start with a very simple WPF application that reads a list of contacts from an XML file and displays them. This will let us explore the INotifyPropertyChanged and ObservableCollection magic first. So to start, here is our XML file that lists out some contacts:

<ArrayOfContact>

    <Contact>

        <FirstName>Tom</FirstName>

        <LastName>Jones</LastName>

        <Phone>888-111-2333</Phone>

    </Contact>

    <Contact>

        <FirstName>Jill</FirstName>

        <LastName>Smith</LastName>

        <Phone>800-222-4455</Phone>

    </Contact>

    <Contact>

        <FirstName>Ed</FirstName>

        <LastName>Baker</LastName>

        <Phone>877-444-4321</Phone>

    </Contact>

</ArrayOfContact>

These contacts will be read from the file and will populate our Contact class shown below:

 6 namespace ContactApp

 7 {

 8     public class Contact : INotifyPropertyChanged

 9     {

10         public event PropertyChangedEventHandler PropertyChanged;

11 

12         private string _firstName;

13 

14         public string FirstName

15         {

16             get { return _firstName; }

17             set

18             {

19                 _firstName = value;

20                 NotifyPropertyChanged("FirstName");

21             }

22         }

23 

24         private string _lastName;

25 

26         public string LastName

27         {

28             get { return _lastName; }

29             set

30             {

31                 _lastName = value;

32                 NotifyPropertyChanged("LastName");

33             }

34         }

35 

36         private string _phone;

37 

38         public string Phone

39         {

40             get { return _phone; }

41             set

42             {

43                 _phone = value;

44                 NotifyPropertyChanged("Phone");

45             }

46         }

47 

48 

49         private void NotifyPropertyChanged(string propertyName)

50         {

51 

52             if (PropertyChanged != null)

53             {

54                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

55             }

56 

57         }

58 

59     }

60 }

The list of contacts will be retrieved using a very simple interface which is defined like this:

 5 namespace ContactApp

 6 {

 7     public interface IContactProvider

 8     {

 9         List<Contact> GetContacts();

10     }

11 }

Now we can define a class that reads our XML file and returns the list of contacts by implementing our interface above:

 7 namespace ContactApp

 8 {

 9     public class ContactProvider : IContactProvider

10     {

11         private string _filepath;

12 

13         public ContactProvider(string filepath)

14         {

15             _filepath = filepath;

16         }

17 

18         public List<Contact> GetContacts()

19         {

20             using (FileStream fs = new FileStream(_filepath, FileMode.Open))

21             {

22                 XmlSerializer xs = new XmlSerializer(typeof(List<Contact>));

23                 return (List<Contact>)xs.Deserialize(fs);

24             }

25         }

26     }

27 }

At this point we need to create what Dan calls the DataModel. The DataModel wraps any code that manipulates the data and makes it accessible to WPF. For our example here the DataModel will be very simple and will be an ObservableList so that our WPF window will be able to bind to the collection and refresh when it changes. At this point our DataModel looks like the following:

 6 namespace ContactApp

 7 {

 8     public class ContactDataModel : ObservableCollection<Contact>

 9     {

10         public ContactDataModel(List<Contact> contacts) : base(contacts)

11         {}

12     }

13 }

Next we create the ViewModel. The ViewModel is what our window will bind to. It will take in an instance of a ContactProvider class and expose the collection of contacts which is our ContactDataModel. Below is what this looks like:

 6 namespace ContactApp

 7 {

 8     public class ContactViewModel

 9     {

10         private ContactProvider _provider;

11         private ContactDataModel _contacts;

12 

13         public ContactViewModel(ContactProvider provider)

14         {

15             _provider = provider;

16             _contacts = new ContactDataModel(_provider.GetContacts());

17         }

18 

19         public ContactDataModel Contacts

20         {

21             get { return _contacts; }

22         }

23     }

24 }

Now we can add the data templates to our application.xaml file to tell WPF how to format the objects we have created so far.

<Application x:Class="ContactApp.App"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:local="clr-namespace:ContactApp"

    StartupUri="Window1.xaml"

    >

    <Application.Resources>

        <DataTemplate DataType="{x:Type local:Contact}">

            <StackPanel Orientation="Horizontal">

                <TextBlock Text="{Binding LastName}" />

                <TextBlock Text=", " />

                <TextBlock Text="{Binding FirstName}" />

                <TextBlock Text=" " />

                <TextBlock Text="{Binding Phone}" />

            </StackPanel>

        </DataTemplate>

        <DataTemplate DataType="{x:Type local:ContactViewModel}">

            <ListBox Name="ContactList" ItemsSource="{Binding Contacts}" />

        </DataTemplate>

    </Application.Resources>

</Application>

Finally, we can create our Window to load bind to a ContactViewModel and display our contacts:

 1 <Window x:Class="ContactApp.Window1"

 2     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

 3     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

 4     Title="ContactApp" Height="300" Width="300"

 5     >

 6     <Grid>

 7         <ContentControl x:Name="_content" />

 8     </Grid>

 9 </Window>

And here is the code behind that does the binding:

14 namespace ContactApp

15 {

16     public partial class Window1 : System.Windows.Window

17     {

18         public Window1()

19         {

20             InitializeComponent();

21             _content.Content = new ContactViewModel(new ContactProvider(@"contacts.xml"));

22         }

23     }

24 }

So this is a very incomplete application that has a lot of holes and plenty of room for improvement. However, it does what I wanted it to do in that it loads a list of contacts from an XML file and displays them. Below is a screenshot of the application as it now stands:

 

What happens if a change is made to that XML file? At this point nothing will happen. In order to track changes to the XML file we will need to implement a file system watcher on that file and then reload the list of contacts whenever that happens. In order to implement this we will first add the following code (in bold) to the ContactProvider class:

 9 public class ContactProvider : IContactProvider

10 {

11     private string _filepath;

12     private FileSystemWatcher _fileWatch;

13 

14     public event EventHandler ListChanged;

15 

16     public ContactProvider(string filepath)

17     {

18         _filepath = filepath;

19         _fileWatch = new FileSystemWatcher(

20             Path.GetDirectoryName(_filepath), Path.GetFileName(_filepath)

21             );

22         _fileWatch.Changed += new FileSystemEventHandler(OnListChanged);

23         _fileWatch.EnableRaisingEvents = true;

24     }

25 

...

35     private void OnListChanged(object sender, FileSystemEventArgs e)

36     {

37         if (ListChanged != null)

38         {

39             ListChanged(this, EventArgs.Empty);

40         }

41     }

42 }

Additionally we will modify the ContactViewModel to reload our list when it receive a ListChanged event. This will have to be done on the UI thread so we will use the Dispatcher trick demonstrated by Dan. Below is the updated ContactViewModel:

10 public class ContactViewModel

11 {

12     private ContactProvider _provider;

13     private ContactDataModel _contacts;

14     private Dispatcher _dispatcher;

15 

16     public ContactViewModel(ContactProvider provider)

17     {

18         _dispatcher = Dispatcher.CurrentDispatcher;

19         _provider = provider;

20         _provider.ListChanged += ListChanged;

21         _contacts = new ContactDataModel(_provider.GetContacts());

22     }

23 

...

29     public void ListChanged(object sender, EventArgs e)

30     {

31         List<Contact> contacts = _provider.GetContacts();

32         _dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,

33             new ThreadStart(delegate

34                 {

35                     _contacts.Clear();

36                     foreach (Contact contact in contacts)

37                         _contacts.Add(contact);

38                 }));

39     }

40 }

That's it! Now if you run the application and edit the XML file the WPF application will update as soon as you hit save. Magic! Now in a real world application you're probably not going to be using a local file, so the next step will be to migrate our Provider to WCF. This will done in part 2 since this post is already too long...

Technorati Tags: WPF WCF

MTeoRite

Posted in Gadgets | Windows Mobile at Wednesday, September 20, 2006 2:48 AM Pacific Daylight Time

A few weeks ago I lost my SP5 SmartPhone and so I was on the market for a new SmartPhone. I had seen the HTC MTeoR but wasn't convinced it was the right phone for me. Especially after reading some of the reviews which said the phone wasn't suitable for North America. I emailed my Expansys sales rep asking about this issue and he told me that he was using the phone on TMO and everything worked great. So I took the plunge and bought the phone.

I've had it for about a week and so far I really like it. I pretty much agree with this review here which says it is the best SmartPhone yet. Yesterday I discovered a new feature: the metal case. As I got out of my car I forgot the phone was in my lap and it went flying out of the car and onto the pavement. Because of the metal case, the phone lived up to its name:

A meteorite is an extraterrestrial body that survives its impact with the Earth's surface without being destroyed.

It hit the cemet very hard but didn't even get a scratch. So I can't say if it works everywhere in North Amercia, but here in SoCal it works great (and it's very durable). :)

URGE + Beta Cycles = Lost Music

Posted in General at Thursday, September 07, 2006 10:48 AM Pacific Daylight Time

When the WMP 11 beta came out I installed it and created an URGE account. I bought some music with the account and then each time I installed a new operating system I would restore my music library. Well I've gone through a laptop upgrade and several versions of Vista (now on RC1) and it appears that I've gone over my restore limit and if I want to listen to the music then I have to buy it all again. Thanks, but no thanks.

Bye bye URGE...

Technorati Tags: URGE

Troubleshooting WCF

Posted in WCF at Thursday, September 07, 2006 4:23 AM Pacific Daylight Time

I had a problem with a WCF service that I created in that I couldn't access the Metadata Exchange (MEX) endpoint using svcutil to generate my client classes if I ran the site under a special service account. Everything else seemed to work, just the MEX was broken. If I switched the site to use the Network Service account then the MEX would work, but my service would not (since it needed to use the other credentials). I posted my question on the WCF forums and quickly got a response:

as i know,mex binding should not depend on what account host process is running under

can you please enable WCF trace(verbose mode) on service side,trace will provide more info about actual error message

So how do you enable WCF tracing? This page explains is all (note that blog belongs to the person who answered my post). Once I enabled the tracing I saw the following error inside the trace log:

at System.ServiceModel.Description.MetadataSetSerializer.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)</StackTrace><ExceptionString>System.InvalidOperationException: Unable to generate a temporary class (result=1).
error CS2001: Source file 'C:\WINDOWS\TEMP\6dad3wan.0.cs' could not be found
error CS2008: No inputs specified

Oopps! I forgot to grant access to the c:\windows\temp folder to the service account. Once I did that everything worked great!

So if you're trying to troubleshoot a WCF issue, tracing is your friend. :)

Technorati Tags: WCF

No Go on Vista RC1

Posted in General at Saturday, September 02, 2006 9:03 AM Pacific Daylight Time

Well I was very excited about the Vista RC1. I downloaded it, burned it to a DVD, and got ready to install it but instead I got:

Windows cannot be installed on this computer with the current system BIOS version. Contact your computer manufacturer for a BIOS update, install the update, and then start Windows installation again. OEM Name: TOSHIBA; OEM Model: TECRA M5; BIOS Version: v1.50 ; BIOS Date: 20060425000000.000000+000

What? I'm already running Vista. So I file a bug and here is what I get back:

Thank you for reporting this issue. This issue is By Design. The reason why is because Vista is functioning correctly by blocking the upgrade due to the older BIOS. Toshiba is supposed to be posting newer BIOSs that are Vista compatible soon.

What a pain. Now I have to wait for Toshiba before I can install Vista. It would be fine if there really was an update. There must be a way to override this behavior.

<rant>
When did MS decide that I shouldn't be making this decision?
</rant>

So now I'm stuck waiting on Toshiba which will release it whenever they feel like releasing it and in the meantime I'm running Pre-RC1. I used to being in this position when it comes to my SmartPhone, but not when it comes to my laptop.

Update: I was able to get RC1 installed. I guess the bios check only happens when you do an upgrade. So I had to back everything up and then do a fresh install which worked. I hope Toshiba comes out with the new bios soon so that I don't have to do this with each RC...

Vista RC1 Released

Posted in General at Friday, September 01, 2006 8:23 AM Pacific Daylight Time

via Neowin:

Windows Vista RC1 was just posted on Microsoft Connect. (~2:45 EST)

View: Windows Vista Blog Posting
Download: Windows Vista RC1 (Connect Users Only)

Pretty cool. I'm downloading it right now. I had heard that RC1 was going to be delayed, but obviously they got it out the door. This means that MS might actually be able to deliver this before the EOY. I really like the Pre-RC1 which I'm running on my laptop, so I expect this build to be even better...

Technorati Tags: Vista

NetFX 3.0 RC1 Released

Posted in WF | WCF | WPF at Friday, September 01, 2006 8:15 AM Pacific Daylight Time

Via Jason Zander:

NETFX 3.0 just went live on the web today, you can download it here.  NETFX 3.0 contains Windows Presentation Foundation (WPF), Windows Communication Foundation (WCF), Windows Workflow, and Windows Cardspace. 

You can find out more information about the Go Live program here.

Finally, you can also download the SDK for this release here.

The Visual Studio exetensions are not available yet, but according to Clemens they should be there soon.

Update: Expression Interactive Designer September CTP is now available [via ActiveWin]. 

Update2: "Orcas" Technology Preview for .Net 3.0 is now available [via Rob Relyea].

Technorati Tags: WPF WCF WF .NET

New Notebook Mouse

Posted in Gadgets at Friday, September 01, 2006 2:30 AM Pacific Daylight Time

Just got my new mouse from Amazon. I had a gift certificate that I had been sitting on for quite some time, so the $75 notebook mouse seemed like a good buy.

Logitech VX Revolution Cordless Laser Mouse for Notebooks
Other products by Logitech

Logitech VX Revolution Cordless Laser Mouse for Notebooks

I'm running the Pre-RC1 Vista build, so I was excited to see the following in the specs when I was ordering it:

System Requirements

PC

  • Windows® XP
  • Windows Vista™ (requires Internet connection)
  • Available USB port
  • CD-ROM drive

So after installing the mouse this morning I headed over to logitech.com to get the drivers so that the extra buttons would work. However, when I got to the download I see:

This release supports Windows XP and Windows 2000 with Service Pack 4.  Windows Vista is not currently supported by SetPoint. [Emphasis Mine]

Hmmm. Oh well. I guess they are planning on supporting Vista at some point, but still I think that is pretty misleading. Other than that the mouse seems pretty nice. It replaces my squeaky mouse which also recently developed a sticky wheel. I'd post a review but I have a feeling I'm not really using the mouse as it was meant to be used since I don't have a driver.