Silverlight 4 - Kontextové menu

[Sledujte také náš twitter @Aglightcz, kde naleznete krátké zprávy nejen o novinkách na našem webu]

Podpora pravého tlačítka myši je zastoupena dvěma událostmi (events), které se dají vyvolat na všech elementech typu UIElements. Těmito událostmi jsou:

  • MouseRightButtonDown
  • MouseRightButtonUp


Obě tyto události jsou tzv. Routed events a tedy jsou podobné událostem kliknutí levého tlačítka myši.

Abychom mohli událost kliknutí tlačítka obsloužit je nutné tuto událost zastavit před dalším “probubláváním” ve vizuálním stromě. Toho docílíme pomocí vlastnosti Handled, kterou nastavíme na true. Tím zaručíme to, že se nám nebude objevovat standardní kontextové menu. Kontextové menu je otevřeno právě při události MouseRightButtonDown, což se liší od WPF, kde kontextové menu bylo vyvoláno při události MouseRightButtonUp. V události MouseRightButtonUp nastavíme naše kontextové menu.

 

Omezení

V Silverlight SDK neexistuje žádná třída, která by implementovala kontextové menu. To ovšem neznamená, že by zde neexistoval způsob jak si takové menu vytvořit. Pro účely kontextového menu můžeme použít komponentu Popup. Pakliže chceme sáhnout po hotovém řešení, je vhodnou volbou komponenta ContextMenu z balíku Silverlight toolkit. A při troše hledání lze na internetu najít další kontextová menu, která jsou šířena zdarma.

Ukázka

V následující ukázce budeme nahrazovat standardní menu vlastním. Jako kontextové menu použijeme komponentu Popup.

Vytvořme tedy nový projekt a do něj vložme komponentu Popup. Vizuální obsah si můžeme zvolit libovolně, ale viditelnost prvku (Visibility) nastavíme na Collapsed. Nechceme, aby prvek byl viditelný dokud ho nevyvoláme pravým tlačítkem. XAML kód by mohl vypadat například takhle:

 

<Grid x:Name="LayoutRoot" Background="AliceBlue" >
        <Popup x:Name="ContextMenu" Visibility="Collapsed">
            <Border Background="Bisque" BorderBrush="Azure" BorderThickness="1"  >
                <Border.Effect>
                    <DropShadowEffect Color="Bisque" ShadowDepth="2" />
                </Border.Effect>
                <StackPanel>
                    <HyperlinkButton NavigateUri="#" Content="Item#1" />
                    <HyperlinkButton NavigateUri="#" Content="Item#1" />
                </StackPanel>
            </Border>
       </Popup>
    </Grid>


 

Nyní modifikujme XAML kód tak, že prvku Grid přidáme dvě události – MouseRightButtonDown a MouseRightButtonUp:

<Grid x:Name="LayoutRoot" Background="AliceBlue" 
          MouseRightButtonDown="LayoutRoot_MouseRightButtonDown"
          MouseRightButtonUp="LayoutRoot_MouseRightButtonUp">
        <Popup x:Name="ContextMenu" Visibility="Collapsed" IsOpen="False">
            <Border Background="Bisque" BorderBrush="Azure" BorderThickness="1"  >
                <Border.Effect>
                    <DropShadowEffect Color="Bisque" ShadowDepth="2" />
                </Border.Effect>
                <StackPanel>
                    <HyperlinkButton NavigateUri="#" Content="Item#1" />
                    <HyperlinkButton NavigateUri="#" Content="Item#1" />
                </StackPanel>
            </Border>
       </Popup>
    </Grid>


 

Přepneme se do aplikačního kódu (Code behind), kde v metodě MouseRightButtonDown nastavíme vlastnost Handled na hodnotu true. Tím si zajistíme to, že se nám nebude zobrazovat konfigurační menu Silverlightu.

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


Nyní je potřeba upravit metodu MouseRightButtonUp, která bude zavolána následně za metodou MouseRightButtonDown. Popis jednotlivých částí je uveden v komentářích.

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

    //Nastavíme kontextové menu na viditelné
    ContextMenu.Visibility = Visibility.Visible;
    ContextMenu.IsOpen = true;

    //Nastavíme pozici kontextového menu
    ContextMenu.Margin = new Thickness(e.GetPosition(LayoutRoot).X,
                                        e.GetPosition(LayoutRoot).Y, 
                                        0, 0);

    //V případě levého kliknutí mimo menu, menu zavři
    LayoutRoot.MouseLeftButtonDown += (s, args) =>
        {
            ContextMenu.Visibility = Visibility.Collapsed;
            ContextMenu.IsOpen = false;
        };
}

 

Výsledná aplikace

Get Microsoft Silverlight

Ukázka #2

Jen pro úplnost zde uvedu kód, který by se postaral o vyvolání kontextového menu uvnitř RichText Boxu.

XAML kód:

