Badiboy
Badiboy

Reputation: 1559

Bind variable to a dependency property through another dependency property

I have the following controls embedding (not inheritance, just placing): enter image description here

Native TextBlock is placed in MyMiddleControl, which is placed in MyGlobalControl. MyMiddleControl has a DependencyPropery "GroupName", which is binded to TextBox.Text. MyGlobalControl has a public property "MyText, which is binded to MyMiddleControl.GroupName.

XAML:

<UserControl x:Class="MyMiddleControl"
         ...
         DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
    <TextBlock Text="{Binding Path=GroupName}"/>
</UserControl>

with

public static readonly DependencyProperty GroupNameProperty =
    DependencyProperty.Register("GroupName", typeof(string), 
    typeof(MyMiddleControl), 
    new PropertyMetadata("default"));

public string GroupName
{
    get { return (string)GetValue(GroupNameProperty); }
    set { SetValue(GroupNameProperty, value); }
}

and

<UserControl x:Class="MyGlobalControl"
         ...
         DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
    <MyMiddleControl GroupName="{Binding MyText}"... />
</UserControl>

with

public string _myText = "myDef";
public string MyText
{
    get { return _myText ; }
    set { _myText = value; }
}

Problem #1. When I run the program I see "default" in the textblock instead of "myDef".

Problem #2. I have the button which do:

private void TestButton_Click(object sender, RoutedEventArgs e)
{
    MyText = "TestClick";
}

The result is the same: "default".

Why? :(

Update:

I forget to say. If I do

<UserControl x:Class="MyGlobalControl"
         ...
         DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}">
    <MyMiddleControl GroupName="FixedTest"... />
</UserControl>

It works fine.

PS. The sample project with changes from the first answer: TestBind.zip.

Upvotes: 1

Views: 699

Answers (1)

punker76
punker76

Reputation: 14601

you must implement INotifyPropertyChanged to notify changes for a binded property

public class SampleData : INotifyPropertyChanged
{
  public SampleData ()
  {
     this.MyText = "myDef";
  }

  public string _myText;
  public string MyText
  {
    get { return _myText ; }
    set {
      _myText = value;
      this.RaisePropChanged("MyText");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  public void RaisePropChanged(string name) {
    var eh = this.PropertyChanged;
    if (eh != null) {
      eh(this, new PropertyChangedEventArgs(name));
    }
  }
}

hope that helps

EDIT try following solution with setting x:Name and DataContext in code behind

public partial class MyMiddleControl : UserControl
{
  public MyMiddleControl() {
    this.DataContext = this;
    this.InitializeComponent();
  }

  public static readonly DependencyProperty GroupNameProperty =
    DependencyProperty.Register("GroupName", typeof(string),
                                typeof(MyMiddleControl),
                                new PropertyMetadata("default"));

  public string GroupName {
    get { return (string)this.GetValue(GroupNameProperty); }
    set { this.SetValue(GroupNameProperty, value); }
  }
}

<UserControl x:Class="TestBind.MyMiddleControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="middleControl">
    <Grid>
        <TextBlock Height="40" HorizontalAlignment="Left" Margin="45,23,0,0" 
                   Name="textBlock1" Text="{Binding ElementName=middleControl, Path=GroupName}" 
                   VerticalAlignment="Top" Width="203" />
    </Grid>
</UserControl>

public partial class MyGlobalControl : UserControl, INotifyPropertyChanged
{
  public MyGlobalControl() {
    this.DataContext = this;
    this.InitializeComponent();
    this.MyText = "myDef";
  }

  public string _myText;
  public string MyText {
    get { return this._myText; }
    set {
      this._myText = value;
      this.OnPropertyChanged("MyText");
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged(string propertyName) {
    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null) {
      handler(this, new PropertyChangedEventArgs(propertyName));
    }
  }

  private void button1_Click(object sender, RoutedEventArgs e) {
    this.MyText = "btnClick";
  }
}

<UserControl x:Class="TestBind.MyGlobalControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:my="clr-namespace:TestBind"
             x:Name="globalControl">
  <Grid>
    <my:MyMiddleControl HorizontalAlignment="Left"
                        Margin="24,82,0,0"
                        x:Name="myFloatTest"
                        GroupName="{Binding ElementName=globalControl, Path=MyText}"
                        VerticalAlignment="Top" />
    <Button Content="Button"
            Height="23"
            HorizontalAlignment="Left"
            Margin="296,65,0,0"
            Name="button1"
            VerticalAlignment="Top"
            Width="75"
            Click="button1_Click" />
  </Grid>
</UserControl>

Upvotes: 2

Related Questions