Todd 的个人资料Sandy Valley日志列表 工具 帮助

日志


2月19日

A new blog

After much frustration with different places of post blogs about WPF and other code issues, I have decided to create a ew blogging area for my code rated topics. My new code blog is Toad's Code. On this blog I will be able to post better formatted code samples as well as links to all samples. Enjoy! 

12月18日

UIPropertyMetadata

Dependency Properties in WPF are one of the coolest new features that WPF introduces in my opinion. They give your UI much more power with much less code. Today we are going to talk about the UIPropertyMetadata of a DependencyProperty.  UIPropertyMetadata allows you to set default values as well as declare callback methods for property manipulation. In this example I have created a class called Window1 that inherits from Window. First, lets look at how the property is declared.

   1: public int MyProperty 
   2: { 
   3:     get { return (int)GetValue(MyPropertyProperty); } 
   4:     set { SetValue(MyPropertyProperty, value);} 
   5: } 

List Item 1

You will notice it looks pretty much like a normal property with the exception of the GetValue() and SetValue() calls. We are not really going to spend time on this methods. These methods are basically used to push and get the value to and from the datastore for dependant values. The declaration of the static property is what we really want to look at.

   1: public static readonly DependencyProperty MyPropertyProperty = 
   2:       DependencyProperty.Register("MyProperty", typeof(int), typeof(Window1), new UIPropertyMetadata(0, 
   3:           new PropertyChangedCallback(myPropCallBack), new CoerceValueCallback(myPropCoerceCall)));
   4:  
List Item 2

You will see the syntax of the Register method is (PropertyName, type of the property, type of object the property belongs too, and a new UIPropertyMetadata). We want to look at how this new UIPropertyMetadata is created. The UIPropertyMetadata can take 3 parameters. The first parameter is the default value. The next two parameters are the PropertyChangedCallback and the CoerceValueCallback. In a normal property if you need to manipulate the value when it is being set or get you would add your code to the get and set method of the property. When using a dependant property this is not a best practice and you will find your code does not get executed most the time. This is because the runtime will skip the actually get and set call and go directly to the registered dependency property datastore.This is when you use the Callback methods.

The CoerceValueCallback and PropertyChangedCallback are called before and after the SetValue() call. Like List Item 3.

   1: set 
   2: { 
   3:       // CoerceValueCallback(); 
   4:       SetValue(MyPropertyProperty, value); 
   5:      // PropertyChangedCallback(); 
   6: } 

List Item 3

CoerceValueCallback is called prior to the value being set and gives us a chance to manipulate the value. List item 4 is an example of the syntax of what the CoerceValueCallback method looks like. You will notice the callback takes two parameters of type DependencyObject and object. The DependencyObject that is past in represents the class object that our property belongs to. In this case our Window1 object. The second parameter of type object is our property value. The parameter that is being used is of type int so we can cast the object to a type of int and perform any manipulation.

   1: private static object myPropCoerceCall(DependencyObject obj, object value) 
   2:   { 
   3:       // perform any value manipulation here and return the value to be used 
   4:       return value; 
   5:   }

List Item 4

It is important to note that this method is private and it is static. Often when creating business objects inheritance is used heavily. If you put logic in the CoerceValueCallback static method it cannot be altered by any class that may inherit from it. This can become a pretty big problem as you build out an enterprise application. To over come this limitation we need to implement a virtual class that can be called and that will contain all our logic to manipulate the value. List Item 5 shows how we set up the CoerceValueCallback method to utilize a virtual class. List Item 6 shows how the virtual class is set up. 

   1: private static object myPropCoerceCall(DependencyObject obj, object value) 
   2:  { 
   3:      Window1 win = (Window1)obj; 
   4:      if (win != null) 
   5:      { 
   6:          value = win.myPropCoerceCall((int)value); 
   7:      } 
   8:      return value; 
   9:  } 

List Item 5

   1: protected virtual int myPropCoerceCall(int value) 
   2:     { 
   3:         if (value > 100) 
   4:             value = 100; 
   5:         return value; 
   6:     }  

List Item 6

Now any class that inherits from this class can override the behavior if they wish.

