我将从我的代码开始(整个示例在这里:https://github.com/robertwojnar/MvvmDemo1) 在我的小演示中,我有一个带有usercontrol的单一视图应用程序。所以我有:
基本上就是这样。非常简单。这是代码:
FooUserControl.xaml
<UserControl x:Class="MvvmDemo1.WPF.Views.FooUserControl"
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:MvvmDemo1.WPF.Views"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="100">
<Grid MouseDown="UIElement_OnMouseDown">
<Rectangle Fill="BlueViolet" />
</Grid>
</UserControl>
FooUserControl(代码隐藏)
public partial class FooUserControl : UserControl
{
public FooUserControl()
{
InitializeComponent();
}
public event EventHandler<BarEventArgs> BarClick;
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
{
double x = e.GetPosition(this).X;
double y = e.GetPosition(this).Y;
string value_to_pass = "[" + x + "," + y + "]";
BarEventArgs bar = new BarEventArgs() { Bar = 2, Foo = value_to_pass };
BarClick?.Invoke(sender, bar);
}
}
MainWindow.xaml (没有代码)
<Window x:Class="MvvmDemo1.WPF.Views.MainWindow"
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"
xmlns:local="clr-namespace:MvvmDemo1.WPF.Views"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="http://www.galasoft.ch/mvvmlight"
xmlns:viewModels="clr-namespace:MvvmDemo1.WPF.ViewModels">
<Window.DataContext>
<viewModels:MainWindowViewModel />
</Window.DataContext>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<cmd:EventToCommand Command="{Binding Mode=OneWay, Path=LoadedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<local:FooUserControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="BarClick">
<cmd:EventToCommand Command="{Binding ClickedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</local:FooUserControl>
</Grid>
</Window>
MainWindowViewModel.cs
public class MainWindowViewModel : ObservableObject
{
public string Title => "Main window";
public ICommand LoadedCommand => new RelayCommand(Loaded);
private void Loaded()
{
Debug.WriteLine("Loaded");
}
public ICommand ClickedCommand => new RelayCommand<BarEventArgs>(o => Clicked(o.Foo));
private void Clicked(string a)
{
Debug.WriteLine("Clicked " + a);
}
}
正如您所看到的,应用程序只是一个紫色矩形(在点击事件中)将点击坐标发送到MainWindowViewModel(通过ICommand,使用MVVM Light的EventToCommand
和Interaction.Triggers
)。
这是我的问题和疑问:
我想为UserControl添加一个ViewModel。想要将FooUserControlViewModel
添加到FooUserControl的DataContext
。当我设置FooUserControl的DataContext时,问题是 ClickedCommand没有被触发。问题是为什么?
当您克隆我的repo并将FooUserControl(代码隐藏)构造函数更改为此时,您将明白我的观点:
public FooUserControl()
{
InitializeComponent();
DataContext = new FooUserControlViewModel();
}
修改
看起来,MainWindowViewModel被分配给FooUserControl的DataContext(我想,因为Iteraction.Triggers
或EventToCommand
)。为什么会这样?这是否违反了view-viewmodel连接应为1&lt; - &gt; 1的规则。一个视图 - 一个ViewModel?
答案 0 :(得分:1)
如果 您想为DatContext
分配一个新的local:FooUserControl
,那么您可以这样做,但您将无法再直接绑定MainWindowViewModel
的控件。您必须更改Binding
下面的Command
:<{1}}:
<cmd:EventToCommand Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=DataContext.ClickedCommand}" PassEventArgsToCommand="True" />
当我们设置控件的
DataContext
时,它将以原始方式显示 通过Property Value Inheritance进行儿童控制。而如果 您在中间更改DataContext
的{{1}} 层次结构/ VisualTree,UserControl
的DataContext将不同 和Ancestors
。
也没有这样的规则1 View -1 ViewModel。这完全取决于您的设计的复杂性/要求您必须为Descendants
设置ViewModels
,为不同的View
设置一个ViewModel
。