Привязка элемента в дочернем представлении к свойству родительского ViewModel

1

Как и в заголовке, я хотел бы привязать элемент в представлении Child к свойству родительского ViewModel.

Есть ли для этого синтаксис Caliburn.Micro или по умолчанию WPF XAML? Я имею в виду эту точную ситуацию: привязать к родительскому свойству ViewModel.

Или я должен попытаться достичь этого по-другому? Так, какой был бы лучший/простой способ сделать это?

Вот пример базового примера Caliburn.Micro:

MainWindowViewModel.cs

namespace BindingToParentVMProperty.MVVM
{
    public class MainWindowViewModel
    {
        public ChildViewModel Child { get; set; }
        public string ParentName { get; set; }

        public MainWindowViewModel()
        {
            Child = new ChildViewModel();
            ParentName = "Peter Griffin";
        }
    }
}

MainWindowView.xaml:

<UserControl x:Class="BindingToParentVMProperty.MVVM.MainWindowView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d">
    <Grid Width="200" Height="200">
        <ContentControl Name="Child" />
    </Grid>
</UserControl>

ChildViewModel.cs:

using Caliburn.Micro;

namespace BindingToParentVMProperty.MVVM
{
    public class ChildViewModel
    {
        public BindableCollection<GrandChildViewModel> GrandKids { get; set; }
        public string ChildName { get; set; }

        public ChildViewModel()
        {
            ChildName = "Stewie Griffin";
            GrandKids = new BindableCollection<GrandChildViewModel>
                {
                    new GrandChildViewModel {GrandChildName = "Stewie Griffin Jr."},
                    new GrandChildViewModel {GrandChildName = "Rupert Griffin Jr."}
                };
        }
    }
}

ChildView.xaml:

<UserControl x:Class="BindingToParentVMProperty.MVVM.ChildView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <!-- need to bind to MainWindowViewModel.ParentName-->
        <TextBlock Text="{Binding Path=HowToBindTo_ParentName}"/>
        <ListView Name="GrandKids" />
    </StackPanel>
</UserControl>

GrandChildViewModel.cs:

namespace BindingToParentVMProperty.MVVM
{
    public class GrandChildViewModel
    {
        public string GrandChildName { get; set; }
    }
}

GrandChildView.xaml:

<UserControl
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             x:Class="BindingToParentVMProperty.MVVM.GrandChildView"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <TextBlock x:Name="GrandChildName" />
        <!-- need to bind to ChildViewModel.ChildName -->
        <TextBlock Text="{Binding Path=HowToBindTo_ChildName}"/>
    </StackPanel>
</UserControl>
Теги:
xaml
wpf
mvvm
caliburn.micro

2 ответа

2
Лучший ответ

Похоже, что самым простым предложением было бы сохранить некоторую запись родителя на дочернем ViewModel (например, свойство Parent). Поскольку вы хотите, чтобы ваши ViewModels привязывались к их соответствующим Views, я думаю, что это станет концептуально довольно сложным, если вы начнете привязываться к свойствам и включаете информацию из-за границы связанного ViewModel.

Кроме того, в то время как это может не беспокоить конкретный проект, над которым вы работаете, если вы начинаете включать свойства из других UserControls, вы неявно создаете ссылки и зависимости, которые могут возникнуть в случае неудобства вам, если вы хотите повторно использовать элементы управления в другом месте в неиерархическом контексте.

Тем не менее, вы можете пройти через свое дерево пользовательского интерфейса, чтобы получить требуемый DataContext (ViewModel) из родительского Kollegos управления и привязать его к желаемому свойству с использованием существующего синтаксиса WPF, как предлагает Kollegos, используя RelativeSource и свойство AncestorType.

В вашем случае это может выглядеть примерно так:

<UserControl x:Class="BindingToParentVMProperty.MVVM.ChildView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:local="clr-namespace:YourProjectNamespaceContainingParentView"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
    <!-- Set our DataContext bind to parent MainWindowViews DataContext (ViewModel) -->
    <TextBlock Text="{Binding Path=ParentName}"
        DataContext="{Binding RelativeSource={RelativeSource
                      FindAncestor, AncestorType={x:Type local:MainWindowView}},
                      Path=DataContext}"/>
    <ListView Name="GrandKids" />
</StackPanel>

Документация RelativeSource

1

Таким образом, вы можете использовать MainWindowViewModel для всех своих просмотров, но я не знаю, как это работает с Caliburn. Я не знаю, как вы используете свой UserControl s, но, возможно, RelativeSource может вам помочь (например, вы можете привязываться к DataContext относительного контроля).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню