2009-08-15 13 views
6

Ho una classe statica che contiene un RoutedUICommand che vorrei usare nel binding.Collegamento a un RoutedUICommand che non è nel codebehind

public static class CommandLibrary 
{ 
    public static ProjectViewModel Project { get; set; } 

    public static RoutedUICommand AddPage { get; private set; } 

    static CommandLibrary() 
    { 
     AddPage = new RoutedUICommand("AddPage", "AddPage", typeof(CommandLibrary)); 

    } 

    public static void AddPage_Executed(object sender, ExecutedRoutedEventArgs args) 
    { 
     Project.AddPage(); 
    } 

    public static void AddPage_CanExecute(object sender, CanExecuteRoutedEventArgs args) 
    { 
     // We need a project before we can add pages. 
     if (Project != null) 
     { 
      args.CanExecute = true; 
     } 
     else 
     { 
      // Did not find project, turning Add Page off. 
      args.CanExecute = false; 
     } 
    } 
} 

Quando si tenta di creare un CommandBinding per questo comando AddPage, VS fa i capricci, lamentando che non riesce a trovare AddPage_CanExecute in Window1 ... che non ha senso se si considera che tutti gli esempi che ho visto indica questo XAML dovrebbe andare bene considerando il codice che ho posto:

<Window x:Class="MyProject.Window1" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:MyProject"> 
    <Menu> 
     <Menu.CommandBindings> 
      <CommandBinding Command="local:CommandLibrary.AddPage" 
          Executed="AddPage_Executed" CanExecute="AddPage_CanExecute" /> 
     </Menu.CommandBindings> 
     <MenuItem Header="_Page"> 
      <MenuItem Header="_New" Command="local:CommandLibrary.AddPage" /> 
     </MenuItem> 
    </Menu> 
</Window> 

ho anche provato non inclusa la sezione Menu.CommandBindings e semplicemente usando questa (come da this question che suggerisce questo, ma non è specifico):

<MenuItem Header="_New" Command="{x:Static local:CommandLibrary.AddPage}" /> 

Questo ha bloccato il flusso di errori ma la voce di menu che genera è sempre disabilitata! CanExecute non sembra mai essere chiamato. Suppongo che l'associazione stia fallendo anche in questo caso, anche se più tranquillamente.

Perché VS odia il mio comando e si rifiuta di cercare nel posto giusto per trovare i metodi Executed e CanExecute? Ho visto un certo numero di esempi (in Pro WPF di Matthew McDonald e su diversi tutorial di comando personalizzati online) che hanno fatto ciò mentre lo sto facendo.

risposta

11

A CommandBinding è proprio come qualsiasi altro elemento nella struttura visiva. Tutti gli eventi specificati su di esso verranno gestiti dalla radice del tuo albero visivo (il tuo Window in questo caso). Ciò significa che se sposti AddPage_Executed e AddPage_CanExecute nel codice della tua finestra, funzionerà. Ciò consente di utilizzare lo stesso comando in molti componenti dell'interfaccia utente, ma con gestori diversi.

Vedo, tuttavia, che il comando esegue una logica contro il modello di visualizzazione. Per farti risparmiare tempo e frustrazione, comprendi che i comandi indirizzati sono la soluzione sbagliata qui. Invece, incapsulare il vostro comando in vista del modello qualcosa di simile:

public class ProjectViewModel 
{ 
    private readonly ICollection<PageViewModel> _pages; 
    private readonly ICommand _addPageCommand; 

    public ProjectViewModel() 
    { 
     _pages = new ObservableCollection<PageViewModel>(); 
     _addPageCommand = new DelegateCommand(AddPage); 
    } 

    public ICommand AddPageCommand 
    { 
     get { return _addPageCommand; } 
    } 

    private void AddPage(object state) 
    { 
     _pages.Add(new PageViewModel()); 
    } 
} 

Un DelegateCommand è un'implementazione di ICommand che richiama i delegati di eseguire e interrogare il comando. Ciò significa che la logica di comando è racchiusa nel comando e non è necessario un CommandBinding per fornire gestori (non è necessario un valore CommandBinding). Quindi, la visualizzazione solo si lega al vostro VM come segue:

<MenuItem Header="_New" Command="{Binding AddPageCommand}"/> 

vi consiglio di leggere attraverso questa serie di post per darvi più contesto:

+0

Ottima risposta. Mi ha preso quello di cui avevo bisogno. Ho letto alcuni tutorial di MVVM e ho visto questo tipo di uso del comando prima, ma non riuscivo a ricordare come farlo, quindi ho fatto ricorso alle soluzioni che ho trovato nei miei libri e tramite la ricerca. Grazie per l'aiuto. – evizaer

+0

Bellissima. Stavo sbattendo la testa su questo ... imparare wpf + mvvm non è così semplice come vorrei. RoutedUIC indicava dove troppo complesso per quello che intendevo e sapevo che ci dovrebbe essere un modo più semplice. @Kent, grazie per i tuoi esempi e blog. –

Problemi correlati