Référencement d'un ContextMenu lié aux données dans un modèle d'élément LongListSelector - Windows Phone
Question
J'écris une application Silverlight pour Windows Phone 7.5.
Je souhaite référencer le ContextMenu dans mon LongListSelector car je souhaite définir .IsOpen
à false
dès que le ContextMenu Click
l'événement est appelé.Je pensais que cela devrait se produire automatiquement, mais ce n'est pas le cas.
L'un de mes MenuItem définit la visibilité d'un <Grid>
depuis collapsed
à visible
qui imite un PopUp.Alors que le code s'exécute correctement et que la visibilité change effectivement.L'interface utilisateur de l'application n'affiche pas la grille à moins que le ContextMenu ne se ferme.
Mon XAML du LongListSelector
qui contient un ContextMenu
appelé Menu
que je souhaite référencer dans l'événement ContextMenuItem Click.
<toolkit:LongListSelector x:Name="moviesLongList" Background="Transparent" IsFlatList="False" GroupHeaderTemplate="{StaticResource GroupHeaderTemplate}" GroupItemTemplate="{StaticResource GroupItemTemplate}" SelectionChanged="moviesLongList_SelectionChanged" GroupViewClosing="moviesLongList_GroupViewClosing" GroupViewOpened="moviesLongList_GroupViewOpened">
<toolkit:LongListSelector.GroupItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</toolkit:LongListSelector.GroupItemsPanel>
<toolkit:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Height="91" Margin="20,0,0,20" Orientation="Horizontal">
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu x:Name="Menu" Opened="ContextMenu_Opened" Loaded="Menu_Loaded" Unloaded="Menu_Unloaded">
<toolkit:ContextMenu.ItemTemplate>
<DataTemplate>
<toolkit:MenuItem Header="{Binding}" Click="ContextMenuButton_Click" LostFocus="MenuItem_LostFocus" />
</DataTemplate>
</toolkit:ContextMenu.ItemTemplate>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Border HorizontalAlignment="Left" Width="61" Height="91" Background="{Binding ID, Converter={StaticResource ThumbImageConvert}}" />
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" Width="395">
<TextBlock x:Name="titleTextBox" Text="{Binding Title, Converter={StaticResource TitleConvert}}" Margin="6,0,6,0" d:LayoutOverrides="Width" FontSize="{StaticResource PhoneFontSizeLarge}" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<TextBlock x:Name="yearTextBox" Text="{Binding Year}" Margin="12,0,0,0" HorizontalAlignment="Left" FontSize="{StaticResource PhoneFontSizeMedium}" Foreground="{StaticResource PhoneSubtleBrush}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</toolkit:LongListSelector.ItemTemplate>
</toolkit:LongListSelector>
Mon code derrière l'événement ContextMenuItem Click
private void ContextMenuButton_Click(object sender, RoutedEventArgs e)
{
//
// This is where I want to set Menu.IsOpen = false to close the ContextMenu.
//
if ((sender as MenuItem).Header.ToString() == "lend movie")
{
DisableAppBarIcons();
LendPopUpOverlay.Visibility = System.Windows.Visibility.Visible;
}
if ((sender as MenuItem).Header.ToString() == "return to collection")
{
... Do stuff
}
if ((sender as MenuItem).Header.ToString() == "add to boxset")
{
... Do stuff
}
if ((sender as MenuItem).Header.ToString() == "delete")
{
... Do stuff
}
}
J'ai défini le ItemSource du ContextMenu dans le ContextMenu_Opened
événement.Les champs sont tous deux de type List<String>
.
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
LentMovieObj = (sender as ContextMenu).DataContext as Movies;
if (LentMovieObj.IsLent)
{
(sender as ContextMenu).ItemsSource = menuItemsReturn;
}
else
{
(sender as ContextMenu).ItemsSource = menuItemsLendOut;
}
}
La solution
Je ne sais pas pourquoi le ContextMenu ne se ferme pas, mais voici deux solutions.La première consiste à obtenir le parent du MenuItem.
private T GetParentOfType<T>(DependencyObject obj) where T : class
{
if (obj == null) return null;
var parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
if (parent is T) return parent as T;
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
Ensuite, récupérez le menu de votre gestionnaire de clics
var menu = GetParentOfType<ContextMenu>(sender as MenuItem);
menu.IsOpen = false;
La deuxième solution consiste à lier IsOpen à un modèle de vue de support
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu x:Name="Menu" Opened="ContextMenu_Opened" Loaded="Menu_Loaded" Unloaded="Menu_Unloaded" IsOpen="{Binding IsOpen}" ItemsSource="{Binding Items}">
<toolkit:ContextMenu.ItemTemplate>
<DataTemplate>
<toolkit:MenuItem Header="{Binding}" Click="ContextMenuButton_Click" LostFocus="MenuItem_LostFocus" />
</DataTemplate>
</toolkit:ContextMenu.ItemTemplate>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
Changez votre événement ouvert :
private void ContextMenu_Opened(object sender, RoutedEventArgs e)
{
LentMovieObj = (sender as ContextMenu).DataContext as Movies;
if (LentMovieObj.IsLent)
{
(sender as ContextMenu).DataContext = new ContextMenuViewModel(menuItemsReturn);
}
else
{
(sender as ContextMenu).DataContext = ContextMenuViewModel(menuItemsLendOut);
}
}
Puis un modèle de vue
public class ContextMenuViewModel : INotifyPropertyChanged
{
private bool _isOpen = true;
public ContextMenuViewModel(IEnumerable<string> items)
{
Items = items;
}
public event PropertyChangedEventHandler PropertyChanged;
public bool IsOpen
{
get { return _isOpen; }
set { _isOpen = value; OnPropertyChanged("IsOpen"); }
}
public IEnumerable<String> Items { get; set; }
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Définissez ensuite la propriété IsOpen de votre ViewModel sur false ;