2016-04-04 26 views
1

WPF'yi küçük bir editör projesiyle öğrenmek ve MVVM ile tasarlayarak.WPF Bağlama Uygulama Komutları ViewModel ICommand

Aşağıdaki kod, "System.Windows.Data.Binding öğesinde değer sağla" özel bir durum oluşturmuştur. XAML ilk ayrıştırıldığında çalışma zamanında. Yapı hatası yok.

nasıl iyi Uygulama Komutları Close, Kaydet, Farklı Kaydet, Aç, Yeni benim ICommands bağlamak vb

Şu anda sadece yakın ve Yeni kurulum var.

Picture of Error Exception

XAML Kod:

<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 Kodu:

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

Sen anlamsızdır başka Komutanlığı'na Gerçekleştirilen bağlayıcıdır. Yürütülen öznitelik için bir yöntem adı sağlayın. – AnjumSKhan

cevap

0

Eğer tartışmalı sen görünüm taşıma gerektiğini komutları yapılandırırken, CommandBinding kullanıyor. Bu nedenle, görünüm modelindeki komutu uygulamak mantıklı değildir. Tersine, görünüm modelinin kendi komutu varsa, değerini komutunu kullanarak önceden tanımlanmış bir tanesini kullanmayın.

ICommand nesnesini bir uygulama komutuna bağlamak istemek mantıklı gelmiyor. ApplicationCommands nesneleri, ICommand uygulamalarının kendileridir! (RoutedUICommand, belirli olması.)

görünümünüzü model zaten standart komutlar için ICommand uygular, sonra sadece bu bağlanma:

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

Gerçekten ApplicationCommands komutlarını kullanmak istiyorsanız, o zaman size' Bir olay işleyici yöntemini Executed ve CanExecute olaylarına abone etmeli ve sonra bunları görüntü modeline delege etmeliyim. Örneğin:

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

kod arkasında, böyle bir şey: Eğer komuta kaynağında CommandParameter set bu durumda emin olmak zorundayız

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

    command.Execute(null); 
} 

Not kendisi. Yani InputBinding ve Button numaralı telefonlara CommandParameter={Binding ExitCommand} kodunu ekleyin ve komutu çağırırsınız. Bu sıkıcı olabilir.

Alternatif olarak, Source nesnenin DataContext görüşünüz modeli olduğunu varsayalım olabilir ve bu doğrudan komut almak:

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

    command.Execute(e.Parameter); 
} 
+0

Çalışmıyor, CommandBinding'in CommandParameter özelliği yok – Wouter

+0

@Wouter: teşekkürler, haklısınız. Tabii ki burada yararlı olmayan 'InputBinding' ile karıştı. –