2011-01-07 8 views
8

Sto tentando di utilizzare un comportamento collegato per eseguire un comando nel mio ViewModel quando il doppio clic dell'utente sulla voce di elenco.Comportamento allegato per eseguire il comando per ListViewItem

Ho esaminato una serie di articoli sull'argomento e ho provato a creare una semplice applicazione di test ma ho ancora problemi ad es. Firing a double click event from a WPF ListView item using MVVM

mio semplice ViewModel test ha 2 collezioni, quella che restituisce una lista di stringhe e l'altro che restituisce un elenco dei tipi ListViewItem

public class ViewModel 
{ 
    public ViewModel() 
    { 
     Stuff = new ObservableCollection<ListViewItem> 
        { 
         new ListViewItem { Content = "item 1" }, 
         new ListViewItem { Content = "item 2" } 
        }; 

     StringStuff = new ObservableCollection<string> { "item 1", "item 2" }; 
    } 

    public ObservableCollection<ListViewItem> Stuff { get; set; } 

    public ObservableCollection<string> StringStuff { get; set; } 

    public ICommand Foo 
    { 
     get 
     { 
      return new DelegateCommand(this.DoSomeAction); 
     } 
    } 

    private void DoSomeAction() 
    { 
     MessageBox.Show("Command Triggered"); 
    } 
} 

Ecco la proprietà associata che è come may altri esempi vedi:

public class ClickBehavior 
{ 
    public static DependencyProperty DoubleClickCommandProperty = DependencyProperty.RegisterAttached("DoubleClick", 
       typeof(ICommand), 
       typeof(ClickBehavior), 
       new FrameworkPropertyMetadata(null, new PropertyChangedCallback(ClickBehavior.DoubleClickChanged))); 

    public static void SetDoubleClick(DependencyObject target, ICommand value) 
    { 
     target.SetValue(ClickBehavior.DoubleClickCommandProperty, value); 
    } 

    public static ICommand GetDoubleClick(DependencyObject target) 
    { 
     return (ICommand)target.GetValue(DoubleClickCommandProperty); 
    } 

    private static void DoubleClickChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) 
    { 
     ListViewItem element = target as ListViewItem; 
     if (element != null) 
     { 
      if ((e.NewValue != null) && (e.OldValue == null)) 
      { 
       element.MouseDoubleClick += element_MouseDoubleClick; 
      } 
      else if ((e.NewValue == null) && (e.OldValue != null)) 
      { 
       element.MouseDoubleClick -= element_MouseDoubleClick; 
      } 
     } 
    } 

    static void element_MouseDoubleClick(object sender, MouseButtonEventArgs e) 
    { 
     UIElement element = (UIElement)sender; 
     ICommand command = (ICommand)element.GetValue(ClickBehavior.DoubleClickCommandProperty); 
     command.Execute(null); 
    } 
} 

Nella mia finestra principale, ho definito lo stile che definisce il comportamento allegato e si lega al comando Foo

0.123.516,41 mila
<Window.Resources> 
    <Style x:Key="listViewItemStyle" TargetType="{x:Type ListViewItem}"> 
     <Setter Property="local:ClickBehavior.DoubleClick" Value="{Binding Foo}"/>     
    </Style> 
</Window.Resources> 

funziona bene quando ListViewItems sono definiti:

<!-- Works --> 
<Label Grid.Row="2" Content="DoubleClick click behaviour:"/>   
<ListView Grid.Row="2" Grid.Column="1" ItemContainerStyle="{StaticResource listViewItemStyle}"> 
    <ListViewItem Content="Item 3" /> 
    <ListViewItem Content="Item 4" /> 
</ListView> 

Questo funziona anche quando si lega alla lista di tipo ListViewItem:

<!-- Works when items bound are of type ListViewItem --> 
<Label Grid.Row="3" Content="DoubleClick when bound to ListViewItem:"/>   
    <ListView Grid.Row="3" Grid.Column="1" ItemContainerStyle="{StaticResource listViewItemStyle}" ItemsSource="{Binding Stuff}">   
</ListView> 

Ma questo non lo fa:

<!-- Does not work when items bound are not ListViewItem --> 
<Label Grid.Row="4" Content="DoubleClick when bound to string list:"/> 
    <ListView Grid.Row="4" Grid.Column="1" ItemContainerStyle="{StaticResource listViewItemStyle}" ItemsSource="{Binding StringStuff}"> 
</ListView> 

Nella finestra di output viene visualizzato l'errore, ma è difficile capire cosa è sbagliato.
Errore System.Windows.Data: 39: errore percorso BindingExpression: proprietà 'Foo' non trovata su 'oggetto' '' String '(HashCode = 785742638)'. BindingExpression: Path = Foo; DataItem = 'String' (HashCode = 785742638); l'elemento target è 'ListViewItem' (Name = ''); indirizzare proprietà è 'DoubleClick' (tipo 'ICommand')

Quindi il mio quesion è: come si può ottenere il comando cablata correttamente per ogni ListViewItem quando si associa il vostro ListView a un elenco di oggetti del modello?

Grazie.

+0

Questo è stato molto utile! Per maggiore riusabilità, ho modificato ListViewItem element = target come ListViewItem; a Control element = target come Control; –

risposta

8

Il problema è che DataContext per Binding è la stringa. Poiché non esiste la proprietà Foo della classe string, si sta verificando un errore. Questo non accade negli altri casi perché ereditano il loro DataContext dal genitore (questo non accade per i contenitori generati automaticamente per gli elementi di dati - il loro DataContext è l'elemento di dati).

Se si cambia il legame di utilizzare la s DataContext genitore ListView', dovrebbe funzionare bene:

Value="{Binding DataContext.Foo, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" 
+0

Grazie per la rapida risposta, Abe. Sei una star, hai cercato di capirlo per troppo tempo. –

+1

Nessun problema Paul. Gli errori di binding sono davvero criptici e a volte basta un nuovo paio di occhi per vedere cosa sta succedendo! –

Problemi correlati