Как и в заголовке, я хотел бы привязать элемент в представлении 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>
Похоже, что самым простым предложением было бы сохранить некоторую запись родителя на дочернем 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>
Таким образом, вы можете использовать MainWindowViewModel
для всех своих просмотров, но я не знаю, как это работает с Caliburn. Я не знаю, как вы используете свой UserControl
s, но, возможно, RelativeSource
может вам помочь (например, вы можете привязываться к DataContext
относительного контроля).