views:

75

answers:

2

The nested ViewModel is set to the MainWindow DataContext:

var mainWindow = new MainWindow();
mainWindow.Show();
mainWindow.DataContext = new
{
    MyProperty = new
    {
        MySubProperty = "Hello"
    }
}

It is easy to bind to MySubProperty in XAML:

<Button Content="{Binding MyProperty.MySubProperty}"/>

How can I do this binding in code behind?

// MyButton.xaml.cs
public partial class MyButton : Button
{
    public MyButton()
    {
        InitializeComponent();
        // todo: add binding here
    }

    // I want this method called if this datacontext is set.
    // and called if MySubProperty changes and INotifyPropertyChange is implemented in the Datacontext.
    public void MySubPropertyChanged(string newValue)
    {
        // ...
    }
}

I have no access to MainWindow in MyButton.xaml.cs, so I cannot use it as a source.

The Button is just an example, but it would be a start. In my original scenario I have no useful dependency property for that. If a dp is necessary for such a binding, an example would be very helpful that includes the creation of a dp.

+1  A: 

How about this? (just a dirty example and untested, should work in principle)

// MyButton.xaml.cs
public partial class MyButton : Button
{
    public MyButton()
    {
        InitializeComponent();
        this.DataContextChanged += DataContext_Changed;
    }

    private void DataContext_Changed(Object sender,DependencyPropertyChangedEventArgs e)
    {
       INotifyPropertyChanged notify = e.NewValue as INotifyPropertyChanged;
       if(null != notify)
       {
          notify.PropertyChanged += DataContext_PropertyChanged;
       }
    }

    private void DataContext_PropertyChanged(Object sender,PropertyChangedEventArgs e)   
    {
        if(e.PropertyName == "MySubProperty")
           MySubPropertyChanged((sender as YourClass).MySubProperty);
    } 

    public void MySubPropertyChanged(string newValue)
    {
        // ...
    }
}

EDIT:

for binding something in codebehind you can use:

Binding binding = new Binding();
// directly to myproperty
binding.Source = MyProperty;
binding.Path = new PropertyPath("MySubProperty");
// or window
binding.Source = mainWindow; // instance
binding.Path = new PropertyPath("MyProperty.MySubProperty");

// then wire it up with (button is your MyButton instance)
button.SetBinding(MyButton.MyStorageProperty, binding);
//or
BindingOperations.SetBinding(button, MyButton.MyStorageProperty, binding);
MrDosu
Thank you very much for taking the time to answer. I didn't know/ I forgot that DataContextChanged is called if a parents DataContext is changed. However the coding effort increases if the data is more nested, so this does not seems to be the best way. So I will not set your answer as the accepted answer.
Janko R
@ your edit: thanks. But I have neither a MyProperty instance nor a MainWindow instance in the MyButton class.
Janko R
If you are binding, you have it set in the DataContext
MrDosu
ah ok. so i still need the DataContext_Changed. i got it :)
Janko R
A: 

In my original problem I had no dependency Property. So I created one.

public partial class MyButton : Button
{
    //...

    public string MyStorage
    {
        get { return (string)GetValue(MyStorageProperty); }
        set { SetValue(MyStorageProperty, value); }
    }

    public static DependecyProperty MyStorageProperty = 
        DependencyProperty.Register("MyStorage", typeof(string), typeof(MyButton),
            new UIPropertyMetadata(OnMyStorageChanged));
    public static void OnMyStorageChanged(DependecyObject d, DependencyPropertyChangedEventArgs e)
    {
        var myButton = d as MyButton;
        if (myButton == null)
            return;
        myButton.OnMyStorageChanged(d,e);
    }

    public void OnMyStorageChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        // ...
    }
}

And now I can set the Binding in XAML

<local:MyButton MyStorage="{Binding MyProperty.MySubProperty}"/>

This solved my problem. But I’m still curious how to do this binding without XAML.

Janko R