2

I know there are many similar questions, I have read loads of them in the past day or so, but none of the solutions seem to help me.

I have a WPF user control, that is basically a souped-up ComboBox, on which I would like to enable data binding. I followed the code shown in the accepted answer to this SO question, but the binding isn't working.

A cut-down version of the content of the user control is as follows...

<UserControl x:Class="Sample.MyComboBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <ComboBox Name="EntityTb"
              IsEditable="True" />
</UserControl>

There's obviously a lot more to it, but the rest isn't relevant to my question.

In the code-behind, I added a dependency property called Text as follows...

public static readonly DependencyProperty TextProperty
         = DependencyProperty.Register("Text", typeof(string),
  typeof(MyComboBox), new FrameworkPropertyMetadata() {
    BindsTwoWayByDefault = true,
    PropertyChangedCallback = TextChanged,
    DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
  });


private static void TextChanged(DependencyObject d,
                             DependencyPropertyChangedEventArgs e) {
  MyComboBox cmb = (MyComboBox)d;
  cmb.EntityTb.Text = e.NewValue.ToString();
}

public string Text {
  get => (string)GetValue(TextProperty);
  set => SetValue(TextProperty, value);
}

I then tried using this on a WPF window. The view model has a Customer property, which has a Name property which I want to bind to the custom control...

<controls:MyComboBox Grid.Column="1"
     Text="{Binding Customer.Name, Mode=TwoWay}" />

The Customer property is nothing more complex than...

private Customer _customer;

public Customer Customer {
  get => _customer;
  set {
    if (_customer != value) {
      _customer = value;
      RaisePropertyChanged();
    }
  }
}

...and the Customer type itself is just a plain C# class...

public partial class Customer {
  public string Name { get; set; }
}

However nothing happens. When the window loads, the customer name is not shown in the combobox, and if I type anything in there, the model is not updated.

I've done a lot of searching, and all code samples seem to look like the one above. Anyone able to tell me what I'm doing wrong?

DreamingOfSleep
  • 1,208
  • 1
  • 11
  • 23
  • Can you share the `Customer` class and most importantly the `Name` property inside it? – Bijington Mar 11 '19 at 20:25
  • @Bijington Added some more. Thanks – DreamingOfSleep Mar 11 '19 at 20:32
  • Did you assign the view model instance to the Window's DataContext? And did you make sure that you did **not** set the UserControl's DataContext? – Clemens Mar 11 '19 at 20:41
  • 1
    Also note that updating `cmb.EntityTb.Text` in a PropertyChangedCallback only works in one direction. Instead of the PropertyChangedCallback, better use a two-way binding like `` – Clemens Mar 11 '19 at 20:48
  • @Clemens That last suggestion got me somewhere. The value now comes out of the view model and is set in the combobox, but if I change the combobox, the value isn't sent back to the view model. Any ideas? We're half-way there! Thanks – DreamingOfSleep Mar 11 '19 at 21:31
  • @Clemens No, ignore that last comment, it's working fine. I had forgotten the binding when I used the user control. Please add your suggestion as an answer and I'll accept it. – DreamingOfSleep Mar 11 '19 at 21:35

1 Answers1

1

Updating cmb.EntityTb.Text in a PropertyChangedCallback only works in one direction.

Instead of that, use a two-way binding like

<ComboBox IsEditable="True"
    Text="{Binding Text, RelativeSource={RelativeSource AncestorType=UserControl}}"/>

As the ComboBox.Text property also binds two-way by default, setting Mode=TwoWay is redundant.

Clemens
  • 123,504
  • 12
  • 155
  • 268