2016-04-04 56 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'混淆了,這當然在這裏沒有用。 –