我有一个带有按钮的UserControl。此按钮需要将一些项添加到所述UC内部的网格中。我知道我可以用Click事件做到这一点。
这里的问题是我使用MVVM并在相应的ViewModel之外更改数据会破坏格式(可以这么说)。
有没有办法创建一个ICommand依赖属性,所以我可以将所述DP绑定到按钮,并具有在ViewModel中将项添加到网格的功能? (我的UC和我的ViewModel中都有List,它们按预期工作)
谢谢。
找到了一种方法来解决它我想要的方式。在这里留下答案,以便人们可以使用它:
1)在用户控件的代码隐藏中,创建一个依赖属性。我选择ICommand,因为在我的ViewModel中我将其设置为DelegateCommmand:
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(UserControl));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
2)在UserControl的XAML代码中,绑定此依赖项属性(在本例中为一个按钮):
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
<Button Command="{Binding Command}" />
</Grid>
3)接下来,在ViewModel上,声明一个Command属性并进行相应配置:
public ICommand ViewModelCommand { get; set; }
public ViewModelConstructor()
{
ViewModelCommand = new DelegateCommand(ViewModelCommandExecute);
}
private void ViewModelCommandExecute()
{
// Do something
}
4)最后,在ViewControl嵌套的View上,我们声明绑定:
<UserControls:UserControl Command={Binding ViewModelCommand}/>
这样,绑定将发生,您可以将命令从任何用户控件的按钮绑定到ViewModel,而不会破坏MVVM。
基本方法是创建一个实现ICommand的Object(即MyCommand),并将其嵌套在ViewModel中。在MyCommand中,您无法访问ViewModel。你可以解决它(即在MyCommand构造函数中传递对ViewModel的引用),但最后它的代码太多了(对于像这样的简单东西)。我想几乎没有人真的这样做。
大多数人使用DelegateCommand解决(大部分)上述问题。
最后但并非最不重要的,只需使用事件处理程序。 如果您对它们进行编码,就像这样:
void Grid_MouseMove(object sender, MouseEventArgs e)
{ viewModel.SaveMousePosition(e.GetPosition()); }
你没有违反任何MVVM规则。 并且您无法使用命令处理上述事件。 MouseMove没有命令(大多数事件都没有),并且您无法在命令中传递事件参数。
您可以使用像this这样的Interaction.Triggers处理每个事件 但是你仍然缺少处理事件参数的能力(并添加丑陋的XAML)。
对我来说,直到WPF支持事件处理程序中的数据绑定,例如
Grid MouseMove="{Binding SaveMousePosition(e)}"
代码隐藏仍然是处理事件的最有效方法。
我遇到了类似的问题,这个问题/答案对我帮助最大;所以我会在这里发布我的解决方案以防其他人稍后再谷歌。用mvvm灯制成。
我有自定义winforms控件作为模型和WPF控件作为视图。所以,xaml of View(我的View有一个usercontrol,没有app.xaml):
<UserControl.Resources>
<ResourceDictionary>
<viewModel:ViewModelLocator x:Key="Locator" />
</ResourceDictionary>
</UserControl.Resources>
<UserControl.DataContext>
<Binding Path = "Main" Source="{StaticResource Locator}"></Binding>
</UserControl.DataContext>
<Grid>
<Button Command="{Binding Zoom, ElementName=Wrapper}"></Button>
<viewModel:ProfileWrapper x:Name="Wrapper" >
</viewModel:ProfileWrapper>
</Grid>
单击按钮将路由到ProfileWrapper中的RelayCommand Zoom(这是我的模型实现的位置)
然后Profile Wrapper的xaml很简单:
<Grid>
<WindowsFormsHost>
<local:ManualControl x:Name="abc" ></local:ManualControl>
</WindowsFormsHost>
</Grid>
以及Profile Wrapper背后的代码:
public partial class ProfileWrapper : UserControl
{
public ProfileWrapper()
{
InitializeComponent();
test = abc;
Command = new RelayCommand(() => test.bZoomIn());
}
public ManualControl test;
public RelayCommand Zoom { get; set; }
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register(
"Zoom",
typeof(ICommand),
typeof(ProfileWrapper));
public ICommand Command
{
get
{
return (ICommand)GetValue(CommandProperty);
}
set
{
SetValue(CommandProperty, value);
}
}
}
我的MainViewModel类是空的,所有功能都转到Profile Wrapper类,这可能很糟糕,但至少它可以工作。