Mar 20, 2006

When to use ObjectDataProvider

There are many ways to instantiate an object that will be used as the data source for bindings. I have seen many people create the object in code and set the DataContext of the Window to that instance, which is a good way to do this. You may have noticed that I have been adding the source object to the Window’s Resource Dictionary in most of my previous posts, which works well too. We have an ObjectDataProvider class in data binding that can also be used to instantiate your source object in XAML. I will explain in this post the differences between adding the source object directly to the resources and using ObjectDataProvider. This will hopefully give you guidance on how to evaluate your scenario and decide on the best solution.

As I describe these features, I will walk you through building a little application that allows people to type their weight on Earth and calculates their weight on Jupiter.

When adding the source object directly to the resources, the Avalon data binding engine calls the default constructor for that type. The instance is then added to a dictionary of resources, using the key specified by x:Key. Here is an example of the markup for this solution:

    <Window.Resources>
        <local:MySource x:Key="source" />
        (…)
    </Window.Resources>

As an alternative, you can add an ObjectDataProvider to the resources and use that as the source of your bindings. ObjectDataProvider is a class that wraps your source object to provide some extra functionality. I will discuss here the following distinguishing capabilities of ObjectDataProvider:

  • Passing parameters to the constructor
  • Binding to a method (which may take parameters)
  • Replacing the source object
  • Creating the source object asynchronously

Passing parameters to the constructor

When adding the source object to the resources directly, Avalon always calls the default constructor for that type. It may happen that you have no control over the source data, and the class you’re given has no default constructor. In that case, you can still create an instance in XAML by using ObjectDataProvider in the following way:

    <ObjectDataProvider ObjectType="{x:Type local:MySource}" x:Key="odp1">
        <ObjectDataProvider.ConstructorParameters>
            <system:String>Jupiter</system:String>
        </ObjectDataProvider.ConstructorParameters>
    </ObjectDataProvider>

This markup creates a new instance of MySource by calling its constructor and passing the string “Jupiter”. It also creates an instance of ObjectDataProvider, which will wrap the MySource object.

MySource has a public property called “Planet” that exposes an actual Planet object – the one whose name matches the string passed in the constructor parameter (in this case, “Jupiter”). I want to have a title Label in my application that binds to the Planet’s Name property. Binding to subproperties can be done in Avalon by using “dot notation”. The syntax for this is Path=Property.SubProperty, as you can see in the following markup:

    <Label Content="{Binding Source={StaticResource odp1}, Path=Planet.Name}" Grid.ColumnSpan="2" HorizontalAlignment="Center" FontWeight="Bold" Foreground="IndianRed" FontSize="13" Margin="5,5,5,15"/>

You may be looking at this binding statement and thinking that it makes no sense. It seems like we are binding to the Name subproperty of the Planet property of ObjectDataProvider. But I just mentioned that MySource is the one that has a Planet property, not ObjectDataProvider. The reason this markup works is that the binding engine treats ObjectDataProvider specially, by applying the Path to the source object that is being wrapped. Note that this special treatment is also used when binding to XmlDataProvider and CollectionViewSource.

Binding to a method

There is a method in MySource that takes as a parameter a person’s weight on Earth and calculates that person’s weight on the planet passed to the constructor. I want to pass some weight to this method in XAML and bind to its result. This can also be done with ObjectDataProvider:

    <ObjectDataProvider ObjectInstance="{StaticResource odp1}" MethodName="WeightOnPlanet" x:Key="odp2">
        <ObjectDataProvider.MethodParameters>
            <system:Double>95</system:Double>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>

Notice that instead of setting the ObjectType property, I set the ObjectInstance property this time. This allows us to reuse the instance of MySource that we created in the earlier ObjectDataProvider. I also set the MethodName property and pass a parameter to this method with the help of the MethodParameters property. Displaying the result returned from this method is as simple as binding to this second ObjectDataProvider:

    <Label Content="{Binding Source={StaticResource odp2}}" Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2"/>

