简体   繁体   中英

Custom context menu XAML for WP8

I try to implement a custom ContextMenu in a LongListSelector .

I'm not using the ContextMenu from Microsoft.Phone.Controls.Toolkit , it's basically the same as in the Rowi App:


(source: hiddenpineapple.com )

Approach 1

My list item toggles a VisualState on hold and an overlay is shown with controls in it.

The problem

I can't find a way to go back to the default state when the user clicks outside of the list item (as in the default ContextMenu).

Approach 2

I've implemented a custom template for the toolkit ContextMenu which looks exactly the same. I had to move its margin top to -itemHeight , as by default it is below the item.

The problem

The problem with this solution is, that it automatically closes itself when opening and I couldn't figure out how to avoid this.
Another problem was that it didn't work well with TiltEffect.IsTiltEnabled from the Toolkit (visual problems).

I need your help

Any suggestions on how to get this working?


Answer

Thanks to Cheese , now I know how to properly close the menu when the user clicks outside. His suggestion was to get the coordinates of a Tap event on the current page, and check if it's inside the menu. When not, close the menu.

So I added a Tap listener to the page when the menu opens, and removed it when the menu closes. From the page listener I got the event coordinates and could check if it's inside the control which holds the menu (same size and position). I received the position of the control with Point leftUpperPoint = control.TransformToVisual(page).Transform(new Point(0, 0)) and the rightLowerPoint by adding the ActualWidth and ActualHeight.

But then I realized:

Why should I even calculate if the tap is inside the menu? I always want to close the menu when the user taps anywhere on the screen. If it's outside, yes . If it's on a menu button, yes .

Another modification I made was to listen for MouseLeftButtonDown instead of Tap as it also triggers when the user swipes.

So I removed this code and came up with the following:

private void ToggleMenu(object sender, System.Windows.Input.GestureEventArgs e)
{
  PhoneApplicationFrame frame = ((PhoneApplicationFrame)Application.Current.RootVisual);
  VisualState state = this.States.CurrentState;

  if (state == null || state.Name == "DefaultState")
  {
    frame.MouseLeftButtonDown += MouseDownDelegate;
    this.State = "MenuState";
  }
  else
  {
    frame.MouseLeftButtonDown -= MouseDownDelegate;
    this.State = "DefaultState";
  }
}

private void MouseDownDelegate(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
  ToggleMenu(sender, null);
}

This works perfectly!

Thanks to Cheese for the hint.

Approach 1 problem

The best solution would be:

Get the menus coordinates, when user makes a tap - you check are tap coordinates on menu or not, if not - dissmiss - simple.

Approach 2 problem

I guess you had some button in a corner and when you tapped on it - nothing happened? And when you dissmissed the Tilt all worked. It seems that tilt works faster than a click, so, tilt changes the button coordinates, and device thiks you have missed/or dragged off

You can use what @ScottIsAFool suggested and maybe create another Dependency Property on your TapMenu control of type UIElement named CloseWhenTappedElement and automatically listen for Tap events inside your control once set. For example

<Grid x:Name="TapArea"/>
<TapMenu CloseWhenTappedElement="{Binding ElementName=TapArea"}/>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM