Astuces DotNet (Sébastien Courtois)

25/01/2010

[Silverlight 4] Supprimer le context menu “Silverlight” lors d’un clic droit

Filed under: Débutant, Silverlight 4, XAML — Étiquettes : , , , , , — sebastiencourtois @ 22:41

Silverlight 4 apporte une nouveauté très demandée : La gestion du clic droit. Le problème est que, par défaut, le clic droit s’accompagne d’un menu contextuel “Silverlight” un peu énervant. Toutefois, il y a une manière de s’affranchir de celui-ci.

L’évènement MouseRightButtonDown est un RoutedEvent qui, lorsqu’il est déclenché, est transmis de contrôle enfant à contrôle parent (ainsi de suite jusqu’au contrôle racine). Or, s’il arrive en haut de l’arbre visuel, il affiche par défaut le menu contextuel “Silverlight”.

1°)Une solution simple est d’indiquer que l’évènement a été géré (e.Handled = true) dans la callback de l’événement.

<UserControl x:Class="RightClickHandled.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <Rectangle Fill="Red" Width="300" Height="200" MouseRightButtonDown="Rectangle_MouseRightButtonDown"></Rectangle>
    </Grid>
</UserControl>
public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void Rectangle_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
        }
    }

Le problème de cette méthode est qu’il faut le mettre sur chacune des callbacks de MouseRightButtonDown. De plus, cela arrête la remontée de l’évenement MouseRightClickDown aux contrôles parent qui doivent peut être y réagir.

2°) Utilisation d’un behavior : Etant donné mon dernier post, je ne pouvais m’empêcher de voir si un behavior peut régler la solution…. et c’est le cas. Pour ceux qui ne connaissent pas les behaviors, vous pouvez vous référez à cette introduction sur les behaviors).

    public class EraseSilverlightContextMenuBehavior : Behavior<UIElement>
    {
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.MouseRightButtonDown += new MouseButtonEventHandler(AssociatedObject_MouseRightButtonDown);
        }

        void AssociatedObject_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            e.Handled = true;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            this.AssociatedObject.MouseRightButtonDown -= new MouseButtonEventHandler(AssociatedObject_MouseRightButtonDown);
        }
    }

Après on associé le behavior au contrôle et le tour est joué.

<UserControl x:Class="RightClickHandled.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:local="clr-namespace:RightClickHandled"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <Rectangle Fill="Red" Width="300" Height="200">
            <i:Interaction.Behaviors>
                <local:EraseSilverlightContextMenuBehavior />
            </i:Interaction.Behaviors>
        </Rectangle>
    </Grid>
</UserControl>

Le soucis avec cette méthode est qu’il faut appliquer le behavior à tous les contrôles ce qui peut devenir lourd.

3°)La solution la plus générique serait de s’abonner à l’événement MouseRightButtonDown du RootVisual contenu dans le App.xaml.cs afin de bloquer l’événement juste afin sa sortie de l’arbre visuel.

private void Application_Startup(object sender, StartupEventArgs e)
{
    this.RootVisual = new MainPage();
    this.RootVisual.MouseRightButtonDown += (sender2, args) => { args.Handled = true; };
}

Ainsi tous les contrôles de l’arbre visuel peuvent avoir accès à l’évènement sans contrainte. Plus besoin de l’implémenter sur chacun des contrôles car cela est géré au niveau de la racine de l’arbre.

Si vous avez des méthodes plus smart pour faire cela, n’hésitez pas à me les indiquer :).

Publicités

Propulsé par WordPress.com.

%d blogueurs aiment cette page :