This is a good start, but I would like to allow users to enter their own weight in a TextBox, and have the Label update to show the new result. The problem here is that I can’t place a Binding statement in the MethodParameters because this property is not a DependencyProperty; in fact, ObjectDataProvider is not even a DependencyObject. Remember that the target of a Binding has to be a DependencyProperty, although the source can be anything. Luckily, there is a way out when you want to bind a CLR property to a DP: you can switch the source with the target, placing your binding in the DP and setting the binding Mode to TwoWay (or OneWayToSource). Here is how to make a TextBox that modifies the parameter being passed to the WeightOnPlanet method:

    <Window.Resources>
        (…)
        <local:DoubleToString x:Key="doubleToString" />
        (…)
    </Window.Resources>

    (…)

    <TextBox Grid.Row="1" Grid.Column="1" Name="tb" Style="{StaticResource tbStyle}">
        <TextBox.Text>
            <Binding Source="{StaticResource odp2}" Path="MethodParameters[0]" BindsDirectlyToSource="true" UpdateSourceTrigger="PropertyChanged" Converter="{StaticResource doubleToString}">
            (…)
            </Binding>
        </TextBox.Text>
    </TextBox>

In this particular situation, because I am binding a TextBox’s Text, I don’t have to do anything for it to be Two-Way; it is already Two-Way by default. Bindings are One-Way by default for most DPs, and Two-Way in DPs that we expect will be changed by the user. This default behavior can be overriden by setting the Mode property of Binding.

I explained earlier that when binding to an ObjectDataProvider, the binding engine automatically looks at the source object being wrapped instead of the data provider. That is a problem for us in this situation, because we want to bind to the MethodParameters property of ObjectDataProvider. To get around the default behavior, we have to set the BindsDirectlyToSource property to true.

MethodParameters is an IList, and in this particular scenario we want to bind to the first element of the list, since the WeightOnPlanet method only takes one parameter. We can do this by using an indexer in the Path, just like we would in C# code.

I set the UpdateSourceTrigger to PropertyChanged so that the method is called and we get a new result every time the user types something in the TextBox. Other values for UpdateSourceTrigger are “Explicit” (which I used in my December 11 post) and “LostFocus” (the source gets updated when focus moves to another element), which is the default behavior.

If we were binding to a property of type double, the binding engine would automatically convert between the TextBox’s Text string and the double property. Because we are binding to a method, however, we need to write a converter ourselves. Without a converter, the binding would look for a method called WeightOnPlanet that takes a string as a parameter, and fail because no such method exists. If you looked at VS’s Output window, you would see a debug message saying that we were not able to find a method that takes the parameters we are passing. This is the code for the converter:

    public class DoubleToString : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null)
            {
                return value.ToString();
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string strValue = value as string;
            if (strValue != null)
            {
                double result;
                bool converted = Double.TryParse(strValue, out result);
                if (converted)
                {
                    return result;
                }
            }
            return null;
        }
    }

Some of you may be a little confused about this converter: should it be StringToDouble or DoubleToString? The Convert method is called when transfering the data from the source (double) to the target (string), and the ConvertBack method is called in the opposite direction. So we need a DoubleToString converter, and not the other way around.

What if the user types an invalid weight? They could type a negative number, or a non-numeric string, or they could even type nothing at all. If that is the case, I don’t even want to allow the binding to initiate the transfer of the value to the source. I want to build my own custom logic that will not only prevent data binding from transfering the value, but also alert the user the value is bad. This can be done with the Validation feature of data binding. I wrote a ValidationRule that checks for bad values and added it to the ValidationRules property in the following way:

    <Binding Source="{StaticResource odp2}" Path="MethodParameters[0]" BindsDirectlyToSource="true" UpdateSourceTrigger="PropertyChanged" Converter="{StaticResource doubleToString}">
        <Binding.ValidationRules>
            <local:WeightValidationRule />
        </Binding.ValidationRules>
    </Binding>

WeightValidationRule derives from ValidationRule and overrides the Validate method, where I added my custom logic:

    public class WeightValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            // Value is not a string
            string strValue = value as string;
            if (strValue == null)
            {
                // not going to happen
                return new ValidationResult(false, "Invalid Weight – Value is not a string");
            }
            // Value can not be converted to double
            double result;
            bool converted = Double.TryParse(strValue, out result);
            if (!converted)
            {
                return new ValidationResult(false, "Invalid Weight – Please type a valid number");
            }
            // Value is not between 0 and 1000
            if ((result < 0) || (result > 1000))
            {
                return new ValidationResult(false, "Invalid Weight – You’re either too light or too heavy");
            }
                return ValidationResult.ValidResult;
        }
    }