Lets turn our attention to the CallBack method now. This one is pretty straight forward. You can use this method to perform action anytime the property is updated to a new value. List Item 7 and 8 show the syntax for setting up this call using the virtual class method. One of the really nice things about using a virtual class is how it helps you deal with type casting. You will note the value of the property and its parent are passed around as objects. Going the virtual method approach allows you to create methods that have these things strongly typed.

   1: private static void myPropCallBack(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
   2:  
   3:    Window1 win = (Window1)obj; 
   4:    if (win != null) 
   5:        win.myPropCallback((int)e.OldValue, (int)e.NewValue); 
   6:   

List Item 7

   1: protected virtual void myPropCallback(int oldValue, int newValue) 
   2: { 
   3:        // You can use this callback to perform some action after the value has been set 
   4: }  

List Item 8

There are a few "Gotcha's" you need to be aware of when you use this approach. Now that we understand what this property is used for we can get deeper into this. I plan on writing a follow on post to this with that will have a  working example and point out these "Gotcha's."

10月19日

Silverlight Streaming and 1.1

I was at the Microsoft office this week and talked with Marc Schweigert who is a developer evangelist for silverlight. He was able to answer my question as to why my 1.1 silverlight app is not working when I upload to the streaming server. Silverlight streaming does not support 1.1 alpha right now.

JavaScript Intellisense ?!

If you have been working with Silverlight 1.0 I am sure you have noticed how you have to do event coding in JavaScript. Has this made you appreciated Visual Studio Intellisense even more since you do not have it for JavaScript? It sure has made me appreciate it even more. I have good news though. With Visual Studio 2008 Beta 2 you can now get a plug in that will give you JavaScript Intellisense. Now building Silverlight 1.0 application is even easier.

9月14日

Lets talk WPF Speech

One of the features of WPF that very few people talk about is the Speech capability. The ability to program your application so it can both perform text to speech as well as recognize speech has come a long way in .NET 3.0. If you are running Windows Vista you should really try out the voice recognition feature, it can actually be pretty accurate. In WPF you can create your own grammer for your application that can be recognized when your users same a key word that is part of yoru grammer. Your application can then perform certian actions based on the word that was spoken. Lets look at a simple example of how to set up your custom grammer in an application.

The frist thing I will do is declare some basic objects

SpeechRecognizer _reco = new SpeechRecognizer();
List<string> _myList = new List<string>();

The SpeechRecoginzer will be used to listen for th user to speak to the application. We will use _myList to hold the customer grammers we wish to create. Now lets populate the list of grammers we want to use. We will simply add some text strings to the List object. We then create a Choices object. The Choices objects holds a list of possible string the application will listen for. We then create a GrammerBuilder and give the grammer builder our Choices. The last thing we have to do is create the Grammer object and provide it the GrammerBuilder. That is it! Your application now has a list of custom grammers it can list for. The application however is not set up to listen for the grammer. Lets cover that next.

public Window1()
{
    InitializeComponent();
   
    _myList.Add("background red");
    _myList.Add("background blue");
    _myList.Add("background black");

    Choices myChoices = new Choices(_myList.ToArray());
    GrammarBuilder builder = new GrammarBuilder(myChoices);
    Grammar gram = new Grammar(builder);
}

Now that you have your grammer object set up it is time to tell your application you want to start listening for the user to say something. Do set this up we only need to add a few lines of code at the end of our Windows1() call. Remeber at the begining of this post I declared the _reco object as type of SpeechRecognizer. Now what we need to do is load the grammer object into the SpeechRecognizer and then enable the SpeechRecognizer.

_reco.LoadGrammar(gram);
_reco.Enabled = true;
_reco.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(_reco_SpeechRecognized);

Now that we have out SpeechRecognizer loaded with grammer a listen for speech we need to wire up and event that will get fired off when the SpeechRecognizer actually recoginzes something the user says. You can see that the event is wire up in the above line of code. Now lets look at the event handler.

You will see that the event handler for this is really simple. All we do is see what the SpeechRecognizedEventArgs results.Text property. This proerty holds the text for what the SpeechRecognizer recognized. Then all we do is perform a switch on that value and perform that action we want to perform. In this case we change the background color.

void _reco_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
{
    switch (e.Result.Text)
    {
        case "background red":
            Main.Background = Brushes.Red;
            break;
        case "background blue":
            Main.Background = Brushes.Blue;
            break;
        case "background black":
            Main.Background = Brushes.Black;
            break;
        default:
            Main.Background = Brushes.Gray;
            break;
    }

    if (e.Result.Text == "background red")
    {
        Main.Background = Brushes.Red;
    }
}

That is it! You have no just created your first application that can perform actions based on what the user says, and your user can now change their background without touching their computer! Do you want your application to welcome your user to the application? Just add the following line of code to the end of the Window1() call. I will get into this and other Speech functionality in a later post.

SpeechSynthesizer syn = new SpeechSynthesizer();
syn.SpeakAsync("Welcome to my speech application");
8月31日

Skinning parts of a WPF application

Lots of people have written about how to skin a WPF application (here is a good one). There is one part of of skinning that no one really covers though, and that is how to skin only a part of my application. What I mean by this is what if I want to built an application where a user can select skins for certain parts of the application but they cannot change the skin for the whole application. This is what I will cover in this post.

Most people that talk about skinning an application will have your replace the application resource dictionary with a new dictionary that will replace all the styles. I recently had a scenario where I wanted only a subsection of the application to be skinnable. The rest of the application I need to always keep the same look and feel. There are a few approaches to this. 1) You load all the static styles when the application loads and mark them as static resources so they never change. Then just switch out resource files for styles that change. 2) You can put all those styles in there own resource dictionary and all the styles that will change in a separate resource dictionary. What if I want to store style and resource references in a database and have those XAML strings passed to me as styles? That is what this example shows. The XAML strings in the code snippet below represent XAML resources I have stored in a database and had pasted back based on the user that is logged in.

 Default list Skin     User selected Skin

