WPF命令全局可用

时间:2016-01-27 17:11:46

标签: c# wpf user-controls routedcommand

我有一个Window元素,其中包含RibbonMenue。在此Window中,有一些UserControls。其中一个UserControlDataGrid。我创建了一个ICommand,可以添加和删除DataGrid中的行。

问题在于我需要从ICommands访问这些RibbonMenu,但我只能在更高级别访问它们" (窗口),因为它们被声明并绑定到绑定到ViewModel的{​​{1}}。

如何创建可以全局调用的UserControl?请注意,ICommands需要对ICommand后面的ViewModel的引用,因为我需要从中删除行等等。

Image makes it a bit clearer I hope

2 个答案:

答案 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
        }
    }
}