2015-04-01 68 views
1

我需要创建一个能够创建动态命令的类,我可以绑定到该类。我有一个高度动态的插件应用程序,开发人员只在后端创建插件,并控制后端的所有内容。前端是在另一个具有后端作为DataContext的“远程”应用程序中创建的。下面是一个例子(不是完整的例子),只显示了我想做的事:带动态命令的MVVM

<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"); }); 
     } 
    } 
} 

所以现在的问题是,如何创建这样的事情,如果XAML需要“明确”或“已知的“属性绑定可以看看。

我想到了一些TaskViewModel并实现了IExpando,但不知怎的,当挂接到IExpando方法时,反射不会执行。是否有其他方式来做这样的事情。

由于 马丁

+4

你的观点应该不**知道你的ViewModel,你在这里打破了MVVM设计模式。您应该将您的命令用作ViewModel的**属性**,而不是动态创建它们。 – 2015-04-01 11:18:10

+0

@MikeEason我不同意。视图已经从你写'{Binding Anything}'的那一刻起“知道”ViewModel。即使没有编译时耦合,仍然存在一个耦合,没有这个耦合什么都不会起作用。 – 2015-04-01 11:30:13

+0

不管怎样,OP,你只是在寻找一个'ObservableCollection '和一个'ItemsControl' @ – 2015-04-01 11:30:29

回答

2

与往常一样,在基于WPF项的UI使用ItemsControl,并利用Data Templating,无论视觉外观用于每个项目或底层类的实际行为的实现。

在这种情况下,你要找的命令的动态集合:

// 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!!!!"))); 
    } 
} 

然后您可以创建一个ItemsControl,显示Button S代表每个命令项:

<Window x:Class="WpfApplication22.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"> 

    <ItemsControl ItemsSource="{Binding Commands}" 
        VerticalAlignment="Top"> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 

     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Button Command="{Binding}" 
         Content="{Binding DisplayName}" 
         Margin="5"/> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Window> 

背后的代码:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     var vm = new ViewModel(); 
     vm.AddSomeCommands(); 

     this.DataContext = vm; 
    } 
} 

结果:

enter image description here

编辑:

如果您需要绑定这些命令的快捷键,只需一个属性添加到命令:

public Key HotKey { get; set; } 

然后在后面的代码中添加如下代码:

foreach (var c in vm.Commands) 
    this.InputBindings.Add(new KeyBinding(c, c.HotKey, ModifierKeys.None)); 
+0

我明白你的观点。问题是我不能使用某些项目集合,因为这些命令不仅用于按钮,还用于键盘事件。所以我真的需要有一种方法,我可以在这里引用一个名字。事实上,我可以使用ObservableCollection,但我也需要一种方式来处理{Binding}中的名称。 – msedi 2015-04-01 12:10:36