WPF: affichage D'un Menu contextuel pour les articles de GridView
j'ai le texte suivant GridView
:
<ListView Name="TrackListView" ItemContainerStyle="{StaticResource itemstyle}">
<ListView.View>
<GridView>
<GridViewColumn Header="Title" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Artist" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Artist.Name}" />
<GridViewColumn Header="Album" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Name}"/>
<GridViewColumn Header="Length" Width="100" HeaderTemplate="{StaticResource BlueHeader}"/>
</GridView>
</ListView.View>
</ListView>
Maintenant je voudrais afficher un menu contextuel sur clic droit sur un délimitée article qui va me permettre de récupérer l'élément sélectionné lorsque je gérer l'événement dans le code derrière.
Comment puis-je accomplir cela?
[mise à Jour]
Suivant Denis Rochele code, j'ai maintenant ceci:
<ListView Name="TrackListView" ItemContainerStyle="{StaticResource itemstyle}">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnListViewItem_PreviewMouseLeftButtonDown" />
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add to Playlist"></MenuItem>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header="Title" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Artist" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Artist.Name}" />
<GridViewColumn Header="Album" Width="100" HeaderTemplate="{StaticResource BlueHeader}" DisplayMemberBinding="{Binding Album.Name}"/>
<GridViewColumn Header="Length" Width="100" HeaderTemplate="{StaticResource BlueHeader}"/>
</GridView>
</ListView.View>
</ListView>
Mais lors de l'exécution, je suis recevoir cette exception:
ne peut pas ajouter de contenu de type 'Système.Windows.Contrôle.ContextMenu" un objet de type 'System.L'objet". Erreur à l'objet 'Système.Windows.Contrôle.ContextMenu" dans le fichier de marquage "Musicrepo_importeur; component/controls / trackgridcontrol.xaml'.
Quel est le problème?
3 réponses
Oui, ajoutez un contrôle ListView.ItemContainerStyle avec le Menu contextuel.
<ListView>
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu">
...
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnListViewItem_PreviewMouseLeftButtonDown" />
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
NOTE: vous devez référencer le ContextMenu comme une ressource et ne pouvez pas le définir localement.
permet d'activer le menu contextuel pour toute la ligne. :)
voir aussi que je gère le PreviewMouseLeftButtonDown
événement, afin de m'assurer de l'élément focalisé (et est l'élément actuellement sélectionné lorsque vous interrogez la Liste). J'ai constaté que je devais à cela lors du changement d'orientation entre les applications, ce peut-être pas dans votre cas.
mise à Jour
dans le code derrière le fichier, vous devez parcourir l'arborescence visuelle pour trouver l'élément de conteneur de liste, car la source originale de l'événement peut être un élément du modèle d'élément (par exemple, un empattement).
void OnListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.Handled)
return;
ListViewItem item = MyVisualTreeHelper.FindParent<ListViewItem>((DependencyObject)e.OriginalSource);
if (item == null)
return;
if (item.Focusable && !item.IsFocused)
item.Focus();
}
MyVisualTreeHelper
c'est utiliser un wrapper que j'ai écrit rapidement à pied de l'arbre visuel. Un sous-ensemble, est affiché en dessous.
public static class MyVisualTreeHelper
{
static bool AlwaysTrue<T>(T obj) { return true; }
/// <summary>
/// Finds a parent of a given item on the visual tree. If the element is a ContentElement or FrameworkElement
/// it will use the logical tree to jump the gap.
/// If not matching item can be found, a null reference is returned.
/// </summary>
/// <typeparam name="T">The type of the element to be found</typeparam>
/// <param name="child">A direct or indirect child of the wanted item.</param>
/// <returns>The first parent item that matches the submitted type parameter. If not matching item can be found, a null reference is returned.</returns>
public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
return FindParent<T>(child, AlwaysTrue<T>);
}
public static T FindParent<T>(DependencyObject child, Predicate<T> predicate) where T : DependencyObject
{
DependencyObject parent = GetParent(child);
if (parent == null)
return null;
// check if the parent matches the type and predicate we're looking for
if ((parent is T) && (predicate((T)parent)))
return parent as T;
else
return FindParent<T>(parent);
}
static DependencyObject GetParent(DependencyObject child)
{
DependencyObject parent = null;
if (child is Visual || child is Visual3D)
parent = VisualTreeHelper.GetParent(child);
// if fails to find a parent via the visual tree, try to logical tree.
return parent ?? LogicalTreeHelper.GetParent(child);
}
}
j'espère que cette information supplémentaire aider.
Denis
Dennis,
l'Amour l'exemple, cependant je n'ai pas trouvé tout le nécessaire pour votre Arborescence Visuelle Helper...
<ListView.Resources>
<ContextMenu x:Key="ItemContextMenu">
<MenuItem x:Name="menuItem_CopyUsername"
Click="menuItem_CopyUsername_Click"
Header="Copy Username">
<MenuItem.Icon>
<Image Source="/mypgm;component/Images/Copy.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem x:Name="menuItem_CopyPassword"
Click="menuItem_CopyPassword_Click"
Header="Copy Password">
<MenuItem.Icon>
<Image Source="/mypgm;component/Images/addclip.png" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem x:Name="menuItem_DeleteCreds"
Click="menuItem_DeleteCreds_Click"
Header="Delete">
<MenuItem.Icon>
<Image Source="/mypgm;component/Images/Delete.png" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</ListView.Resources>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu" Value="{StaticResource ItemContextMenu}" />
</Style>
</ListView.ItemContainerStyle>
puis dans les événements MenuItem_Click j'ai ajouté du code qui ressemble à ceci:
private void menuItem_CopyUsername_Click(object sender, RoutedEventArgs e)
{
Clipboard.SetText(mySelectedItem.Username);
}
mySelectedItem est utilisé sur ListView.SelectedItem:
<ListView x:Name="ListViewCreds" SelectedItem="{Binding mySelectedItem, UpdateSourceTrigger=PropertyChanged}" ....
veuillez me cocher si cela peut vous aider...
Vous pourriez être intéressé par les réponses pour ce DONC, la question - j'avais la même question mais je n'étais pas satisfait de l'utilisation de l'événement mousedown pour capturer l'article qui a été cliqué dessus. Plusieurs personnes ont répondu avec des solutions simples et faciles à comprendre qui pourraient vous intéresser.
résumé: vous pouvez utiliser le contexte de données pour passer l'élément au gestionnaire, ou un paramètre de configuration commande + Commande.