views:

69

answers:

3

I am trying to set twoway binding on a UserControl that I have created.

When I use the control in Xaml is set the DataContext like so...

<uc:MyUserControl DataContext="{Binding Path=MyObject, Mode=TwoWay}" />

My user control is defined as the following....

<UserControl x:Class="SilverlightApplication1.XText"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox x:Name="Text" Text="{Binding}"/>

    </Grid>
</UserControl>

The data is displayed correctly, however if I make I change I wanted it to update with TwoWay binding.

I have tried this below, but it errors at runtime since no Path is defined.

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox x:Name="Text" Text="{Binding Mode=TwoWay}"/>

    </Grid>
</UserControl>

Any ideas on how to get the control inside the usercontrol to twoway bind to the DataContext?

A: 

Ok I think I have come up with a way to get this to work....

First I set a public property in my UserControl's code behind...

public Binding BindingValue
{
   set { this.MyTextBox.SetBinding(TextBox.TextProperty, value); }
}

Then in XAML

<uc:MyUserControl BindingValue="{Binding Path=MyObject, Mode=TwoWay}" />
gmcalab
+1  A: 

While your above (self-answered) answer seems to fix the problem, I can't help but think this is a problem domain issue. I have a hard time thinking why you'd want to bind directly like that in the first place, especially since it gives you less control over what happens with the data.

Take the following:

<UserControl 
    x:Class="SilverlightApplication1.XText"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Name="UserControl"
    d:DesignHeight="300" 
    d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox x:Name="Text" Text="{Binding Path=Value, ElementName=UserControl, Mode=TwoWay}"/>    
    </Grid>
</UserControl>

Then in the codebehind:

public partial class XText
{
    public static DependencyProperty ValueProperty =
        DependencyProperty.Register(
            "Value",
            typeof(string),
            typeof(XText),
            new FrameworkPropertyMetadata(null)
        );

    public string Value
    {
        get { return ((string)(base.GetValue(XText.ValueProperty))); }
        set { base.SetValue(XText.ValueProperty, value); }
    }

    ...
}

Then, when you're ready to use it:

<uc:XText Value="{Binding Path=MyObject, Mode=TwoWay}" />

Yes, it's more code, but it gives you much more control over what happens with Value inside of your UserControl, and makes working with this code much much simpler in the future.

Thoughts?

-Doug

EDIT: fixed a couple typos.

Doug
Interesting approach, let me try that.
gmcalab
@Doug, one thing I noticed is randomly I get an error when adding this user control to my grid. If I am using a couple of these user controls I get an error saying "Value does not fall within expected range"...If i continue debugging I get a parser error say "UserControl already exists in the tree" So Since I named the UserControl like you did in the above, is this creating the problem? When I actually create the instance of the UserControl I am not giving it a name at all. But like you I gave it the name UserControl inside the actual Xaml for the UserControl so I could use ElementName to Bind
gmcalab
I've named all of my UserControls and never experienced that issue. When you name your UserControl, it falls only within the name scope of the control itself. Therefore, it won't have naming collisions when you have the same control multiple times on your page. I don't think the problem is with the code that I gave you, but in your implementation somewhere.
Doug
I definitely agree that naming the root name UserControl shouldn't be in the same scope when I am actually adding the control in code. But as I am debugging it, it some how is picking up that name. I am using it inside a DataTemplate and loading the control at runtime, dynamically. Any ideas?
gmcalab
A: 

I have found a solution that doesn't require you to give a name to the base control. When I defined a name for the base UserControl it was creating issues for me when I was adding multiple instances to my Grid, since they were defined as the same name.

This is a combination of my first answer and Doug's answer. Note the UserControl lacks the name property and the TextBox has no Binding declared in the XAML

XAML

<UserControl 
    x:Class="SilverlightApplication1.XText"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" 
    d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBox x:Name="MyText"/>    
    </Grid>
</UserControl>

CodeBehind

public partial class XText
{
    public XText()
    {
       InitializeComponent();
       MyText.SetBinding(TextBox.TextProperty, new Binding() 
       { 
          Source = this,  
          Path = new PropertyPath("Value"), 
          Mode = BindingMode.TwoWay
       });
    }


    public static DependencyProperty ValueProperty =
        DependencyProperty.Register(
            "Value",
            typeof(string),
            typeof(XText),
            new PropertyMetadata(null)
        );

    public string Value
    {
        get { return ((string)(GetValue(ValueProperty))); }
        set { SetValue(ValueProperty, value); }
    }

    ...
}

When you are ready to use it do the following

<uc:XText Value="{Binding Path=MyObject, Mode=TwoWay}" />
gmcalab
The MyText.SetBinding() chunk is still somewhat of a hack. I think you'll find using it is much more problem than it's worth.
Doug