我有一个Window
元素,其中包含RibbonMenue
。在此Window
中,有一些UserControls
。其中一个UserControl
是DataGrid
。我创建了一个ICommand
,可以添加和删除DataGrid
中的行。
问题在于我需要从ICommands
访问这些RibbonMenu
,但我只能在更高级别访问它们" (窗口),因为它们被声明并绑定到绑定到ViewModel
的{{1}}。
如何创建可以全局调用的UserControl
?请注意,ICommands
需要对ICommand
后面的ViewModel
的引用,因为我需要从中删除行等等。
答案 0 :(得分:0)
传统的MVVM方式"全局命令"是使用CompositeCommand。您将拥有一个GlobalCommands.cs文件,其中包含一个名为GlobalCommands的静态类。
在其中,您将拥有返回CompositeCommand实例的ICommand属性。然后,任何对该命令感兴趣的VM都可以在其构造函数中附加到它:GlobalCommands.SomeCommand.RegisterCommand(...)。您的UI将附加到GlobalCommands命令。
因此GlobalCommands将保存CompositeCommand,它只是一个空的shell / holder命令,VM将使用复合命令注册一个正常的RelayCommand并处理该命令。多个VM可以使用相同的命令注册,所有VM都将被调用。
更高级的CompositeCommand实现还包括一个IActiveAware功能,可以使CompositeCommand只将canexecute / execute发送给" active" VM' S
我相信CompositeCommand最初来自Prism,但许多人(包括我自己)刚刚将其用于非Prism应用程序。
答案 1 :(得分: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
}
}
}