Vahid
Vahid

Reputation: 5444

AncestorLevel not working when binding to the view model of parent window in WPF

MainWindow is bound to MainViewModel and the rest are all bound to ChildViewModel which is a property of MainViewModel. Now in the innermost child window, which is bound to ChildViewModel, I want to bind a property to MainViewModel.

I'm using the following code:

Here the first value of the Converter is bound to property C in ChildViewModel and it works. I have tried to bind the second value to a property to the DataContext of MainWindow (MainViewModel) with no success.

<MultiBinding Converter="{StaticResource UnitConverter}">
    <Binding Path="C"/>
    <Binding RelativeSource="{RelativeSource FindAncestor, 
        AncestorType={x:Type Window}, AncestorLevel=2}"
             Path="DataContext.CurrentTargetUnit"/>
</MultiBinding>

--- Main Window -------------------------------------------
-   ----- User Control 1 -------------------------------  -
-   -   ---- User Control 2--------------------------  -  -
-   -   -   ------ Child Window 1 ----------------  -  -  -
-   -   -   -   ----- Child Window 2 ----------  -  -  -  -
-   -   -   -   -                             -  -  -  -  -
-   -   -   -   -   [Bind to MainViewModel]   -  -  -  -  -
-   -   -   -   -                             -  -  -  -  -
-   -   -   -   -------------------------------  -  -  -  -
-   -   -   --------------------------------------  -  -  -
-   -   ---------------------------------------------  -  -
-   ----------------------------------------------------  -
-----------------------------------------------------------

Update:

My best guess is that one only can bind to the parent window and not higher than that. Maybe the uppermost window is not in the visual tree?

Upvotes: 1

Views: 989

Answers (1)

ΩmegaMan
ΩmegaMan

Reputation: 31616

Create a property on the ChildViewModel which is a referential link to the MainViewModel. Upon the instantiation of the child VM, link it to the MainViewModel. Then the internal windows/controls can get to the MainViewModel by referencing the aformentioned ChildViewModel property to the main vm.


On the User Control1 and 2 create a dependency property of the main view model's type such as:

// <summary>
/// Holds the parent VM here.
/// </summary>
public MainVM ParentVM
{
    get { return GetValue(ParentVMProperty) as MainVM; }
    set { SetValue(ParentVMProperty, value); }
}

    /// <summary>
    /// Identifies the ParentVM dependency property.
    /// </summary>
    public static readonly System.Windows.DependencyProperty ParentVMProperty =
        System.Windows.DependencyProperty.Register(
            "ParentVM",
            typeof(MainVM),
            typeof({Insert Control1 or 2 class type here}),
            new System.Windows.PropertyMetadata(null, OnParentVMPropertyChanged));

    /// <summary>
    /// ParentVMProperty property changed handler.
    /// </summary>
    /// <param name="d">BeginRandom that changed its ParentVM.</param>
    /// <param name="e">Event arguments.</param>
    private static void OnParentVMPropertyChanged(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)
    {
        var source = d as {Insert Control1 or 2 class type here};
        MainVM value = e.NewValue as MainVM;
    }

Since each window will have a reference available to the MainWindowVM, all you have to do is path to the current window's ParentVM property.


Note that to create control's dependency properties I use the handy snippets, written for Silverlight, but all of them work in WPF:

Helpful Silverlight Snippets - Jeff Wilcox

Upvotes: 1

Related Questions