Rubio

I have a bit of trouble understanding classes in XAML. Suppose I have a business class MyData that has a property called Color (and the class implements INotifyPropertyChanged).

Code Block

<Window1 ...

xmlns:dp="clr-namespace:DataBindingTest">

<DockPanel.Resources>
<dp:MyData x:Key="myDataSource"/>
</DockPanel.Resources>


<Button x:Name="someButton"

Background="{Binding Source={StaticResource myDataSource}, Path=Color}">

</Window1>



If I've understood things correctly, the runtime will at this point create an instance of class MyData and myDataSource a "reference" to that object. This implies that the myDataSource object is part of the Window1 class and I should be able to access it through the this pointer. However, the only way to access myDataSource, as far as I've been able to figure out, is through GetBindingExpression.

Now suppose I create an instance of MyData in Window1 and want my Button Background property to bind to that.

Code Block

public partial class Window1 : System.Windows.Window
{
MyData myOtherSource = new MyData();
...
}


I can only set the binding to myOtherSource in C#.

Code Block

Binding bd = new Binding();
bd.Source = myOtherSource;
bd.Path = new PropertyPath("Color");
someButton.SetBinding(Button.BackgroundProperty, bd);


Setting the Button Background binding source to myOtherSource in XAML results in XamlParseException. Yet this is, I would think, a more realistic scenario, and it would be nice if I could define all my bindings in XAML. The business logic is likely to be in another assembly and you bind to objects, not classes, within that assembly. All examples of data binding show only binding to a class.

Am I missing something fundamental here




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Paul76

I was having a simialar problem tring to access a xaml declared resource in code - I found that you can use (in my instance resource was located in app.xaml) app.current.findresource(<resoucekey as string>)

Does this help

Paul





Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Kent Boogaart

Hi,

In your example, you are adding the "myDataSource" resource to the DockPanel's Resources collection. This does not create a corresponding member in the code behind for the Window. You might be tempted to try assigning a name to the resource:

Code Block

<dp:MyData x:Name="myData" x:Key="myData"/>


But that won't work either (and I wish I had a .NET 3.0 machine handy so I could give more info on this). You can gain access to the resource by doing a resource lookup:

Code Block

MyData myData = FindResource("myData") as MyData;


FindResource to search up the logical tree to find the resource. In your example, you actually declare the resource as belonging to the DockPanel, so you'd have to start the search from the DockPanel or from a control within the DockPanel:

Code Block

MyData myData = dockPanel.FindResource("myData") as MyData;


In your code example, you do not add the MyData instance to the Resources collection, so any attempt to FindResource or use the StaticResource / DynamicResource markup extensions won't find myData.

HTH,
Kent




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Rubio

Paul,

You're right. If I define the resource within the Windows instead of the DockPanel, I can call FindResource to get the class instance.

Code Block

MyData md = (MyData)this.FindResource("myDataSource");


So it appears an object instantiated in XAML is NOT part of the class in which it was instantiated. I guess ultimately the binding objects would be defined in a resource dictionary.

My main issues are 1) how are classes instantiated in XAML implemented (scope etc.), and 2) how can I bind to an object in XAML I need more information about how WPF is implemented internally in order to make informed decisions about my overall design.




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Rubio

Kent,

I still don't know how to bind to an object instead of to a class (in XAML).




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Kent Boogaart

Hi Rubio,

You are binding to an object. It's just that the object is stored in the resources collection rather than as a member of the Window. If you want the latter, there are again numerous ways to achieve it (as I mentioned in my previous post). Here's one way:

Code Block

<Window x:Name="_root"...>
<Label Content="{Binding MyData.SomeProperty, ElementName=_root}"/>
</Window>


This assumes you are exposing a MyData property from your Window class (possibly a dependency property, or a CLR property with INotifyPropertyChanged behavior). Another way:

Code Block

<Window DataContext="{Binding RelativeSource={RelativeSource Self}}">

<Label Content="{Binding MyData.SomeProperty}"/>

</Window>


Same applies here, except we're using the DataContext to contain the data source.

HTH,
Kent




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Paul76

With out meaning to sound dim (not much effort required in fairness), how would you differentiate between an 'object' and a 'class'





Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Kent Boogaart

An object is an instance of a class. By way of metaphor: a class is like a cookie cutter and the objects are like the cookies. You can make many cookies using the same cookie cutter. You can make many object instances of the same type (class).




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Rubio

Thanks for your replies, Kent. I appreciate it.

