2016-01-27 49 views
0

我有一个Window元素,它包含一个RibbonMenue。在此Window内有一些UserControls。其中UserControlDataGrid。我创建了一个ICommand,它允许我添加和删除DataGrid中的行。WPF命令全球可用

的问题是,我莫名其妙地需要从RibbonMenu访问这些ICommands,但我可以在“较高水平”(窗口)访问它们,因为它们的声明并绑定到这势必给UserControlViewModel

如何创建可在全球范围内调用的ICommands?请注意,ICommand需要参考UserControl之后的ViewModel,因为我需要从中删除行等等。

Image makes it a bit clearer I hope

+0

代码,你询问你想有一个不同的视图按钮调用位于您的MainViewModel绑定到主窗口一个ICommand ? – mrsargent

+0

我添加了一张图片,希望更清楚我要求的内容。 –

回答

0

传统MVVM的方式做 “全局命令” 是使用CompositeCommand。您将拥有一个GlobalCommands.cs文件,其中包含一个名为GlobalCommands的静态类。

其中,您将拥有返回CompositeCommand实例的ICommand属性。然后,任何对该命令感兴趣的虚拟机都可以附加到它的构造函数中:GlobalCommands.SomeCommand.RegisterCommand(...)。您的用户界面将附加到GlobalCommands命令。

因此,GlobalCommands将持有CompositeCommand,它只是一个空的shell/holder命令,VM将用composite命令注册一个正常的RelayCommand并处理该命令。多个VM可以使用相同的命令进行注册,并且所有的VM都会被调用。

更高级的CompositeCommand实现还包括一个IActiveAware功能,可以使CompositeCommand只发送canexecute/execute到“活动”虚拟机。

我相信CompositeCommand最初来自Prism,但许多人(包括我自己)刚刚将它分解出来用于非Prism应用程序。

0

我设法得到你所需要的,我做了这里一个单指令是整个例子(抱歉长的帖子只是想确保你得到它正确地将工作):

using System; 
using System.Windows.Input; 

namespace WpfApplication 
{ 
    public class GlobalCommand<T> : ICommand 
    { 
     #region Fields 
     private readonly Action<T> _execute = null; 
     private readonly Predicate<T> _canExecute = null; 
     private static GlobalCommand<T> _globalCommand; 
     private static readonly object locker = new object(); 
     #endregion 

     #region Constructors 

     public static GlobalCommand<T> GetInstance(Action<T> execute) 
     { 
      return GetInstance(execute, null); 
     } 
     public static GlobalCommand<T> GetInstance(Action<T> execute, Predicate<T> canExecute) 
     { 
      lock (locker) 
      { 
       if (_globalCommand == null) 
       { 
        _globalCommand = new GlobalCommand<T>(execute, canExecute); 
       } 
      } 
      return _globalCommand; 
     } 

     private GlobalCommand(Action<T> execute, Predicate<T> canExecute) 
     { 
      if (execute == null) 
       throw new ArgumentNullException("execute"); 

      _execute = execute; 
      _canExecute = canExecute; 
     } 

     #endregion 

     #region ICommand Members 

     public bool CanExecute(object parameter) 
     { 
      return _canExecute == null || _canExecute((T)parameter); 
     } 

     public event EventHandler CanExecuteChanged 
     { 
      add 
      { 
       if (_canExecute != null) 
        CommandManager.RequerySuggested += value; 
      } 
      remove 
      { 
       if (_canExecute != null) 
        CommandManager.RequerySuggested -= value; 
      } 
     } 

     public void Execute(object parameter) 
     { 
      _execute((T)parameter); 
     } 

     #endregion 
    } 
} 


视图模型

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.ComponentModel; 
using System.Windows.Input; 

namespace WpfApplication 
{ 
    public class ViewModel : INotifyPropertyChanged 
    { 

     public event PropertyChangedEventHandler PropertyChanged; 
     public ObservableCollection<Category> Categories { get; set; } 
     public ICommand AddRowCommand { get; set; } 
     public ViewModel() 
     { 
      Categories = new ObservableCollection<Category>() 
      { 
      new Category(){ Id = 1, Name = "Cat1", Description = "This is Cat1 Desc"}, 
      new Category(){ Id = 1, Name = "Cat2", Description = "This is Cat2 Desc"}, 
      new Category(){ Id = 1, Name = "Cat3", Description = "This is Cat3 Desc"}, 
      new Category(){ Id = 1, Name = "Cat4", Description = "This is Cat4 Desc"} 
      }; 

      this.AddRowCommand = GlobalCommand<object>.GetInstance(ExecuteAddRowCommand, CanExecuteAddRowCommand); 
     } 

     private bool CanExecuteAddRowCommand(object parameter) 
     { 
      if (Categories.Count <= 15) 
       return true; 
      return false; 
     } 

     private void ExecuteAddRowCommand(object parameter) 
     { 
      Categories.Add(new Category() 
      { 
       Id = 1, 
       Name = "Cat"+(Categories.Count+1), 
       Description = "This is Cat" + (Categories.Count + 1) + " Desc" 
      }); 
     } 

    } 
} 


型号

namespace WpfApplication 
{ 
    public class Category 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
     public string Description { get; set; } 
    } 
} 


MainWindow。XAML

<Window x:Class="WpfApplication.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfApplication" 
     Title="MainWindow" Height="500" Width="525"> 
    <Window.Resources> 
     <local:ViewModel x:Key="ViewModel" /> 
    </Window.Resources> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Ribbon x:Name="RibbonWin" SelectedIndex="0" Grid.Row="0"> 
      <Ribbon.QuickAccessToolBar> 
       <RibbonQuickAccessToolBar> 
        <RibbonButton x:Name ="Delete" Content="Delete a row" Click="Delete_Click"/> 
       </RibbonQuickAccessToolBar> 
       </Ribbon.QuickAccessToolBar> 
     </Ribbon> 
     <UserControl Grid.Row="1" x:Name="UserControl" DataContext="{StaticResource ViewModel}"> 
      <Grid> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="*"/> 
        <RowDefinition Height="Auto"/> 
       </Grid.RowDefinitions> 
       <DataGrid ItemsSource="{Binding Path=Categories}" AutoGenerateColumns="False" CanUserAddRows="False" Margin="0,10,0,100" Name="DataGrid1" Grid.Row="0" > 
        <DataGrid.Columns> 
         <DataGridTextColumn Header="Id" IsReadOnly="True" Binding="{Binding Id}"/> 
         <DataGridTextColumn Header="Name" IsReadOnly="True" Binding="{Binding Name}"/> 
         <DataGridTextColumn Header="Description" IsReadOnly="True" Binding="{Binding Description}"/> 
        </DataGrid.Columns> 
       </DataGrid> 
       <Button Content="Add new row" Command="{Binding Path=AddRowCommand}" HorizontalAlignment="Center" Width="75" Grid.Row="1"/> 
      </Grid> 

     </UserControl> 
    </Grid> 
</Window> 


背后

using System.Windows; 

namespace WpfApplication 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     private void Delete_Click(object sender, RoutedEventArgs e) 
     { 
      GlobalCommand<object>.GetInstance(null).Execute(null);// I'm not quite happy with this but it works 
     } 
    } 
} 
+0

是的,这很糟糕...不要直接调用事件处理程序。如上所述,查看CompositeCommand。 – SledgeHammer