tags:

views:

23

answers:

1

I created an object with a simple property with a default value. I then created a user control that has a text box in it. I set the datacontext of the user control to the object.

The text box correctly shows the properties default value but I can't seem to update the property value when the user changes the text box value. I created a simple project to illustrate my code.

Thanks for the help!!

public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        private string _titleValue;

        public string TitleValue
        {
            get
            {
                return _titleValue;
            }
            set 
            {
                _titleValue = value;
                textBox1.Text = _titleValue;
            }
        }

        public static readonly DependencyProperty TitleValueProperty = DependencyProperty.Register(
           "TitleValue", typeof(string), typeof(UserControl1), new FrameworkPropertyMetadata(new PropertyChangedCallback(titleUpdated))
           );

//Don't think I should need to do this!!!
        private static void titleUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((UserControl1)d).TitleValue = (string)e.NewValue; 
        }
    }

<UserControl x:Class="WpfApplication1.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <TextBox Height="23" HorizontalAlignment="Left" Margin="94,97,0,0" Name="textBox1" VerticalAlignment="Top" Width="120"
                  Text="{Binding Path=TitleValue, Mode=TwoWay}"/>
    </Grid>
</UserControl>

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();

                var dummy = new DummyObject("This is my title.");
                userControl11.DataContext = dummy;

            }

            private void button1_Click(object sender, RoutedEventArgs e)
            {
                MessageBox.Show("The value is: " + ((DummyObject)userControl11.DataContext).Title);
            }
        }

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:WpfApplication1">
        <Grid>
            <my:UserControl1 HorizontalAlignment="Left" Margin="95,44,0,0" x:Name="userControl11" VerticalAlignment="Top" Height="191" Width="293" 
                             TitleValue="{Binding Path=Title, Mode=TwoWay}"/>
            <Button Content="Check Value" Height="23" HorizontalAlignment="Left" Margin="20,12,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
        </Grid>
    </Window>
A: 

The DataContext on your usercontrol isn't set. Specify a Name for it (I usually call mine "ThisControl") and modify the TextBox's binding to Text="{Binding ElementName=ThisControl, Path=TitleValue, Mode=TwoWay}". You can also set the DataContext explicitly, but I believe this is the preferred way.

It seems like the default DataContext should be "this", but by default, it's nothing.

[edit] You may also want to add , UpdateSourceTrigger=PropertyChanged to your binding, as by default TextBoxes' Text binding only updates when focus is lost.

JustABill
I'm not trying to be stupid (it's hard though!) but didn't I set that when in this line of code (MainWindow): var dummy = new DummyObject("This is my title."); userControl11.DataContext = dummy; Where do I set that?
Scott
I don't blame you, the initial learning curve for WPF is pretty steep. The DataContext you set is for *that instance* of the UserControl1, but what I'm talking about is the DataContext for *the class* of UserControl1, which is not set. At the top where you have d:DesignHeight="300" d:DesignWidth="300">, add "Name="ThisControl"" to it (or whatever name you prefer). Then make the modification(s) to the binding I mentioned above.
JustABill
Alright, that works. Thanks so much!!! Ok, one last question. Let's say I create another user control that contains UserControl1, let's call it UserControl2. I then drop UserControl2 on the MainWindow and set it's datacontext to the dummy object. Do I need to add a dependency property on the UserControl2? Sorry about the questions....
Scott
To be more explicit, I thought data binding works up and down the control tree. I would expect UserControl1 to still be able to bind same property and have it work bi-directionally....but it doesn't. As soon as I drop UserControl1 inside UserControl2 and then drop UserControl2 on the MainWindow binding is broken.Thanks again!
Scott
I figured it out...or at least I have it working with two layers of user control. I removed the ElementName from the binding and added UpdateSourceTrigger=PropertyChanged as you suggested. It now works and I don't know why.
Scott
The binding does work down the tree, but not in the way you think, if I'm reading this right. It applies to children *in the XAML*, so like, if you put a control inside your UserControl's Content property, that will inherit the previous DataContext. It does not migrate *into* a control, so you have to manually specify one. As for why it works with just the UpdateSourceTrigger, I'll admit I'm not really sure. (I'd appreciate it if you marked the answer as correct if it worked, though :) )
JustABill