<Grid x:Name="LayoutRoot" Background="White">
    <RichTextBox x:Name="rtb" Height="300" Width="300" Background="AliceBlue" 
                    MouseRightButtonDown="rtb_MouseRightButtonDown" 
                    MouseRightButtonUp="rtb_MouseRightButtonUp" />
    <Popup x:Name="ContextMenu" Visibility="Collapsed">
        <Border CornerRadius="5" BorderBrush="White" BorderThickness="1" Background="Black">
            <StackPanel >
                <HyperlinkButton x:Name="Weight" IsEnabled="True" Visibility="Visible"  
                                    Content="Font Weight" Foreground="White" 
                                    Click="Weight_Click"/>
                <HyperlinkButton x:Name="Style" Content="Font Style" Foreground="White" 
                                    Click="Style_Click"/>
            </StackPanel>
        </Border>
    </Popup>
</Grid>

 

Aplikační kód:

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

private void rtb_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
    if (rtb.Selection.Text.Length > 0)
    {
        e.Handled = true;
        //Nastavíme kontextové menu na viditelné
        ContextMenu.Visibility = Visibility.Visible;
        ContextMenu.IsOpen = true;

        //Nastavíme pozici kontextového menu
        ContextMenu.VerticalAlignment = VerticalAlignment.Top;
        ContextMenu.HorizontalAlignment = HorizontalAlignment.Left;
        ContextMenu.Margin = new Thickness(e.GetPosition(LayoutRoot).X,
                                            e.GetPosition(LayoutRoot).Y, 0, 0);

        //Vytvoříme canvas, který bude obsluhovat událost kliknutí levého tlačítka
        Canvas canvas = new Canvas();
        canvas.Background = new SolidColorBrush(Colors.Transparent);
        canvas.MouseLeftButtonDown += (s, args) =>
        {
            ContextMenu.IsOpen = false;
            LayoutRoot.Children.Remove(canvas);
        };
        canvas.MouseRightButtonDown += (s, args) => 
        { 
            rtb_MouseRightButtonDown(s, args); 
            ContextMenu.IsOpen = false; 
            LayoutRoot.Children.Remove(canvas); 
        };
        LayoutRoot.Children.Add(canvas);

    }
}


private void Weight_Click(object sender, RoutedEventArgs e)
{
    if (rtb.Selection.GetPropertyValue(Run.FontWeightProperty) is FontWeight &&
       ((FontWeight)rtb.Selection.GetPropertyValue(Run.FontWeightProperty)) == FontWeights.Normal)
        rtb.Selection.ApplyPropertyValue(Run.FontWeightProperty, FontWeights.Bold);
    else
        rtb.Selection.ApplyPropertyValue(Run.FontWeightProperty, FontWeights.Normal);
    //Zavři kontextové menu
    ContextMenu.IsOpen = false;
}

private void Style_Click(object sender, RoutedEventArgs e)
{
    if (rtb.Selection.GetPropertyValue(Run.FontStyleProperty) is FontStyle &&
       ((FontStyle)rtb.Selection.GetPropertyValue(Run.FontStyleProperty)) == FontStyles.Normal)
        rtb.Selection.ApplyPropertyValue(Run.FontStyleProperty, FontStyles.Italic);
    else
        rtb.Selection.ApplyPropertyValue(Run.FontStyleProperty, FontStyles.Normal);
    //Zavři kontextové menu
    ContextMenu.IsOpen = false;
}

 

Pokud v aplikaci nemáme vybranou žádnou část textu, pak se kontextové menu nezobrazí. V kontextovém menu máme možnost změnit tloušťku(weight) a styl(style) písma. Zajímavou věcí na tomto kódu je vytvoření canvasu, který je transparentní. Tento canvas je tam z toho důvodu, že RichText box obsluhuje událost levého tlačítka myši. Nejjednodušší způsob jak reagovat na stisk levého tlačítka uvnitř RichText boxu je vytvoření canvasu, který bude implementovat událost stisku levého tlačítka. Při zavření kontextového menu se i canvas zruší.

Výsledná aplikace

Get Microsoft Silverlight

 

Shrnutí

  • Podpora pravého tlačítka myši v rámci událostí MouseRightButtonDown a MouseRightButtonUp
  • Nutné nastavit vlastnost Handled na true v události MouseRightButtonDown
  • V metodě MouseRightButtonUp voláme vlastní kontextové menu
  • K tvorbě kontextového menu lze použít komponentu Popup, ze Silverlight Toolkitu hotovou komponentu ContextMenu apod.
  • Lze použít na všechny elementy typu UIElements

 

Ohodnoťte článek: starstarstarstarstar

Komentáře

[ 20.12.2011 2:12:58 ]

That's way more clever than I was extepcing. Thanks!

Přidat komentář

jméno

text komentáře

opište text z obrázku


O autorovi

David Beinhauer

David Beinhauer

Působí jako Microsoft Student Partner a pracuje jako vývojář v jedné nadnárodní firmě. Zajímá se o webové technologie a počítačovou grafiku. Pozornost také věnuje hernímu průmyslu

web: www.aglight.cz

©2010 | David Beinhauer | Lukáš Kubis