wpf binding upwards: bind to view model property inside nested uiElement

Deadly 提交于 2021-02-11 12:40:41

问题


I have a WPF project with a view model and some nested UI elements. Here is the (relevant section of) XAML:

<UserControl> // DataContext is MyVM (set programmatically)
    <TreeView ItemsSource="{Binding Trees}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Subtrees}">
                <StackPanel>
                    <ListView ItemsSource="{Binding Contents}"
                              SelectedValue="{Binding SelectedContent}" // won't work: Tree has no such property
                              SelectionMode="Single"/>
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
</UserControl>

Here the code for the ViewModel class:

public class MyVM : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }

    public IEnumerable<Tree> Trees { get; set; }

    private object _selectedContent;
    public string SelectedContent
    {
        get => _selectedContent;
        set
        {
            _selectedContent = value;
            OnPropertyChanged();
        }
    }
}

Here the code for class Tree:

public class Tree
{
    public IEnumerable<Tree> Subtrees { get; set; }
    public IEnumerable<string> Contents { get; set; }
}

I want to allow only one selection globally for all ListViews. Just like here, I want to bind all ListViews to the property SelectedContent in the view model MyVM.

The problem is that the data context of the ListView is a Tree, and not the MyVM from the top user control. (It should be Tree, since we want to show the Contents.) I know I can bind downwards using SelectedValuePath, but how do I go up instead in order to bind SelectedValue to the MyVM property SelectedContent?

I tried SelectedValue="{Binding RelativeSource={RelativeSource AncestorType ={x:Type UserControl}}, Path=SelectedContent}", but it did not work.


回答1:


Try to use

SelectedValue="{Binding RelativeSource={RelativeSource 
  Mode=FindAncestorBindingContext, AncestorType ={x:Type MyVM}}, 
  Path=SelectedContent}"

Maybe, you'll need to describe your model's namespace in header:

xmlns:viewmodel="clr-namespace:_your_namespace_.ViewModels"

and use

SelectedValue="{Binding RelativeSource={RelativeSource 
  Mode=FindAncestorBindingContext, AncestorType ={x:Type viewmodel:MyVM}}, 
  Path=SelectedContent}"



回答2:


There is a comment here, saying:

Just wanted to note here that if you want to bind to a property in the DataContext of the RelativeSource then you must explicitly specify it: {Binding Path=DataContext.SomeProperty, RelativeSource=.... This was somewhat unexpected for me as a newbie when I was trying to bind to a parent's DataContext within a DataTemplate.

This comment deserves more attention, so I'll use it as the correct answer.



来源:https://stackoverflow.com/questions/65991141/wpf-binding-upwards-bind-to-view-model-property-inside-nested-uielement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!