I haven't been very successful in describing the issue, so let me try again. I'm well aware that I'm binding to an object. Question is where is the class instantiated Coming from procedural programming background I just have trouble grasping the idea that the object (class instance) is stored in some obscure entity called the resource collection, and that I don't explicitly create the instance by calling MyData myObject = new MyData(). Instead, the runtime creates the instance because I have declared it in the XAML. (This I erroneously called "binding to a class".) I'm slightly uncomfortable with the idea that I can't fully understand what goes on in my code by just looking at the code, that's all.

So, to restate my question, how do I do the following binding in XAML
Code Block

public partial class Window1 : System.Windows.Window
{
MyData myOtherSource = new MyData();

public Window1()
{
InitializeComponent();

Binding bd = new Binding();
bd.Source = myOtherSource;
bd.Path = new PropertyPath("Color");
otherButton.SetBinding(Button.BackgroundProperty, bd);
}

}


Now the binding is to an object that is not stored in the resource collection, but in the Window1 class. I cannot, as far as I know, do the same in XAML. The following will cause a XamlParseException. Yet data binding is something I would rather do in markup. If I can't, it partly invalidates the benefit of using XAML markup.

Code Block

<Button x:Name="otherButton"
Background="{Binding Source={StaticResource myOtherSource}, Path=Color}">
Other button
</Button>



The reason I want to bind to an object that is instantiated in C# code is that I'm binding to business logic objects that are in another assembly. The objects have already been created by the business logic layer, and may well have existed long before the UI was created.

Should I bind directly to the managed objects in the business logic layer (assembly), or should I have some sort of proxy classes in the UI layer that contain a reference to the actual business objects This is part of a larger question and I'm looking for help from people who have more experience with WPF than I do. I have this gnawing feeling that there's something fundamental about WPF I'm simply not getting. I would really appreciate any insight on this.




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

neitz33a

When you say

<Window>
<Window.Resources>
</Windows.Resources>
</Window>

- whatever is between the <Window.Resources> area is assigned to the Resources property of the Window object.

So in procedural code it would look similar to this -

public class Window
{
protected Dictionary<String, Object> _resources;

public Window()
{
_resources = new Dictionary<String, Object>();
}

public Dictionary<String, Object> Resources
{
get { return _resources; }
set { _resources = value; }
}
}

When you put something in between Window.Resources, such as

<dp:MyData x:Key="myDataSource"/>

it is creating an instance of that object (i.e.) and adding it to the collection -

Resources.Add("myDataSource", new MyData());

So really, the XAML specifies exactly where the object is instantiated and referenced (there is no behind the scenes magic, it is just instantiating an object tree).

So to reference it, you can call the FindResource() method. Or, just access the collection -

MyData myData = ((MyData)this.Resources["myDataSource"]) as MyData;

Hope this helps. Remember the code above isn't exactly how Window is implemented (use reflector for that), just an illustration.




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Laurent Bugnion

Hi,

There is however a big difference between using FindResource (or, better, TryFindResource) and accessing the Resource collection of an element: The method (Try)FindResource walks the tree up to find the resource. If it doesn't find it in the element, it will try in its parent, then its parent's parent, the Window, the Application and eventually the operating system.

Using FindResource is better practice because it allows refactoring without having to modify the code-behind. You can move resources in other objects, external resource dictionaries, or even in external DLLs. See the webcast I published about creating skins for WPF.
http://www.galasoft.ch/mydotnet/articles/article-2007100601.html

When you use the StaticResource or DynamicResource markup extensions, you actually use TryFindResource in the background. So I recommend against using
MyData myData = ((MyData)this.Resources["myDataSource"]) as MyData;

HTH,
Laurent





Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Laurent Bugnion

neitz33a wrote:
MyData myData = ((MyData)this.Resources["myDataSource"]) as MyData;


Just noticed you're "double-casting".

((MyData)this.Resources["myDataSource"]);

is (almost) equivalent to

(this.Resources["myDataSource"]) as MyData;

The difference is that the first one will crash if the data cannot be casted (InvalidCastException), the second will simply return null. This makes more sense for resources.

HTH,
Laurent





Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

nightski

Laurent Bugnion wrote:
Hi,

There is however a big difference between using FindResource (or, better, TryFindResource) and accessing the Resource collection of an element: The method (Try)FindResource walks the tree up to find the resource. If it doesn't find it in the element, it will try in its parent, then its parent's parent, the Window, the Application and eventually the operating system.

