2016-04-04 25 views
1

小さなエディタプロジェクトでWPFを学習し、MVVMを考慮して設計します。WPFアプリケーションコマンドをViewModelにバインドするICommand

次のコードは、 "System.Windows.Data.Binding 'の値を提供すると例外がスローされました。実行時にXAMLが最初に解析されます。ビルドエラーはありません。現在、私はちょうど閉じ、新しいセットアップを持って最善の方法アプリケーションのコマンド閉じる、保存、名前を付けて保存、オープン、新しいなど

に私のICommandsをバインドする

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> 

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

あなたは無意味である別のコマンドに実行されるバインディングされています。 Executed属性のメソッド名を指定します。 – AnjumSKhan

答えて

0

あなたは間違いなくあなたがビューが取り扱うべきであるというコマンドを設定している、CommandBindingを使用しています。したがって、ビュー・モデルにコマンドを実装することは意味があるとは私には分かりません。逆に、ビューモデルがコマンドを所有する必要がある場合は、コマンドを使用してください。あらかじめ定義されたコマンドではありません。

ICommandオブジェクトをアプリケーションコマンドにバインドすることは頼りになりません。 ApplicationCommandsオブジェクト自体はICommand実装です! (RoutedUICommand、具体的にする。)

あなたのビューモデルが既にだけのものに結合し、標準コマンドのICommandを実装している場合:

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

あなたが本当にApplicationCommandsコマンドを使用する場合は、あなたが」 ExecutedCanExecuteイベントにイベントハンドラメソッドをサブスクライブし、それらをビューモデルに委譲する必要があります。たとえば、次のコードビハインドで次に

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

、このような何か:あなたは、コマンドのソースでCommandParameterを設定し、この場合のことを確認する必要があるだろう

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

    command.Execute(null); 
} 

注意自体。私。コマンドを呼び出すInputBindingおよびButtonCommandParameter={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'と混同しましたが、ここではあまり役に立ちません。 –

関連する問題