Question

I am writing a Silverlight for Windows Phone 7.5 app.

I want to reference the ContextMenu inside my LongListSelector because I want to set .IsOpen to false as soon as the ContextMenu Click event is called. My thought was that this should happen automatically but it does not.

One of my MenuItem's sets the visibility of a <Grid> from collapsed to visible which mimics a PopUp. Whilst the code executes fine and the Visibility does indeed change. The UI of the app does not show the Grid unless the ContextMenu closes.

My XAML of the LongListSelector which contains a ContextMenu called Menu that I wish to reference in the ContextMenuItem Click event.

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

My code behind ContextMenuItem Click event

  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
        }

   }

I set the ItemSource of the ContextMenu in the ContextMenu_Opened event. The fields are both of 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;
        }
    }
Was it helpful?

Solution

Not sure why the ContextMenu is not closing, but here are two solutions. The first is to get the parent of the 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;
}

Then get the Menu from your click handler

var menu = GetParentOfType<ContextMenu>(sender as MenuItem);
menu.IsOpen = false;

The second solution is to bind IsOpen to a backing viewmodel

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

Change your open event:

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);
    }
}

Then a viewmodel

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));
        }
    }
}

Then set the IsOpen property of your ViewModel to false;

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top