2016-04-04 58 views
1

学习WPF与一个小型编辑器项目,并设计MVVM的考虑。WPF绑定应用程序命令ViewModel ICommand

以下代码抛出“在'System.Windows.Data.Binding'上提供值抛出异常。”在XAML首次被解析的运行时。没有生成错误。

如何最好地为我个ICommand绑定到应用程序的命令关闭,保存,另存为,打开,新建等

目前我刚才的关闭和新的安装。

Picture of Error Exception

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> 

视图模型代码:

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 
} 
+0

要绑定执行另一个命令,它是没有意义的。为Executed属性提供方法名称。 – AnjumSKhan

回答

0

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

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

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

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

如果你真的想使用ApplicationCommands命令,那么你”我们需要订阅事件处理程序方法到ExecutedCanExecute事件,然后将这些事件委托给视图模型。例如:

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

然后在后台代码,像这样:

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

    command.Execute(null); 
} 

请注意,你必须确保在这种情况下,你设置的CommandParameter在命令的源本身。即在调用该命令的InputBindingButton中包含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); 
} 
+0

不起作用,CommandBinding没有CommandParameter属性 – Wouter

+0

@Wouter:谢谢,你是对的。与'InputBinding'混淆了,这当然在这里没有用。 –