WP7: Suppressing XNA touch input when handled by Silverlight?
I've got an XNA + Silverlight game in Mango: Mostly XNA with some Silverlight UI on top. The problem I'm having is that when you hit a b开发者_JS百科utton or interact with a Silverlight control, the touch information is still passed along to the XNA game loop. How do you suppress this?
Wrote up a class to do the tracking for me. After your page loads (in the Loaded handler), create this and give it the root element (so it can attach to the LayoutUpdated event). Register any controls that might overlay the game surface during play. Then just call TouchesControl and pass in the touch position to find out if you should ignore that point or not. It caches the regions of the controls and updates them when there's a layout update.
Should work for rectangular elements moving, changing size or collapsing/expanding.
public class ControlTouchTracker
{
private List<FrameworkElement> controls = new List<FrameworkElement>();
private Dictionary<FrameworkElement, ControlRegion> controlBounds = new Dictionary<FrameworkElement, ControlRegion>();
public ControlTouchTracker(FrameworkElement rootElement)
{
rootElement.LayoutUpdated += this.OnLayoutUpdated;
}
public void RegisterControl(FrameworkElement control)
{
controls.Add(control);
}
public void RemoveControl(FrameworkElement control)
{
controls.Remove(control);
controlBounds.Remove(control);
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
foreach (Control control in this.controls)
{
this.RefreshControlBounds(control);
}
}
private void RefreshControlBounds(FrameworkElement control)
{
if (this.ControlIsVisible(control))
{
try
{
GeneralTransform controlTransform = control.TransformToVisual(Application.Current.RootVisual);
Point offset = controlTransform.Transform(new Point(0, 0));
this.controlBounds[control] = new ControlRegion
{
Left = (float)offset.X,
Right = (float)(offset.X + control.ActualWidth),
Top = (float)offset.Y,
Bottom = (float)(offset.Y + control.ActualHeight)
};
}
catch (ArgumentException)
{
}
}
else
{
if (this.controlBounds.ContainsKey(control))
{
this.controlBounds.Remove(control);
}
}
}
private bool ControlIsVisible(FrameworkElement control)
{
// End case
if (control == null)
{
return true;
}
if (control.Visibility == Visibility.Collapsed)
{
return false;
}
return this.ControlIsVisible(control.Parent as FrameworkElement);
}
public bool TouchesControl(Vector2 touchPosition)
{
foreach (ControlRegion region in this.controlBounds.Values)
{
if (touchPosition.X >= region.Left && touchPosition.X <= region.Right &&
touchPosition.Y >= region.Top && touchPosition.Y <= region.Bottom)
{
return true;
}
}
return false;
}
public class ControlRegion
{
public float Left { get; set; }
public float Right { get; set; }
public float Top { get; set; }
public float Bottom { get; set; }
}
}
(edit) Updated example to work with parent elements changing Visibility
.
Due to the way interop with XNA works, you will always get the touch input processed both by XNA and Silverlight - to some extent, XNA gets the priority, so the Silverlight acts on top of that. What you could do, if you need to ignore specific gesture locations (e.g. where Silverlight buttons are located), you could check the gesture position:
if (TouchPanel.IsGestureAvailable)
{
if (TouchPanel.ReadGesture().GestureType == GestureType.Tap)
{
if (TouchPanel.ReadGesture().Position == new Vector2(120, 120))
{
}
}
}
精彩评论