As you can see in the screenshot, there is a default datatemplate that is loaded for the list items and than there is a datatemplate (skin) for the users selected view. Below is the code that shows how to update the resource dictionary reference for a single reference type. This would allow you to store a XAML string in the database for user style settings.

private void ChangeSkin2(Object sender, RoutedEventArgs args)
{
    DataTemplate usertemplate = null;
    string xamlString = string.Empty;
    XmlReader reader = null;

    switch (SkinSelector.SelectedIndex)
    {
        case 0:
            xamlString = @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                                xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
                        <CheckBox Width='160' Height='13' Content='{Binding}'/>
            </DataTemplate>";
            
            reader = XmlReader.Create(new StringReader(xamlString));
            usertemplate = (DataTemplate)XamlReader.Load(reader);
            break;
        case 1:
            xamlString = @"<DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                                xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
                <CheckBox OpacityMask='{x:Null}'  Content='{Binding}' RenderTransformOrigin='0.5,0.5' Width='120' 
                Height='16' Background='#FFEA1B1B' BorderBrush='#FF1CB4B4' FontFamily='Broadway' 
                FontSize='16' Foreground='#FF582D11'>
                    <CheckBox.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform ScaleX='1' ScaleY='1'/>
                            <SkewTransform AngleX='31' AngleY='0'/>
                            <RotateTransform Angle='0'/>
                            <TranslateTransform X='0' Y='0'/>
                        </TransformGroup>
                    </CheckBox.RenderTransform>
                </CheckBox>
            </DataTemplate>";
            reader = XmlReader.Create(new StringReader(xamlString));
            usertemplate = (DataTemplate)XamlReader.Load(reader);
            break;
        default:
            break;
    }

    Application.Current.Resources["ListItemTemplate"] = usertemplate;

}
7月18日

Linking Code between VS 2005 projects

