views:

227

answers:

1

I cannot understand the Silverlight documentation on data binding. I seek a very simple example.

Suppose I define a UserControl in a XAML file. The toplevel child of the UserControl is a Grid, of n columns and m rows. Within the Grid is a Rectangle. Like this:

<UserControl....
    <Grid ...>
        <Rectangle ...>

The rectangle should be displayed in a particular (row, column) within the Grid. This row/column pair changes at runtime, according to various evevnts.

I think I can use data binding for that. Can someone confirm this is a reasonable use of data binding?

I think I can do something like this:

 <Rectangle  x:Name="rect"
     Grid.Column = "{Binding ???}"
     Grid.Row = "{Binding ???}"  />

BUT, I don't know what to put for the binding.

What goes there? And, How do I validate what I put there? It seems I can put any string I like, even the full text of the Declaration of Independence, and it behaves exactly the same way. Which is to day, it does nothing. It does not work. It does not throw an exception.

I don't know what that string should be. and I don't know how to debug what I put there. There seems to be no way to know if it is correct or valid or ridiculous.

A simple example is all it would take. I don't know why the MSDN doc is so obtuse. Am I thoe only one who cannot understand things like this

In Silverlight, you can bind to the target value of any dependency property. The source property value for a data binding need not be a dependency property; it can be a property on a CLR object if certain conditions are met (see Data Binding). The source object can also be an existing dependency object referenced either by name or by a relative position in the object graph. In Silverlight, you can bind to the target value of any dependency property. The source property value for a data binding need not be a dependency property; it can be a property on a CLR object if certain conditions are met (see Data Binding). The source object can also be an existing dependency object referenced either by name or by a relative position in the object graph.

That kind of documentation makes me want to fall down and cry. Who writes that crap? And the doc page does not include a single example to show what all those words mean. Listen, English is my first language. And I consider myself a .NET developer. But I cannot make any sense what-so-ever of that paragraph. The person or committee who wrote it should be taken out back and shot. Twice.

Even outside te MSDN pages, I haven't been able to find an example that actually shows how silverlight databbinding works. There are examples in MSDN that show things like

<Binding ...who cares? ....>

But I don't know what that "" thing is. It's not in my xaml and I don't think I want it in my xaml. What I have is an actual control, and a Rectangle within it. Can I specify the Grid.Column or Grid.Row of a rectangle via a databinding?

Now, I told you that the Rectangle lives within a Grid, which is a child of a UserControl.

<UserControl....
    <Grid ...>
        <Rectangle ...>

I get a code-behind file for the UserControl, it looks like this:

public partial class MyThing : UserControl
{
    ....
}

What if I want to bind te position of the rectangle within the grid (within the usercontrol) via an int property on the UserControl. Can I do that? Can I bind the Grid.RowProperty and Grid.ColumnProperty to something ? What if X and Y are like this:

public partial class MyThing : UserControl
{
    public int X { get; set; }
    public int Y { get; set; }
    ....
}

Can I bind that to the rectangle's grid.row and grid.column? How?

Please, someone clarify and give a simple example.

+3  A: 

Each FrameworkElement has a DataContext, which (if not null) is an instance of an arbitrary data class. You're binding to a property of that DataContext.

<Rectangle Width="{Binding MyRectWidth}" x:Name="_myRect" />

Codebehind:

public class Foo
{
    public double MyRectWidth { get; set; }
}

Foo foo = new Foo();
foo.MyRectWidth = 100;
_myRect.DataContext = foo;

The notation {Binding MyRectWidth} is shorthand for {Binding Path=MyRectWidth}.

You can specify other parameters for the binding, such as an instance of an object that implements IValueConverter, to convert between the source and destination values.

The programmatic version of the XAML syntax is the Binding object:

Binding b = new Binding();
b.Path = "MyRectWidth";
_myRect.SetBinding(Rectangle.WidthProperty, b);

A FrameworkElement's DataContext is in most cases inherited from its parent. You can see how this makes editing a more complex object fairly straightforward.

<UserControl x:Class="PersonEditControl">
    <StackPanel>
        <TextBox Text="{Binding Name, Mode=TwoWay}" />
        <TextBox Text="{Binding Address, Mode=TwoWay}" />
        <TextBox Text="{Binding Phone, Mode=TwoWay}" />
    </StackPanel>
</UserControl>

(You'll notice in this case I've set another property on the Binding: Mode=TwoWay. This is necessary to propagate changes in the control back to the DataContext.)

public class Person
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
}

public partial class PersonEditControl
{
    void SetPerson(Person p)
    {
        // child controls inherit this DataContext, if they are
        // not explicitly given another:
        DataContext = p; 
    }
}

At any point in the control hierarchy, you can specify a new DataContext, and it will be inherited by children from that point downward.

Silverlight 3 introduces a new binding markup extension, ElementName, which allows you to specify another XAML element as the Binding source. I played around with giving a name to my UserControl (let's say _myControl) and then specifying {Binding Path=PropertyName, ElementName=_myControl} in a child control's property, but it didn't work.

I didn't spend much time on it and I might have missed something. At the very least, you can specify this relationship manually:

public partial class MyThing : UserControl
{
    public int X { get; set; }
    public int Y { get; set; }

    public MyThing()
    {
        InitializeComponent(); // important to call this first: loads the XAML

        _myRect.DataContext = this;
    }
}

Another important piece in this puzzle is the interface INotifyPropertyChanged. If your DataContext implements this interface, and fires the PropertyChanged event when its properties change, Bindings to those properties will pick up on the changes and propagate them to the control.

Ben M
very interesting. can you circle back and make that example fit my situation? Can I bind to a property that exists on the UserControl, which is the root parent of the Rectangle in question? ?How do I specify the datacontext for the Rectangle, in XAML? Can I (in XAML) specify that the datacontext of the Rectangle is the UserControl? or is that implicitly understood?
Cheeso
I've added some info about your situation.
Ben M
listen, thanks for your effort on this. you;ve obviously take some time to put this answer together. And how does INotifyPropertyChanged fit in ? And so I need to set DataContext=this in the UserControl, if I want to bind properties on child controls within the UserControl, to C# Properties on the UserControl class...?
Cheeso
Glad to help--I've updated again with `INotifyPropertyChanged`. And yeah, I'm pretty sure that's the only way to bind to the parent control--you could try the `ElementName` syntax; I've only tried to use it once for that situation with no luck.
Ben M