Search code examples
c#wpfuser-controlsdependency-propertiesinotifypropertychanged

Data binding to a UserControl in WPF - cant get Value back


I have a UserControl where I want to make DataBinding happen. I just cant get the Input back to the Binding.

UserControl:

<UserControl x:Class="WPFLibrary.UserControls.LabeledTextBox"
             x:Name="root" ... >
    <StackPanel  Orientation="Horizontal" Width="270" Height="30">
        <Label Content="LabelNotDef" Width="100" Name="BaseLabel" 
               HorizontalAlignment="Left" HorizontalContentAlignment="Left" VerticalContentAlignment="Top" />
        <TextBox Margin="0,0,20,0" Name="BaseTextBox" Width="150" Height="25" VerticalContentAlignment="Center" 
                 Text="{Binding ElementName=root, Path=Text2, UpdateSourceTrigger=PropertyChanged}" />
    </StackPanel>
</UserControl>

Code Behind of UserControl:

public partial class LabeledTextBox : UserControl, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public static DependencyProperty TextProperty = DependencyProperty.Register("Text2", typeof(string), typeof(EffLabeledTextBox),
                                                                                 new PropertyMetadata(string.Empty, OnTextPropertyChanged));

    [Browsable(true)]
    public string Text2
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    private static void OnTextPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        EffLabeledTextBox myUserControl = dependencyObject as EffLabeledTextBox;
        myUserControl.OnPropertyChanged("Text2");
        myUserControl.OnTextPropertyChanged(e);
    }
    private void OnTextPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
        BaseTextBox.Text = Text2;
    }

    public LabeledTextBox()
    {
        InitializeComponent();
    }
}

Implementation in another UserControl:

<uCon:LabeledTextBox x:Name="Toastbread" Tabelle="artikel" Feld="nr" Text2="{Binding _strNR, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

CodeBehind:

public partial class ArtikelSearch : UserControl
{
    ArtikelSearchVM objVM;

    public ArtikelSearch()
    {
        InitializeComponent();
        objVM = new ArtikelSearchVM();
        this.DataContext = objVM;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string a23 = Toastbread.Text2;
        string a24 = Toastbread.BaseTextBox.Text;
        System.Diagnostics.Debugger.Break();
        objVM.Suche();
    }
}

The PropertyChanged is triggered when i enter something in the Textfield. If i check Toastbread.Text2 i get the Value. If i check Toastbread.BaseTextBox.Text i get the Value. But if i check objVM._strNR i only get null.

When i set a value manually on objVM._strNR on the Constructor of ArtikelSearchVM it is in the box but i also dont get the modified value back from the Textbox.


Solution

  • You do no need to implement INotifyPropertyChanged in a UserControl. This is all you need:

    public partial class LabelTextBox : UserControl
    {
        public LabelTextBox()
        {
            InitializeComponent();
        }
    
        public static DependencyProperty TextProperty = DependencyProperty.Register(
            nameof(Text), typeof(string), typeof(LabelTextBox));
    
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
    }
    

    with a XAML like this:

    <UserControl ...>
        ...
        <TextBox Text="{Binding RelativeSource={RelativeSource AncestorType=UserControl},
                        Path=Text, UpdateSourceTrigger=PropertyChanged}" .../>
        ...
    </UserControl>
    

    You may also consider to make the Text property bind two-way by default:

    public static DependencyProperty TextProperty = DependencyProperty.Register(
        nameof(Text), typeof(string), typeof(LabelTextBox),
        new FrameworkPropertyMetadata(string.Empty,
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));