【问题标题】:WPF Binding Application Commands to ViewModel ICommandWPF 将应用程序命令绑定到 ViewModel ICommand
【发布时间】:2016-04-04 01:52:29
【问题描述】:

通过小型编辑器项目学习 WPF,并在设计时考虑到 MVVM。

以下代码抛出“在 'System.Windows.Data.Binding' 上提供值引发异常。”在第一次解析 XAML 的运行时。没有构建错误。

如何最好地将我的 ICommands 绑定到应用程序命令关闭、保存、另存为、打开、新建等。

目前我只有关闭和新建设置。

XAML 代码:

<Window x:Class="Editor.Views.EditorView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Editor.Views"
        xmlns:vm="clr-namespace:Editor.ViewModels"
        xmlns:userControls="clr-namespace:Editor.UserControls"
        mc:Ignorable="d"
        Title="EditorView" Height="600" Width="800" WindowStartupLocation="CenterScreen">

    <Window.Resources>
        <DataTemplate DataType="{x:Type vm:DocumentViewModel}">
            <ContentControl Content="{Binding DocTextBox}" />
        </DataTemplate>
    </Window.Resources>

    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Close"
                        Executed="{Binding ExitCommand}" />
        <CommandBinding Command="ApplicationCommands.New"
                        Executed="{Binding NewDocumentCommand}" />
        <!--<CommandBinding Command="ApplicationCommands.Open"
                        Executed="OpenDocument" />
        <CommandBinding Command="ApplicationCommands.Save"
                        CanExecute="SaveDocument_CanExecute"
                        Executed="SaveDocument" />
        <CommandBinding Command="ApplicationCommands.SaveAs"
                        Executed="SaveDocumentAs" />-->
    </Window.CommandBindings>

    <Window.InputBindings>
        <KeyBinding Key="N" Modifiers="Control" Command="{Binding NewDocumentCommand}" />
        <KeyBinding Key="F4" Modifiers="Control" Command="{Binding CloseDocumentCommand}" />
    </Window.InputBindings>

    <DockPanel>
        <userControls:Menu x:Name="menu"
                              DockPanel.Dock="Top" />

        <TabControl ItemsSource="{Binding Documents}" SelectedIndex="{Binding SelectedIndex}">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <WrapPanel>
                        <TextBlock Text="{Binding FileName}" />
                        <Button Command="{Binding CloseCommand}" Content="X" Margin="4,0,0,0" FontFamily="Courier New" Width="17" Height="17" VerticalContentAlignment="Center" />
                    </WrapPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
        </TabControl>
    </DockPanel>
</Window>

ViewModel 代码:

public class EditorViewModel : ViewModelBase
{
    private static int _count = 0;
    public EditorViewModel()
    {
        Documents = new ObservableCollection<DocumentViewModel>();
        Documents.CollectionChanged += Documents_CollectionChanged;
    }

    #region Event Handlers

    void Documents_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null && e.NewItems.Count != 0)
            foreach (DocumentViewModel document in e.NewItems)
                document.RequestClose += this.OnDocumentRequestClose;

        if (e.OldItems != null && e.OldItems.Count != 0)
            foreach (DocumentViewModel document in e.OldItems)
                document.RequestClose -= this.OnDocumentRequestClose;
    }

    private void OnDocumentRequestClose(object sender, EventArgs e)
    {
        CloseDocument();
    }

    #endregion

    #region Commands

    private RelayCommand _exitCommand;
    public ICommand ExitCommand
    {
        get { return _exitCommand ?? (_exitCommand = new RelayCommand(() => Application.Current.Shutdown())); }
    }

    private RelayCommand _newDocumentCommand;
    public ICommand NewDocumentCommand
    {
        get { return _newDocumentCommand ?? (_newDocumentCommand = new RelayCommand(NewDocument)); }
    }

    private void NewDocument()
    {
        _count++;
        var document = new DocumentViewModel { FileName = "New " + _count, DocTextBox = new RichTextBox() };
        Documents.Add(document);
        SelectedIndex = Documents.IndexOf(document);
    }

    private RelayCommand _closeDocumentCommand;
    public ICommand CloseDocumentCommand
    {
        get { return _closeDocumentCommand ?? (_closeDocumentCommand = new RelayCommand(CloseDocument, param => Documents.Count > 0)); }
    }

    private void CloseDocument()
    {
        Documents.RemoveAt(SelectedIndex);
        SelectedIndex = 0;
    }

    #endregion

    #region Public Members

    public ObservableCollection<DocumentViewModel> Documents { get; set; }

    private int _selectedIndex = 0;
    public int SelectedIndex
    {
        get { return _selectedIndex; }
        set
        {
            _selectedIndex = value;
            OnPropertyChanged();
        }
    }

    #endregion
}

【问题讨论】:

标签: c# wpf xaml mvvm binding


【解决方案1】:

当您使用CommandBinding 时,可以说您正在配置view 应该处理的命令。因此,我不清楚在视图模型中实现命令是否有意义。相反,如果视图模型应该拥有该命令,则使用 its 命令,而不是预定义的命令。

要求将ICommand 对象绑定到应用程序命令是没有意义的。 ApplicationCommands 对象本身就是 ICommand 实现! (具体来说是RoutedUICommand。)

如果您的视图模型已经为标准命令实现了ICommand,那么只需绑定到那些:

<CommandBinding Command="{Binding ExitCommand}"/>

如果您真的想使用ApplicationCommands 命令,那么您需要为Executed 和CanExecute 事件订阅一个事件处理程序方法,然后将它们委托给视图模型。例如:

<CommandBinding Command="ApplicationCommands.Close"
                Executed="Close_Executed" />

然后在代码隐藏中,像这样:

void Close_Executed(object sender, ExecutedRoutedEventArgs e)
{
    ICommand command = (ICommand)e.Parameter;

    command.Execute(null);
}

请注意,在这种情况下,您必须确保在命令本身的源中设置CommandParameter。 IE。在调用命令的InputBinding 和Button 中包含CommandParameter={Binding ExitCommand}。这可能会变得乏味。

或者,您可以假设Source 对象的DataContext 是您的视图模型,并直接从中获取命令:

void Close_Executed(object sender, ExecutedRoutedEventArgs e)
{
    EditorViewModel viewModel = (EditorViewModel)((FrameworkElement)e.Source).DataContext;
    ICommand command = viewModel.ExitCommand;

    command.Execute(e.Parameter);
}

【讨论】:

    猜你喜欢
    • 2015-11-13
    • 2012-02-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-23
    • 2011-06-21
    • 2013-08-05
    • 1970-01-01
    相关资源
    最近更新 更多