Typing an invalid value will now cause a red outline to appear around the TextBox. I would like the user to be notified of the error message I returned in the ValidationResult, though. More specifically, I would like a ToolTip to come up with the error message when the user types something wrong. This can be done all in XAML, with the help of a Style and a Trigger:

    <Style x:Key="tbStyle" TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
            </Trigger>
        </Style.Triggers>
    </Style>

Validation.HasError is an attached DependencyProperty that is true whenever at least one ValidationRule is in error. Validation.Errors is also an attached DependencyProperty that contains a list of all errors for a particular element. In this particular scenario we know that the TextBox can only have one error (since it only has one rule), so it’s OK to bind the ToolTip to the first error in this collection. “{RelativeSource Self}” simply means the source of the binding is the TextBox element itself. Notice the parenthesis notation in the Path – parenthesis should be used every time we are binding to an attached DependencyProperty. In English, “Path=(Validation.Errors)[0].ErrorContent” means we find the attached property Validation.Errors on the source element (TextBox), get the first error object (of type ValidationError) in this list and drill into the ErrorContent subproperty of that ValidationError.

You should see a ToolTip come up with an error message when you type anything other than a number between 0 and 1000 into the TextBox.

I wrote a sample (which is in the Avalon SDK), that shows a few other aspects of Validation. There is a lot more to this feature, but a more detailed explanation will have to wait until a future post.

Replacing the source object

You may have a scenario where you want to swap the current source of all your bindings with another object. If you have an object in the resource dictionary that all your bindings use as source, there is no way to swap that object with something else and have all binding update. Removing that object from the resource dictionary and adding a new one with the same x:Key will not cause your bindings to be notified.

If this is your scenario, you may consider using an ObjectDataProvider. If you swap the ObjectType, all bindings to that ObjectDataProvider will be notified that the source object changed and will be updated.

Note that if you are setting the DataContext of an element up in the tree to your source data programatically, setting it to a different object will cause all bindings to update, too.

Creating the source object asynchronously

In a nutshell, ObjectDataProvider has a property called IsAsynchronous that allows you to control whether the loading of the data happens in the same thread as your application or in a different thread. By default, ObjectDataProvider is synchronous and XmlDataProvider is asynchronous.

I am planning to talk about this in detail in one of my future posts, so stay tuned.

You could use the data source in this sample to write an Avalon application that allows the user to pick a planet and enter his or her weight, and shows the weight on that planet. It is actually very simple. I started out by writing that application, but I realized I wouldn’t get to show some of the concepts I wanted to talk about, so I tweaked it until I had all the features I wanted.

Here you can find the VS project with this sample code. This works with February CTP WPF bits.

