views:

486

answers:

2

I'm trying to create a reusable UserControl in WPF that has a Label and a TextBox. I want to add properties to my UserControl to bubble up the Text fields of both child controls up to the parent for easy binding. I read that I need to a little bit of hocus pocus by adding owners to DependencyProperties. Here is my code now. It seems close but not quite right. Any ideas?

Here is the Xaml:

<UserControl x:Class="MAAD.AircraftExit.Visual.LabelTextBox"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="20" Width="300">
    <DockPanel>
     <TextBlock Text="{Binding Path=Label, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" DockPanel.Dock="Left" TextAlignment="Right" Width="122" />
     <TextBlock Text=": " DockPanel.Dock="Left"/>
     <TextBox Text="{Binding Path=Text, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
    </DockPanel>
</UserControl>

And the code behind:

public partial class LabelTextBox : UserControl
{
 public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabelTextBox));
 public string Label
 {
  get { return (string)GetValue(LabelProperty); }
  set { SetValue(LabelProperty, value); }
 }

 public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(LabelTextBox));
 public string Text
 {
  get { return (string)GetValue(TextProperty); }
  set { SetValue(LabelTextBox.TextProperty, value); }
 }

 public LabelTextBox()
 {
  InitializeComponent();

  ClearValue(HeightProperty);
  ClearValue(WidthProperty);
 }
}

Edit: Here is the final working code. I switched over to relative source binding.

A: 

I haven't looked into exactly why your implementation isn't working, but I don't really understand why you're doing it that way. Why not just define the dependency properties you need on the UserControl and then bind to them?

public static readonly DependencyProperty LabelTextProperty = ...;

And then in your XAML:

<Label Content="{Binding LabelText}"/>

HTH, Kent

Kent Boogaart
+1  A: 

Binding is really the way to go:

XAML:

<UserControl x:Class="testapp.LabelTextBox "
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" x:Name="This">
<DockPanel>
 <TextBlock DockPanel.Dock="Left" TextAlignment="Right" Width="70" Name="label" Text="{Binding Label, ElementName=This}"  />
 <TextBlock Text=": " DockPanel.Dock="Left" />
 <TextBox Name="textBox" Text="{Binding Text, ElementName=This}" />
</DockPanel>

Code Behind:

    public partial class LabelTextBox : UserControl
{
 public LabelTextBox()
 {
  InitializeComponent();
  Label = "Label";
  Text = "Text";
 }
 public static readonly DependencyProperty LabelProperty = DependencyProperty.Register("Label", typeof(string), typeof(LabelTextBox), new FrameworkPropertyMetadata(LabelPropertyChangedCallback));
 private static void LabelPropertyChangedCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
 {
 }
 public string Label
 {
  get { return (string) GetValue(LabelProperty); }
  set { SetValue(LabelProperty, value); }
 }

 public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(LabelTextBox), new FrameworkPropertyMetadata(TextPropertyChangedCallback));
 private static void TextPropertyChangedCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
 {
 }
 public string Text
 {
  get { return (string) GetValue(TextProperty); }
  set { SetValue(LabelTextBox.TextProperty, value); }
 }
}
David Rogers
Thanks for the code, I get this output when I try to use it:System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=This'. BindingExpression:Path=Label; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
Jake Pearson
Sorry, I figured it out. You defined This as the name of the control. Thanks!!
Jake Pearson