Potlačení výchozí Context nabídky v Silverlight 4

Jan Holan       02.01.2011       Silverlight       10798 zobrazení

V Silverlight aplikacích se na pravé tlačítko myši kdekoliv v aplikaci zobrazí contextová nabídka s volbou Silverlight , která volá nastavení pluginu (a případně jsou v nabídce ještě další volby týkající se OutOfBrowser funkcí jako nainstalování aplikace na počítač). Silverlight od verze 4 umožňuje toto výchozí chování změnit, je možné odchytit stisk pravého tlačítka myší a provést vlastní akci, typicky to může být zobrazení vlastní nabídky, nebo potlačení té výchozí.

Kód na potlačení nabídky pak konkrétně vypadá takto:

/// <summary>
/// Zákládní control aplikace
/// </summary>
public partial class MainPage : UserControl, IDisposable
{
    /// <summary>
    /// MainPage constructor
    /// </summary>
    public MainPage()
{ InitializeComponent(); //Disable Silverlight ContextMenu this.MouseRightButtonDown += (sender, e) => e.Handled = true; } }

Kód zobrazuje odchycení události MouseRightButtonDown a nastavení Handled na true v konstruktoru hlavní stránky aplikace.

Věci ale nejsou takto jednoduché, po spuštění aplikace se sice správně zablokovala nabídka na této stránce MainPage, ale pokud např. zobrazíme Popup, je opět možné Silverlight nabídku vyvolat. To je způsobeno tím, že každý Popup není ve visual stromu umístěn pod root element stránky MainPage, ale má svůj vlastní root. O to zajímavější je ještě případ, pokud máme na stránce libovolný ComboBox, po jeho rozevření je opět možné vyvolat výchozí nabídku, to je způsobeno tím, že součástí Comboboxu je pro jeho dropdown použit právě Popup.

Řešení, které používám je rozšíření Popup pomoci behavior třídy, ve které se provede zablokování právého tlačítka myši jako na hlavní stránce. Kód PopupBehavior třídy vypadá takto:

using System;
using System.Windows.Controls.Primitives;
using System.Windows.Interactivity;

namespace IMP.Windows.Interactivity
{
    /// <summary>
    /// Disable Silverlight context menu on Right mouse click on popup
    /// </summary>
    public class PopupBehavior : Behavior<Popup>
    {
        #region action methods
        /// <summary>
        /// Overrides OnAttached
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();
            this.AssociatedObject.Opened += new EventHandler(Popup_Opened);
        }

        /// <summary>
        /// Overrides OnDetaching
        /// </summary>
        protected override void OnDetaching()
        {
            this.AssociatedObject.Opened -= new EventHandler(Popup_Opened);
            base.OnDetaching();
        }
        #endregion

        #region private member functions
        /// <summary>
        /// Overrides Invoke
        /// </summary>
        private void Popup_Opened(object sender, EventArgs e)
        {
            this.AssociatedObject.Child.MouseRightButtonDown += (s, args) => args.Handled = true;
        }
        #endregion
    }
}

Namespace System.Windows.Interactivity je v assembly System.Windows.Interactivity.dll, která je součástí Blend 4 SDK a rozšiřuje Silverlight o Behavior a EventTrigger funkcionalitu.

V XAML pak každé použití Popup elementu rozšíříme o připojení objektu PopupBehavior do Behaviors sekce:

<Popup x:Name="Popup" >
    <Border ....
    <i:Interaction.Behaviors>
        <interactivity:PopupBehavior />
    </i:Interaction.Behaviors>
</Popup>

Aby jsme “opravili” zmíněný ComboBox provedeme stejnou úpravu popupu ve style pro ComboBox control. Nejjednodušší možnost jak toto udělat je pomoci Blendu, volbou Edit Template/Edit a Copy si necháme vygenerovat style výchozího comboboxu a Popup v dolní části rozšíříme. Dále pak stylu umažeme Key atribut tím bude style použit pro všechny ComboBoxy v aplikaci. (Pozn.: Pokud style pak budete z Blendu kopírovat do aplikace nezapomeňte zkopírovat i ValidationToolTipTemplate, který se pro style také vytvoří.)

<Style TargetType="ComboBox" >
    ...
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ComboBox" xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">
                <Grid>
                    <Grid.Resources>...
                    <vsm:VisualStateManager.VisualStateGroups>...
                    <Border ...
                    <Rectangle x:Name="DisabledVisualElement" RadiusX="3" RadiusY="3" Fill="White" Opacity="0" IsHitTestVisible="false"  />
                    <Rectangle x:Name="FocusVisualElement" RadiusX="2" RadiusY="2" Margin="1" Stroke="#FF6DBDD1" StrokeThickness="1" Opacity="0" IsHitTestVisible="false"  />
                    <Border ...
                    <Popup x:Name="Popup" >
                        <Border x:Name="PopupBorder" HorizontalAlignment="Stretch" Height="Auto" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="3">
                            <Border.Background>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFFFFFFF" Offset="0" />
                                    <GradientStop Color="#FFFEFEFE" Offset="1" />
                                </LinearGradientBrush>
                            </Border.Background>
                            <ScrollViewer x:Name="ScrollViewer" BorderThickness="0" Padding="1">
                                <ItemsPresenter />
                            </ScrollViewer>
                        </Border>
                        <i:Interaction.Behaviors>
                            <interactivity:PopupBehavior />
                        </i:Interaction.Behaviors>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Pokud Popup element tvoříte v kódu a není uveden v XAML, je možné provést odchycení MouseRightButtonDown popup child elementu pomoci následujícího kódu:

var popup = new Popup();
popup.Child = panel;

//Disable Silverlight context menu on Right mouse click
popup.Child.MouseRightButtonDown += (s, args) => args.Handled = true;

Toto řešení bylo inspirováno těmito články:
http://stackoverflow.com/questions/3828514/disable-right-click-silverlight-popup-in-comboboxes
http://forums.silverlight.net/forums/t/187372.aspx
http://www.dotnetfunda.com/articles/article802-silverlight-4-how-to-use-the-all-new-right-click-contex...

 

hodnocení článku

0 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback