views:

607

answers:

2

I feel like I'm missing a fairly fundamental concept to WPF when it comes to databinding, but I can't seem to find the right combination of Google keywords to locate what I'm after, so maybe the SO Community can help. :)

I've got a WPF usercontrol that needs to databind to two separate objects in order to display properly. Both objects must be dynamically set from an outside source. Thus far I've simply been using the DataContext property of the form for dynamic object binding, but that only allows for one object to be referenced. I feel like this is a simple problem and that I must be missing something obvious.

My previous attempt looks something like this:

<UserControl.Resources>
    <src:Person x:Key="personSource" />
    <src:Job x:Key="jobSource" />
</UserControl.Resources>
<TextBox Text="{Binding Source={StaticResource personSource}, Path=Name" />
<TextBox Text="{Binding Source={StaticResource jobSource}, Path=Address" />

This will bind to any defaults I give the classes just fine, but If I try to dynamically set the objects in code (as I show below) I don't see any change.

Person personSource = FindResource("personSource") as Person;
personSource = externalPerson;
Job jobSource= FindResource("jobSource") as Job;
jobSource = externalJob;

What am I missing?

+4  A: 

I would probably use a CustomControl with two DependencyProperties. Then the external site that uses your custom control could bind the data that they want to that control, also by using a custom control you can template the way the control looks in different situations.

Custom control code would look something like:

public class CustomControl : Control
{
    public static readonly DependencyProperty PersonProperty =
     DependencyProperty.Register("Person", typeof(Person), typeof(CustomControl), new UIPropertyMetadata(null));
    public Person Person
    {
     get { return (Person) GetValue(PersonProperty); }
     set { SetValue(PersonProperty, value); }
    }


    public static readonly DependencyProperty JobProperty =
     DependencyProperty.Register("Job", typeof(Job), typeof(CustomControl), new UIPropertyMetadata(null));
    public Job Job
    {
     get { return (Job) GetValue(JobProperty); }
     set { SetValue(JobProperty, value); }
    }

    static CustomControl()
    {
     DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
    }
}

Generic.xaml is a file that should be created for you and could have a Style that looks something like this:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication3">


    <Style TargetType="{x:Type local:CustomControl}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomControl}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
         <StackPanel>
          <TextBox Text="{TemplateBinding Person.Name}" />
          <TextBox Text="{TemplateBinding Job.Address}" />
         </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Finally, when you go to use your control you would do something like this.

<src:CustomControl Person="{Binding Person}" Job="{Binding Job}" />
Todd White
This seems like it will work, but now I have a different problem. I don't really want to use Styles to bind these elements, but whenever I try to reference the new dependency property it tries to find it in the datacontext, not my local object. How do I explicitly reference a local property?
Toji
Can you give a bit more context of how you are now trying to do it? Maybe create a new question if this one is no longer relevant.
Todd White
Okay, I've got it solved. Both this and Ian Oakes answers in conjunction are what solved it for me, but since this one has more explicit code the answer goes to Todd.
Toji
+1  A: 

The reason your text boxes don't update is that you are binding them to a StaticResource. As the name implies these resources are static and don't post change notifications. And because Binding is a MarkupExtension and does not derive from DependencyObject you can't use a DynamicResource.

Try creating depedency properties on your control to reference the Person and Job objects.

Then set the DataContext of the UserControl to reference itself.

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Then you can use dot notation to reference the required properties.

<TextBox Text="{Binding Path=Person.Name" />
<TextBox Text="{Binding Path=Job.Address" />

Or use the source parameter

<TextBox Text="{Binding Source=Person, Path=Name" />
<TextBox Text="{Binding Source=Job, Path=Address" />
Ian Oakes