32 Comments
  1. Anonymous

    This is really neat, Thanks.

    One question I have is, if I have a section in my UI that needs to repeat (say, a label and a textfield) and that repetition is not fixed (it could be zero to X), how does one use an ObjectDataProvider for this?

    • Bea

      If I understand your question correctly, you have a data source collection that can be of any size (0 to X) and you want to display a Label and a TextBox for each item. Is this right?

      If so, you can add your collection to the Window’s resources section (with or without using ObjectDataProvider) and bind an ItemsControl’s ItemsSource to that collection. You can then set the ItemTemplate property to a DataTemplate containing the Label and TextBox.

      See this blog post for an example.

      Did this answer your question?

  2. Anonymous

    It sure did, thank you very much!

  3. Laurent

    Hi Beatriz,

    I am testing Binding in XAML, and especially conversion of one type to the other. I thus implemented a IValueConverter, bound a TextBox.Text to a Slider.Value through the converter, and it works fine (I know it is not necessary to go through the converter for that, but I am just testing).

    However, the XAML parser delivers errors, which I think are due to the first error:
    - Assembly ” could not be found, are you missing an assembly reference (this appears where I define xmlns:local=”clr-namespace:WPFWin1″)

    I downloaded your ObjectDataProviderSample, and it executes fine, but opening the XAML file in the XAML editor delivers the exact same errors. Any idea where this comes from?

    Thanks a lot for any tip about that,
    Laurent

    • Bea

      Hi Laurent,

      Yeah, I typically see that error at start time, but it goes away when I rebuild the project. I don’t know why that happens, that is not something my teams owns. If you are really curious, you may want to post that question in the Forums.

      Bea

  4. Fernando

    Hello Beatriz,

    This comment arrives two months after your original post, so I’m not sure if you’re going to read it anyway.

    I’ve got a question.
    In the context of your example, how do I pass to the method WeightOnPlanet a parameter from an XMLDataProvider ?

    Let’s suppose the weight on Earth is not entered on a TextBox by the users. Instead, it comes from an XML file.
    For example:

    (Persons)
    (…)

    (John)
    (Age)30(/Age)
    (Height)1.79(/Height)
    (Weight)95(/Weight)
    (/John)

    (…)
    (/Persons)

    I want to pass “95″ as a parameter to the method WeightOnPlanet.
    How is it done in XAML ?

    Thank you.

    Fernando
    PS: I replaced the XML angle brackets for parenthesis so as the tags don’t get parsed by Blogger’s engine. Wrapping the block with the XML comment tag didn’t do the trick.

    • Bea

      Hi Fernando,

      What you are asking would be easy to do if we could data bind the Method Parameter, which we can’t for various reasons. In my sample, I can work around it by having a TextBox with a two-way binding. This way, I can place the binding in the TextBox’s Text (target), so that when the user types a new value, it gets updated to the MethodParameter (source).

      You can use the same technique to get the value from an XmlDataProvider, but you will need a middle man control.

      So, what do you need in your scenario? You need a property that receives the XML value and that passes it along to the method parameter. If you could have two bindings in the same DP of the intermediate control, this could be done really easily: the first Binding would have the XML as the source and would be “one way to target”. The second Binding would have the Method Parameter as the source and would be “one way to source”. But we don’t support having more than one Binding in the same DP. You can get around it though, by having two DPs in the control and making sure that when one of them changes, that change is propagated to the second one.

      In this sample, you can see I implemented a control called “Intermediate” with two DependencyProperties. The “Input” property is responsible for hooking up to the XmlDataSource (one way to target). The “Output” property is responsible for pushing that value to the method parameter (one way to source). The only extra thing I had to do was to propagate the value from the Input to the Output when the Input changes, which was done in the OnInputChanged handler.

      Do I recommend this approach? Not sure, I guess it depends on the goal of your particular app. It seems like a lot of work for something you can easily do in code. And you have to write code too, to define the class for the Intermediate control.

      If this becomes a very common request, we may consider adding an Intermediate control to the platform for this purpose. But personally I’m not yet convinced we should do it. It would take a lot of explaining and it would only be useful it very specific (uncommon) scenarios.

      Thanks,
      Bea

  5. Anonymous

    Great stuff!!
    question thu, what if I want to pass the culture argument to the converter? how would I do that from XAML?
    Do you recommend using the converter for localisation?

    • Bea

      Regarding the localization question:

      There is a “ConverterCulture” property on Binding that you can set to the desired culture. This is really easy to do from XAML – I uploaded a simple app
      here that shows how to do this.

      Do I recommend this approach? No, not really. I know that the localization team has been working pretty hard on a document with guidelines and best practices on localization. I don’t think this document is public yet, but make sure you check the SDK on our next release.

      Hope this helps.
      Bea

  6. Anonymous

    How would you go about updating the dataset if you are using that technique? If i call the data access layer directly, the data will be persisted, but the ui wont update unless i reload the data. Is there any way to call a method on the datasource and pass in the value of a textbox?

  7. Bea

    Regarding your question on updating the DataSet:

    You asked ” Is there any way to call a method on the datasource and pass in the value of a textbox? “. This is exactly what I am showing in this post. I call the method WeightOnPlanet and pass the value in the TextBox as a parameter. When the value in the TextBox changes, the method is called and we get a new result.

    You ask how we can update the DataSet with this technique. Do you mean updating the DataSet to the database or update the in-memory DataSet?

    If you are talking about the in-memory DataSet, are you assuming we’re storing the weight on Jupiter in our source (which I’m not in this sample, but let’s assume we are)? We are already binding the weight on Jupiter to the result of the method (one way to target), and we can’t add another binding directly that causes the source to be updated (one way to source). We can, however, use the workaround that I explained on my reply to Fernando on this blog post, with the help of an “Intermediate” custom control.

    If you are talking about updating the data to the database, you should use whatever technique you use with WinForms (or the technology you use today). The data should be persisted when you are done with the changes in the UI.

    Let me know if I didn’t reply to your question. And if that’s the case, could you please include more details?

    Thanks,
    Bea

  8. Gonzalo

    Hi Beatriz, I wondering what can I pass another value to the method in Xaml? I saw your blog and you had write this (with tags):

    ObjectDataProvider ObjectInstance=”{StaticResource odp1}” MethodName=”WeightOnPlanet” x:Key=”odp2″
    ObjectDataProvider.MethodParameters
    system:Double 95 system:Double
    /ObjectDataProvider.MethodParameters
    /ObjectDataProvider

    If I want to pass the parameter data (95) from a DataContent and use it in a DataTemplate, How can I do that?

    Thanks a lot, Gonzalo.

    • Bea

      Hi Gonzalo,

      You mentioned your data (95) comes from a DataContent, but I’m not aware of a property with that name in Avalon. Do you mean DataContext, or maybe Content?

      The technique I show in this blog post is used to pass data as a parameter to a method in your data source. You ask how to pass data into a DataTemplate. These two scenarios are quite different.

      When you set the Content property of a ContentControl (for example, Button), and define a DataTemplate for that control, the data in the Content property is passed to the DataTemplate automatically. To be more precise, we set the DataContext of one of the generated elements to the data in the Content property. This element is higher in the tree than the elements in the DataTemplate. This is why we don’t usually set the Source property of a Binding inside a DataTemplate: the Binding inherits its source from DataContext set up in the tree.

      Did this reply to your question? Let me know!

      Bea

  9. Christian

    Hi Beatriz,

    Been reading your informative pages trying to find an answer for my problem.

    I have a multilingual application in which a TextBlock displays it’s text based on its key and a Translator.

    The translator class contains a Translate method with one parameter, something like:

    Static string Translate(string key)
    …do something
    return TranlatedString;

    I tried binding the TextBlock:

    [TextBlock Text=”"{Binding Source={StaticResource Translator}}…

    and searched for a way to pass the key of my TextBlock.

    I could do so by defining an ObjectDataProvider containing the key of the TextBlock for every TextBlock in my Application using the technique you’ve shown, but that seems the wrong way to go.

    So, is there another option I’ve overlooked?

    Thanks for you’re help

    Christian

    • Bea

      Hi Christian,

      I can’t think of a way to do this all in XAML. The only way to call a method of a binding source in XAML is using ObjectDataProvider the way I show in this post and you can not bind the ConverterParameter of ObjectDataProvider.

      I think that the only way to do this is to compromise and write a little code (other than having one ODP per TextBlock, which is overkill in my opinion.) I wrote a little app that contains a Converter which returns the correct translated string based on the parameter it receives (which is the key.) Here is the only line inside the Convert method of my Converter:

      return Translator.Translate(parameter as string);

      And here is how you could consume this Converter in the TextBlock’s Text:

      Text=”{Binding Source={x:Null}, Converter={StaticResource conv}, ConverterParameter=en-US}”

      This way, you can have several TextBlocks with different string parameters and only one Converter, so it scales pretty well.

      Notice that the source of my binding is null. If your method was not static, you could set the source of the binding to an instance of Translator (simply add it to the resources.) But because the Translate method is static, you don’t really need a source, you just need a way to execute some code.

      This is a little hacky. Binding to null just so that a Converter is called is kinda weird, and there are probably more elegant solutions. But it works :)

      Here is the solution where I implemented what I explained. If you find a better solution I would like to hear about it.

      Bea

  10. Hugo Soares

    Hi Beatriz!
    I would like to know if in the future there will be some kind of error provider (like the one we used in winForms) that will allow to validate user input. Using Validation Rule is not very useful…
    Thank’s!

    • Bea

      Hi Hugo,
      I can never promise a feature since so many unpredictable events affect what we ship. However, I can tell you that we are currently planning the features for out next version, and it’s on our list to make improvements to Validation. We get that feedback a lot. We are completely aware of the fact that we have some limitations in our current Validation design, and we are very commited to improving on those for the next version.

      Thanks,
      Bea

  11. Laurent

    Hi Bea,

    I know this article is quite old, but it helped me again. Maybe you’ll read this.

    Any idea why the bjectDataProvider.ConstructorParameters> doesn’t appear in Intellisense when I try to use the ObjectDataProvider tag in XAML? The functionality works, but Intellisense doesn’t recognize the tag.

    Thanks,
    Laurent

    • Bea

      Hi Laurent,

      VS support for WPF is owned by a different team, and they haven’t shipped yet, they’re still in beta. So it is likely that you will find a few issues with that until they release their final version.

      Thanks!
      Bea

  12. Anonymous

    We are using a ListCollectionView that contains a list of objects that have derived from ObjectDataProvider. We are taking advantage of the fact that setting the DataContext (on another ascociated panel ) to the ListCollectionView implicitly sets the DataContext of that panel to the ‘current’ selected item displayed in the list. Also we are setting the DisplayMemberPath of a ListBox to one of the properties that is exposed by the ObjectInstance property of the ObjectDataProvider. Notice we do not have to mention the fully qualified root to the property as it is infered as part of the ObjectDataProvider mechanism. This results in the desired text being displayed in the listbox.

    However, and this is the source of our problem to which I would welcome any assistance, we can not bind directly to the properties we require to display in the panel without fully qualifying the property name (for instance ObjectInstance.PropertyName)

    Unfortunately this defeats any benefits of using ObjectDataProvider as a wrapper for our own DataObjects.

    Is there sometjing we should be doing?

    • Bea

      Hi,

      Unfortunately I was not able to repro what you described. I set my panel’s DataContext to an ObjectDataProvider instance, and tried to data bing a ListBox and a TextBlock within the panel to the data wrapped by the ODP. I am not required to fully qualify the property path in the TextBlock, I can simply use the property name of my source. You can find my attempt to repro your scenario here.

      Maybe I didn’t fully understand your scenario, or maybe I am missing some detail. If that’s the case, it would be great if you could tell me how your app differs from mine, or send me a code sample.

      Thanks,
      Bea

  13. Slugman

    Hi Bea,

    Thanks for the information – your blog is a real find for those of us increasing our knowledge of WPF.

    One thing I am having a problem with is understanding best practice in implementing data-binding. There seems to be more ways than ever of achieving data-binding between different source types and the UI, and a vast amount of differing advice on the best ways of doing it. Using your ObjectDataProivder as one example, you even use it to call a method. Being a bit old school, I don’t like to see UI code referencing specific object types, let alone references to methods – because to me, that defines a specific coupling between data and view. My company is currently completing a large non-WPF SmartClientFactory project, and in this we manage data-binding by having the Presenter of a View tell the view what object to use as a data-source and what property on that object to bind to. By doing this, we can completely change the source object in the Presenter without having to even opening the View meaning our classes are easily manageable and loosely coupled.

    So bearing in mind there’s so many examples of XAML with references to Property names, Object types and the like, can you please let me know what I am missing here? What advantage do I gain by adding property names into my XAML as opposed to keeping them out of the UI and strictly in a View-Model or Presenter?

    Thanks,
    Slugman

    • Bea

      Hi Slugman,

      Your points are all very valid. The more separation there is between UI and data, the more scalable the application will be long term, there’s no doubt about it.

      The Model-View-ViewModel pattern is one of the most used techniques for achieving this separation in WPF. Very briefly, in this pattern the Model is your data, and the View is your UI (XAML and maybe a bit of code). The ViewModel is a layer introduced between the View and the Model that exposes the Model in a way that is more easily consumed by the View. It’s ok for the ViewModel to use certain types introduced by WPF, and to make certain assumptions about the UI. The ViewModel is usually a pretty thin layer compared to the Model, still allowing easy portability to future (or alternative) technologies. So, in this pattern, your UI bindings communicate with the ViewModel and not with the Model.

      These ideas were introduced by John Gossman in his blog a while ago. John was an architect in Blend at the time, so his post explains in a high-level how Blend was designed. I’m also a big fan of Dan Crevier’s approach to this pattern (he was an architect in Max, another product that was heavily using WPF). Dan uses a slightly different terminology compared to John, but the basic idea is the same. I especially like how Dan deals with commanding in his approach.

      You ask why we added a feature that allows binding to methods. Well, as most of the features we add, this was introduced based on customer feedback, in the context of binding to web services. Users felt that creating a simple application that binds to a web service’s method is a common enough scenario that shouldn’t require code behind.

      In general, the main advantage of allowing a certain scenario to be created using XAML only is the fact that it becomes toolable. This is a huge advantage – it opens scenarios to designers and less advanced developers, and speeds up development for advanced developers.

      My guess is that a large application that is following M-V-VM or any other pattern that allows clean separation between UI and data will likely not use binding to methods as a common practice. Also, any property and object names that it refers to in XAML will be referring to the ViewModel, and not the Model itself.

      Thanks for your great comment.

      Bea

  14. Sriwantha Sri Aravinda Attanayake

    Great article indeed. I like the way you presented this. Keep it up! One more question where is the other asynchronous data binding part?
    Sriwantha Sri Aravinda Attanayake

    • Bea

      Hi Sriwantha,

      I wrote about the two types of asynchronous binding in the following post: http://www.zagstudio.com/blog/448 (so old I almost forgot I had written about it)

      Bea

  15. Rune Baess

    Works perfectly in WPF 4.0 (beta 2) as well, thx.

    • Rune Baess

      Woops, I was a bit hasty .. the example works perfectly as long you compile it for the 3.5 framework (in VS 2010).
      But if you convert it to WPF 4.0 project the method WeightOnPlanet on ObjectDataProvider is nolonger invoked on odp2 when you edit the textbox.
      I have tried to find any new Attributes on either the Binding or the ObjectDataProvider – but nothing has worked out so far …
      Are there possibly a new way of doing this in WPF 4.0 ?

      • Bea

        Hi Rune,

        Yeah, I can repro what you describe (by comparing the VS 2008 and VS 2010 versions of this project).

        The error message I get in 2010 is:

        System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=MethodParameters[0]; DataItem=’ObjectDataProvider’ (HashCode=40998886); target element is ‘TextBox’ (Name=’tb’); target property is ‘Text’ (type ‘String’) ArgumentException:’System.ArgumentException: Object of type ‘MS.Internal.Data.PropertyPathWorker+IListIndexerArg’ cannot be converted to type ‘System.Int32′.
        at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
        at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
        at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
        at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
        at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
        at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
        at MS.Internal.Data.PropertyPathWorker.SetValue(Object item, Object value)
        at MS.Internal.Data.ClrBindingWorker.UpdateValue(Object value)
        at System.Windows.Data.BindingExpression.UpdateSource(Object value)’

        WPF 4.0 is supposed to be backwards compatible and shouldn’t break apps written in 3.5. So this may be a bug in 4.0.

        Thanks,
        Bea

        • simon

          Has anyone found a workaround for this ?

  16. Lina Manjarres

    Thanks Bea for this post and other post you have in binding.
    I have one problem. I need to bind a DataGrid to vallidate if the data is loaded is not outbound. There are several columns that have to evaluate. The problem is, that I need the value of a textbox.text in the XAML. I need it, for evaluation porpuses.
    I have the validation working with IValueConverter. It change the color of the cell, after evaluating the cell that is outbound.
    However, I haven’t being able to pass the textbox value. I have tried using ConverterParameter, but I only get the name I have in the ConverterParameter, instead of its value.
    Is there a way I can do this. I have been tring to solve this for a week, and I am realy kind of desperate.
    Thanks a lot for your time!!
    Lina

    • Bea

      Hi Lina,

      I’m glad you found an answer. Sorry I couldn’t get to your question earlier.

      Bea

Comments are closed.