C# 使用动态命令的MVVM
我需要创建一个能够创建动态命令的类,我可以绑定到该类。我有一个带有插件的高度动态应用程序,开发人员只在后端创建插件,并从后端控制所有事情。前端是在另一个“远程”应用程序中创建的,该应用程序将后端作为DataContext。下面是一个示例(不是完整的示例),只是为了说明我想做什么:C# 使用动态命令的MVVM,c#,.net,wpf,C#,.net,Wpf,我需要创建一个能够创建动态命令的类,我可以绑定到该类。我有一个带有插件的高度动态应用程序,开发人员只在后端创建插件,并从后端控制所有事情。前端是在另一个“远程”应用程序中创建的,该应用程序将后端作为DataContext。下面是一个示例(不是完整的示例),只是为了说明我想做什么: <Window x:Class="WpfApplication7.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/p
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Command="{Binding PressMe}">PressMe</Button>
</Grid>
</Window>
namespace WpfApplication7
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
TaskViewModel Model = new TaskViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = Model;
Model.AddCommand("PressMe", (o) => { Console.WriteLine("TEST"); });
}
}
}
压榨
命名空间WpfApplication7
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
TaskViewModel模型=新的TaskViewModel();
公共主窗口()
{
初始化组件();
DataContext=模型;
Model.AddCommand(“PressMe”,(o)=>{Console.WriteLine(“TEST”);});
}
}
}
所以问题是,如果XAML需要绑定可以查看的“定义良好”或“已知”属性,我如何创建类似的内容
我想到了一些TaskViewModel并实现了IExpando,但不知何故,当连接到IExpando方法时,反射并没有执行。有没有其他方法来做这样的事情
谢谢
Martin与往常一样,WPF中基于项的UI是使用和利用实现的,而不管每个项的视觉外观如何,也不管底层类的实际行为如何 在本例中,您正在查找命令的动态集合:
// This class is not fully implemented. Replace by your own DelegateCommand or
// Grab an ICommand implementation from any of the well known MVVM Frameworks out there.
// This only exists for the sake of the example.
public class Command : ICommand
{
private readonly Action action;
public string DisplayName { get; private set; }
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
action();
}
public Command(string displayName, Action action)
{
this.action = action;
this.DisplayName = displayName;
}
}
视图模型:
public class ViewModel
{
public ObservableCollection<Command> Commands { get; private set; }
public ViewModel()
{
Commands = new ObservableCollection<Command>();
}
// You will add commands at some point at runtime.
public void AddSomeCommands()
{
Commands.Add(new Command("Command1", () => MessageBox.Show("This is Command1!")));
Commands.Add(new Command("Command2", () => MessageBox.Show("This is Command2!!")));
Commands.Add(new Command("Command3", () => MessageBox.Show("This is Command3!!!")));
Commands.Add(new Command("Command4", () => MessageBox.Show("This is Command4!!!!")));
}
}
代码隐藏:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var vm = new ViewModel();
vm.AddSomeCommands();
this.DataContext = vm;
}
}
结果:
编辑:
如果需要将这些命令绑定到热键,只需向命令添加属性:
public Key HotKey { get; set; }
然后在代码隐藏中添加如下内容:
foreach (var c in vm.Commands)
this.InputBindings.Add(new KeyBinding(c, c.HotKey, ModifierKeys.None));
您的视图不应该知道您的ViewModel,您正在打破MVVM设计模式。您应该将命令用作ViewModel的属性,而不是动态创建它们。@MikeEason我不同意。从您编写
{Binding Anything}
的那一刻起,视图就已经“知道”了ViewModel。尽管不存在编译时耦合,但仍然存在一种耦合,没有这种耦合,任何东西都无法工作。总之,OP,您只是在寻找一个可观察的集合
和一个项控件
@HighCore,这是错误的。它根本不耦合。实际上,这是一个隐含的契约。视图绑定到“某物”,从而形成一个契约,它期望DataContext拥有该“某物”。它不知道(耦合)datacontext实际上是什么。ViewModel为该绑定契约提供了实现(或不提供,但绑定失败)。@Meirionhugh提供了一个隐式契约,必须满足该隐式契约才能使一切正常工作。如果我为soapweb服务创建一个接口,或者说一个WSDL,根据定义,这就是一个契约。如果中间的任何部分不遵守合同,那么什么都不起作用。我的观点是,将代码耦合到特定的ViewModel(或者,如果您更喜欢的话,也可以耦合到接口)是可以的,就像使用{Binding Anything}
是可以的一样。我明白您的观点。问题是我无法使用某些项集合,因为这些命令不仅用于按钮,还用于键盘事件。所以我真的需要有一个方法,在那里我可以引用一个名字。事实上,我可以使用ObservaleCollection,但我还需要一种在{Binding}中使用名称的方法。
foreach (var c in vm.Commands)
this.InputBindings.Add(new KeyBinding(c, c.HotKey, ModifierKeys.None));