20

I created a Dependency Property in the usercontrol, but however changes in the usercontrol was NOT notified to the Viewmodel

Usercontrol

<UserControl x:Class="DPsample.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 x:Name="txtName"></TextBox>
</Grid>

UserControl.cs

/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
    public UserControl1()
    {
        InitializeComponent();
    }

    #region SampleProperty 

    public static readonly DependencyProperty SamplePropertyProperty
                                            = DependencyProperty.Register("SampleProperty", 
                                            typeof(string), 
                                            typeof(UserControl1), 
                                            new PropertyMetadata(OnSamplePropertyChanged));


    public string SampleProperty
    {
        get { return (string)GetValue(SamplePropertyProperty); }
        set { SetValue(SamplePropertyProperty, value); }
    }


    static void OnSamplePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        (obj as UserControl1).OnSamplePropertyChanged(e);
    }
    private void OnSamplePropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        string SamplePropertyNewValue = (string)e.NewValue;

        txtName.Text = SamplePropertyNewValue;
    }

    #endregion
}

MainWindow

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:DPsample" x:Class="DPsample.MainWindow"
    Title="MainWindow" Height="350" Width="525">
<Grid>

    <local:UserControl1 SampleProperty="{Binding SampleText,Mode=TwoWay}" HorizontalAlignment="Left" Margin="76,89,0,0" VerticalAlignment="Top" Width="99"/>
    <Button Content="Show" HorizontalAlignment="Left" Margin="76,125,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>

</Grid>

MainWindow.cs

 public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new MainViewModel();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var item = this.DataContext as MainViewModel;
        MessageBox.Show(item.SampleText.ToString());
    }

MainViewModel.cs

public class MainViewModel : NotifyViewModelBase
{
    public MainViewModel()
    {
        this.SampleText = "test";           
    }

    private string _sampleText;
    public string SampleText
    {
        get { return _sampleText; }
        set { _sampleText = value; OnPropertyChanged("SampleText"); }
    }
}
Spen D
  • 4,225
  • 9
  • 39
  • 47
  • You haven't coded anything that passes changes of the `TextBox.Text` property to `SampleProperty`. You should also use a binding there, with `RelativeSource={RelativeSource AncestorType=UserControl}`. – Clemens Sep 23 '14 at 07:16
  • @Clemens do i need to use the viewmodel for the usercontrol? – Spen D Sep 23 '14 at 07:23
  • Not in this case. However, the UserControl might as well directly bind to your view model's `SampleText` property. Then there would be no need at all for `SampleProperty`. – Clemens Sep 23 '14 at 07:28

2 Answers2

62

Bind the TextBox.Text property in the UserControl to its SampleProperty like this:

<TextBox Text="{Binding SampleProperty,
                RelativeSource={RelativeSource AncestorType=UserControl}}"/>

Now you could simply remove your OnSamplePropertyChanged callback.


You might also register SampleProperty to bind two-way by default like this:

public static readonly DependencyProperty
    SamplePropertyProperty = DependencyProperty.Register(
        "SampleProperty", typeof(string), typeof(UserControl1),
        new FrameworkPropertyMetadata(
            null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • 11
    Can't believe I've read so many tutorials and examples on custom UserControls and DependencyProperties and not one mentions the FrameworkPropertyMetadata that solves passing the value back to the model. Great job man! – Diogo Mendonça Apr 05 '16 at 11:14
4

An alternative way to do this is an ElementName Binding. First assign the x:Name attribute to the UserControl (for example x:Name="MyUC"), then change the binding to:

<TextBox Text="{Binding ElementName=MyUC, Path=SampleProperty}"/>
Clemens
  • 123,504
  • 12
  • 155
  • 268
Dabbas
  • 3,112
  • 7
  • 42
  • 75