Ok this is not really WPF it applies to all VS.Net 2005 projects. It is a nice little bit of knowledge I just recently found out. You can actually link code file or config file (this is where I think it is most useful) between VS projects. So if it is changed it one it is changed in another.

  • In the project where you wish to add the file, right click the project name in the Solution Explorer
  • Select Add and then Existing Item...
  • In the Add Existing Item dialog, navigate to the desired file
  • Click the downward pointing arrow next to the Add button and select Add As Link.
    Once added to a project, linked files are easy to identify by the small arrow in the lower-left corner of the file icon in the Solution Explorer.
  • Code on my friends!

    7月3日

    BindingListCollectionView filtering

    In an earlier post I talked about filtering with ListCollectionView and CollectionViewSource. Now it is time to cover BindingListCollectionView. If you have ever tried to bind to a Dataset in WPF with ListCollectionView or CollectionViewSource you will know that it does not really work. For ADO.net objects you need to use BindingListCollectionView. Here is an example of how you would set up this view.

    BindingListCollectionView _mylist = null;
    
            public MyBindingListCollectionView()
            {
                InitializeComponent();
    
                // Create the data table
                DataTable table = new DataTable();
    
                DataColumn Vehicle = new DataColumn("Vehicle");
    
                table.Columns.Add(Vehicle);
    
                table.Rows.Add(new string[] { "Red Truck" });
                table.Rows.Add(new string[] { "Blue Car" });
                table.Rows.Add(new string[] { "Blue Truck" });
                table.Rows.Add(new string[] { "Red Car" });
    
                // Get the default view of the data table. The default view is a BindingListCollection
                _mylist = (BindingListCollectionView)CollectionViewSource.GetDefaultView(table);
    
                this.DataContext = _mylist;
    
            }
    
            private void FilterItems(Object sender, RoutedEventArgs args)
            {
                _mylist.CustomFilter = "Vehicle like '%" + FilterText.Text + "%'";
            }

    Notice that I set the "CustomFilter" not the "Filter" property. If you interrogate the "CanFilter" property for _myList you will get a false back. But if you look at the "CanCustomFilter" property you will get a true back. You will notice that the filter that is applied looks just like a normal filter you would apply to a DataTable.

    Here is the XAML: Notice that I created a datatemplate to display the values in the View. For this type of a collection you have to do this.

    <Window.Resources>
        <DataTemplate x:Key="MyList">
          <TextBlock Text="{Binding Path=[0]}" HorizontalAlignment="Left"/>
        </DataTemplate>
      </Window.Resources>
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
          </Grid.RowDefinitions>
          <TextBox Name="FilterText" KeyUp="FilterItems" Width="200" Height="20"/>
          <ListView Name="MyList" Grid.Row="1" ItemsSource="{Binding}" ItemTemplate="{StaticResource MyList}"/>
        </Grid>

    Here is the window you get when you run it. You will notice that as I type in the textbox the filter is fired off and the list is filtered in real time. That is all there is to filtering on a ADO.net object.

    6月11日

    WPF Web App

    There is a lot of confusion about WPF apps on the client and on the web and when you need the .Net framework installed. So I figured I would take a moment and make a post on it to help clarify. This was a point that I was confused on as well for awhile. I use to think that the WPF XBAP apps were web based and required nothing to run a WPF web app. Lets get some clarification shall we and lets start by defining the different types of WPF app setups you can have.

    WPF App Requires .Net 3.0 on client Requires Silverlight plugin Installs on client
    Desktop Yes No Yes
    Web (XBAP) Yes No No
    Silverlight (WPF/e) No Yes No

     Now lets clarify those terms.

    WPF Desktop App - This is a WPF application that is installed on a client machine via ClickOnce or an MSI. The application is installed and shows up in Add/Remove Programs.

    Web (XBAP) - This does not appear in Add/Remove programs and does not get installed on the client machine. XBAP is a ClickOnce install manifest that loads the application from a web server when the client browses to it.

    Silverlight - This is a plugin that runs inside a webpage. Webpage does not have to be WPF or ASP, it can simply be a HTML page with a Silverlight plugin (very similar to flash plugin). The Silverlight plugin must be installed on the client.

    Since XBAP is probably the lest understood application type of WPF here is a quick example of how it works. I create an example XBAP app in Visual Studio. All the app does is display "Hello World" on the screen. I build the application. In the bin folder I now I have three files. I have the .exe, .manifest and .xbap files. I now need to copy those three files to a web server. Once I do that I can browse to that website on any computer that has the .Net 3.0 framework installed and use the application. So if I go to http://localhost/WPFWeb.xbap I will see a quick download progress bar and then my application will start up. The application has not been installed on my computer and I must go to that URL everytime I want to use the application. That URL allows me to pull down the lastest .manifest and .exe file and run the application.

    Hopefully this helps to clear up confusion on WPF applications. Walt has some additional breakdown on this if you still need more information.

    5月31日

    CollectionViewSource XAML

    In an earlier blog I talked about how to filter a CollectionViewSource. This time around we are going to talk about how to create your CollectionViewSource Object in XAML and set the object up in XAML to group. This feature really comes in handy whenever you have a list you want to display and group it. You can change the group in code as well.

     

    <Window.Resources>
        
        <CollectionViewSource Source="{Binding}" x:Key="cvs">
          <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Type" />
          </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
        
      </Window.Resources>
        <Grid>
            <Grid.ColumnDefinitions>
              <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
              <RowDefinition />
            </Grid.RowDefinitions>
          <ListBox Name="MyList" Grid.Row="0" ItemsSource="{Binding Source={StaticResource cvs}}"
                    DisplayMemberPath="Name">
            <ListBox.GroupStyle>
              <x:Static Member="GroupStyle.Default" />
            </ListBox.GroupStyle>
          </ListBox>
           
        </Grid>

     

    Here is the code behind

     

    public partial class CollectionViewSource : System.Windows.Window
        {
    
            public CollectionViewSource()
            {
                InitializeComponent();
    
                Truck[] myValues = new Truck[4];
    
                myValues.SetValue(new Truck("Truck", "Red"), 0);
                myValues.SetValue(new Truck("Truck", "Blue"), 1);
                myValues.SetValue(new Truck("Car", "Blue"), 2);
                myValues.SetValue(new Truck("Car", "Red"), 3);
    
                this.DataContext = myValues;
          
            }
    
        }
    
        public class Truck
        {
            private string _type;
            private string _color;
    
            public Truck(string Type, string Color)
            {
                _type = Type;
                _color = Color;
            }
    
            public string Type
            {
                get { return _type; }
                set { _type = value; }
            }
    
    
            public string Color
            {
                get { return _color; }
                set { _color = value; }
            }
    
            public string Name
            {
                get { return string.Concat(this.Type, " ", this.Color); }
            }
        }

     

    Screenshot #1

    Screenshot #2 

    Screenshot #3

     

    sorry for the blurry pics 

     

     

    As you can see the list is now grouped by the type of car (Truck and Car. Yes I know a truck is a type of car, I just wanted a quick example). You can change

    <PropertyGroupDescription PropertyName="Type" /> So property name is Color and the list will be sorted by color. You can also do this in code. In my second screenshot I have a check box. If you click the check box it changes the grouping to be by color. The follow code allows you to do this.

     

    private void ColorSort(Object sender, RoutedEventArgs args)
            {
                CollectionViewSource csv = (CollectionViewSource)FindResource("cvs");
                csv.GroupDescriptions.Clear();
    
                if (Sort.IsChecked == true)
                {
                    PropertyGroupDescription colorGroup = new PropertyGroupDescription("Color");
    
                    csv.GroupDescriptions.Add(colorGroup);
                }
                    // Add default group back
                else
                {
                    csv.GroupDescriptions.Clear();
                    PropertyGroupDescription typeGroup = new PropertyGroupDescription("Type");
    
                    csv.GroupDescriptions.Add(typeGroup);
                }
            }

     

    Do you want more control over how the items look? This is easily done by changing just a few things in the xaml. The third screenshot from above shows a more custom look to the list. This is done by adding two resources and changing the list box binding a little. Here is what I changed. I have made the xaml I changed in the listbox bold and italic. You will notice that in the GroupItem template I bind the textblock to the "Name" path. The name is the groupdescription property name that is being grouped not the name property on my object.

     

    <DataTemplate x:Key="GroupHeader">
          <TextBlock Background="BurlyWood" Text="{Binding Path=Name}"></TextBlock>
        </DataTemplate>
    
        <DataTemplate x:Key="GroupItem">
          <TextBlock Text="{Binding Path=Name}" Margin="0,0,0,10">
            <TextBlock.RenderTransform>
              <SkewTransform CenterX="0" CenterY="0" AngleX="0" AngleY="10" />
            </TextBlock.RenderTransform>
          </TextBlock>
        </DataTemplate>
    <ListBox Name="MyList" Grid.Row="1" ItemsSource="{Binding Source={StaticResource cvs}}"
                    ItemTemplate="{StaticResource GroupItem}">
            <ListBox.GroupStyle>
              <GroupStyle HeaderTemplate="{StaticResource GroupHeader}" />
            </ListBox.GroupStyle>
          </ListBox>
    5月26日

    CollectionViewSource Filtering

    Here is the follow on to my last post about CollectionView filtering in WPF. This posts shows how to filter a CollectionViewSource object as apposed to a ListCollectionView which the last post covered. CollectionViewSource is mainly used when you want to set up grouping or sorting in XAML (Here is an example). The way you filter a CollectionViewSource in code is different than how you filter a ListCollectionView.  

            CollectionViewSource _view;
    
            public Window1()
            {
                InitializeComponent();
    
                string[] myValues = new string[] { "Red Car", "Red Truck", "Blue Car", "Yellow Truck" };
    
                _view = new CollectionViewSource();
                
                _view.Source = myValues;
    
                this.DataContext = _view;
            }
    
    
            private void FilterTrucks(Object sender, RoutedEventArgs args)
            {
                if (ShowTrucks.IsChecked == true)
                    _view.Filter += new FilterEventHandler(IsValueTruck);
                else
                {
                    // Remove the filter
                    _view.Filter -= new FilterEventHandler(IsValueTruck);
                }
            }
    
    
            public void IsValueTruck (object sender, FilterEventArgs e)
            {
                if (e.Item.ToString().Contains("Truck"))
                {
                    e.Accepted = true;
                }
                else
                {
                    e.Accepted = false;
                }
            }

    If you want see what the app looks like when the filter is used see my last post. The app works the same way.

     

    5月25日

    CollectionView Filtering

    For those of you that have worked with data collection in WPF if you have probably learned how helpful a CollectionView can be. CollectionViews let you filter, group and sort a collection of data without any requiring of the data. Setting a CollectionVIew up to filter or group data is actually pretty easy. Here is an example of how you would setup a Collection into a CollectionView to be filtered.

     ListCollectionView _view;

    public Window1()

    {

    InitializeComponent();

    string[] myValues = new string[] { "Red Car", "Red Truck", "Blue Car", "Yellow Truck" };

    _view = new ListCollectionView(myValues);

    this.DataContext = _view;

    }

    private void FilterTrucks(Object sender, RoutedEventArgs args)

    {

    if (_view.CanFilter && (ShowTrucks.IsChecked == true))

        _view.Filter = new Predicate<object>(IsValueTruck);

    else

    {

        // Remove the filter

        _view.Filter = null;

    }

    }

    public bool IsValueTruck(Object value)

    {

    return (value.ToString().Contains("Truck"));

    }

     

    You can see that when the "Show only Trucks" checkbox is check the list is automatically filtered to show only items that are trucks. You do not need to write any code that refreshes the UI this is all handled for you by the WPF binding and the ListCollectionView. You can try changing the ListCollectionView to just a CollectionView. If you do this you will see that the UI does not refresh the list when the check box is selected. This is because CollectionView itself does not handle the UI level view update. You can use ListCollectionView, CollectionViewSource or BindingListCollectionView (this type is used for binding and filtering ADO.net objects like datasets) to filter and bind to lists. We have covered ListCollectionView binding and filter. In future posts I will cover the other types as well as how to set up grouping and sorting.

    5月7日

    WPF Validation

    I recently had to build out a validation solution for a WPF project I was working on. For those of you that have not work with WPF (you are missing out J ) validation works differently. At first I was unsure about the way validation works in WPF and it seemed a little incomplete. I still believe it is incomplete, mainly because there is no built in way to do complete form validation unless you implement a custom solutions. This brings us to the point of this post. I recently wrote up an example of a few different ways to do complete form validation using WPF. I created a Validation manager that allows me to do this. The validation manager utilizes the creation of custom validation rules. You can download the whole paper and the example solution here. The paper includes validation approaches other developers have done as well.

    The validation manager that is used in this approach allows you to handle validation at the form level and allows you to have your validation logic separated from your business objects. This is one thing the other approaches do not let you have. The validation manager is also not coupled at all with the DataContext of the page so it gives you more flexibility. The IDataError approach Paul Stovell uses can be helpful but is tightly coupled with the DataContext. There is also one other very nice feature the Validation Manager I created gives you. It gives you the ability to invalidate a field on the page programmatically. Even if all the custom validation rules that are bound to in pass you can still use the Validation manager to invalidate the field and put an error message on it. This gives you great extensibility to build out a validation framework and use the validation manager to handle invalidating whatever field needs to be invalidated.

    5月6日

    Silverlight 1.1

    If you have not heard Silverlight 1.1 has hit the Alpha stage. 1.1 gives you the ability to code in C# or other .Net languages. Big news for those of you that are not a fan of trying to create WPF controls using Javascript. 1.1 will work inside Orcas and give you intelisense. Boy how I love intelisense! J

    Silverlight 1.1

    4月16日

    Shift in purpose

    As you have probably noticed I have not been writting much on this blog. I am going to try and get back on the ball. I have been working a lot with Windows Presentation Foundation as of late so I will start adding some content about that here also. Hopefully I can share some of the things I have learned and help everyone to start working with the WPF, because it is sweet!
     
    If you have not heard Microsoft annoucement Silverlight (formally known as WPF/E) today at NAB. Here is a nice MS blog highlighting it. Let me tell you I am excited to hear what #10 is going to be.