0

A teammate and I were discussing different ways to create user controls in WPF. Specifically, the discussion was in context to a numeric up/down user control built from scratch. It consists of a Label for a title, a TextBox for the value, a Label for the units and 2 buttons for the up/down action. The ultimate goal is to bind to the properties exposed by this user control from screen view models.

The TextBox xaml declaration for the user control is as follows:

<TextBox x:Name="Textbox" Text="{Binding TextboxValue, FallbackValue=0}" Width="100" Height="40" TextAlignment="Left" FontSize="28" VerticalAlignment="Center"  BorderBrush="Black" BorderThickness="2"/>

The TextBoxes Text property is bound to the code-behind for the user controls view. Snippets of the relevant parts of the code-behind are shown below.

public static readonly DependencyProperty TextboxValueProperty = DependencyProperty.Register("TextboxValue",
         typeof(double), typeof(IncrementDecrementTextbox), new PropertyMetadata(12.0d, new PropertyChangedCallback(OnTextboxValueChanged)));

public IncrementDecrementTextbox()
{
    InitializeComponent();
    this.DataContext = this;
}

public double TextboxValue
{
    get
    {
        return (double)GetValue(TextboxValueProperty);
    }
    set
    {
        SetValue(TextboxValueProperty, value);
        NotifyTextboxValueUpdated();
    }
}

private static void OnTextboxValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    IncrementDecrementTextbox control = d as IncrementDecrementTextbox;
    control.OnTextboxValueChanged(e);
}

private void OnTextboxValueChanged(DependencyPropertyChangedEventArgs e)
{
    TextboxValue = Convert.ToDouble(e.NewValue);
}

public event EventHandler TextboxValueUpdated;

private void NotifyTextboxValueUpdated()
{
    TextboxValueUpdated?.Invoke(this, EventArgs.Empty);
}

The implementation of this user control is confusing to me. I don't understand why data binding is being used between the view & it's code-behind part. I would think that since the code-behind and the corresonding xaml view are essentially one in the same, that one would want to access elements declared in xaml directly from the code behind by setting the x:Name property of the element. But, I might be missing something.

Is binding between the view & the code-behind a standard practice when creating user controls? If not, is there a better way to do it?

Thanks!

GnUfTw
  • 337
  • 1
  • 4
  • 19
  • Create dependency properties in the code behind and then bind them to the view. Then you can bind to the usercontrol properties and or not if you choose. – Trevor Oct 17 '19 at 00:21
  • First and foremost: you should _never_ set your `UserControl.DataContext` property to `this`. The code _using_ the control needs to be able to set that, so that they can bind their view model properties to your control's properties. Beyond that, it's up to you how to propagate values, but a common strategy is to use bindings that specify the source with the `RelativeAncestor` markup. You could also specify the source by name, but that may again interfere with client code (i.e. if you have client code that also wants to set the name). See marked duplicates for extensive discussion on the topic. – Peter Duniho Oct 17 '19 at 01:34
  • See also https://stackoverflow.com/questions/1939345/wpf-should-a-user-control-have-its-own-viewmodel – Peter Duniho Oct 17 '19 at 01:37
  • I read chapter 18 about creating custom user controls in Pro WPF 4.5 In C# last night and that pretty much answered any question I had. Definitely don't wanna be setting DataContext to this. Binding between view & code-behind using binding is totally fine and actually necessary for binding to work for those using the user control. Using the RelativeAncestor markup in the controls view was one suggestion I saw in that chapter. – GnUfTw Oct 17 '19 at 16:53

1 Answers1

-2

I think you can do like this.

public UserControl1()
{
    InitializeComponent();
}



public string TextValue
{
    get { return (string)GetValue(TextValueProperty); }
    set { SetValue(TextValueProperty, value); }
}

// Using a DependencyProperty as the backing store for TextValue.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextValueProperty =
    DependencyProperty.RegisterAttached("TextValue", typeof(string), typeof(UserControl1), new PropertyMetadata(null, OnTextValueChange));

private static void OnTextValueChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    UserControl1 userControl = (UserControl1)d;
    string value = (string)e.NewValue;
    if (userControl == null || value == null)
        return;
    userControl.textvalue.Text = value;
}

you don't need to bind the usercontrol to its code behind.

Beben
  • 1
  • 2
  • 1
    It's true that you can accomplish the goal without data binding. But it's silly to do so. I will also point out that your suggested implementation is flawed: `d` should never be `null` (so that check is pointless) and it is not illegal to set the `Text` value to `null` (so that check disables otherwise-legal behavior). – Peter Duniho Oct 17 '19 at 01:36
  • 1
    @PeterDuniho sorry my bad, and I learn something in this comment. Thank you. – Beben Oct 17 '19 at 01:46