Using FindResource is better practice because it allows refactoring without having to modify the code-behind. You can move resources in other objects, external resource dictionaries, or even in external DLLs. See the webcast I published about creating skins for WPF.
http://www.galasoft.ch/mydotnet/articles/article-2007100601.html

When you use the StaticResource or DynamicResource markup extensions, you actually use TryFindResource in the background. So I recommend against using
MyData myData = ((MyData)this.Resources["myDataSource"]) as MyData;

HTH,
Laurent


Very true! Accessing via the Resources collection was only for illustrative purposes on where stuff was instantiated, use the FindResource() method in production code. Also good catch on the double cast Smile It was a copy paste from some other code and I added the "as MyData" as an afterthought.




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Rubio

Thanks for your reply.

I guess the programming paradigm is so different that I have trouble changing my old way of thinking. I would have to disagree with you on a few issues, though. Think of the following.

Code Block

public partial class Window1 : System.Windows.Window
{
MyData myOtherSource = new MyData();

...

}


<Window x:Name="root" x:Class="DataBindingTest.Window1"
...
>

<Window.Resources>
<dp:MyData x:Key="myDataSource"/>
</Window.Resources>

</Window>


In both cases there's a Window class that has a "member" which is an instance of class MyData. In the first example, the Window1 class explicitly instantiates the MyData class. Within the Window1 class I can access the myOtherSource member directly. In the latter case, the same class is instantiated but it is stored in a resource collection, which is somehow tied to the Window1 class (and that is the behind the scenes magic). Within the Window1 class I can access myDataSource only through FindResource or through GetBindingExpression, not directly (as in myDataSource.Color = "Red"). The whole problem is how the C# Window1 class and the XAML Window class are tied together. Previously I could just glance through the C++ code and have an understanding of what the class represents and what it does. Now I have to piece together C# and XAML code to get the same understanding, and even then it's not complete because I don't have full understanding of how the runtime works with the XAML code. Like I said, I will have to change my way of thinking and I'm sure I'll get there eventually.

But my principal questions still remain:

1. In XAML how do I access myOtherSource
2. If I have an assembly that contains the business logic and instances of the business logic classes, can I bind directly to those objects, or do I have to create proxy classes in my UI layer

If you can answer these two questions, I'll be one happy camper.




Re: Windows Presentation Foundation (WPF) Data binding to a class vs. an object

Laurent Bugnion

Hi,

In the first case, the member is the private attribute. In the second case, the member is *not* the MyData, the member is the ResourceDictionary saved in the property "Resources" for the current window. This dictionary happens to contain an element of type MyData, but it could contain anything.

You must consider the Resources as a collection of stuff. You can save anything you like (well, as long as it is a CLR object) into them. The fact that you can use FindResource, TryFindResource, or that you can write the resources in XAML are just conveniences.

I think that people often see XAML as a kind of magic trick, but in fact there is nothing magic when you understand that XAML is just a serialization language. WPF uses it for UI, but there are other uses. Anything you express in XAML can be expressed in code-behind directly. So when you read XAML, try to understand what object will be created once it's deserialized.

This also explains why you cannot access myOtherSource from the XAML: When you serialize an object to XML, only public properties are serialized. So if you want to have access to myOtherSource from the XAML (for example in a Binding), you need to make it a public property (dependencyproperty, or "normal" property).

That you must consider the XAML front-end and the code-behind to understand a WPF element is a good point. It's nothing new to ASP.NET developers, though: This way of thinking is very much how ASPX (ASMX, etc...) pages work: Front-end, code-behind. Two files for one element. For "traditional" Windows programmers, the learning curve is steeper, that's true. Given the advantages of this approach, I still think it's worth it though :-) but still, that's a very good point.

To your questions:

1) You cannot, except if you provide a public property to access the private member.

2) Yes you can, but it's not recommended. You can bind a DependencyProperty to any CLR property, but then you will lose the automatic updates. I prefer to take another approach, using what John Gossman names the model/viewmodel/view pattern

http://blogs.msdn.com/johngossman/archive/2005/10/08/478683.aspx

In short, the idea is to provide a thin "UI data layer" between your business layer and the UI layer. There are many advantages to this approach, one of them being that it greatly facilitates the designers' work by making it easy to provide data in test mode and in design mode:

http://www.galasoft.ch/mydotnet/articles/article-2007091401.html

Also, it allows you to replace the business layer (god knows that happens...) without touching your UI. Of course, the drawback is that there is work needed to create the new layer, but it is a rather thin layer.

HTH,

Laurent