[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:
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.
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.
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; }; }
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ší.
That's way more clever than I was extepcing. Thanks!
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
email: davidb@devedu.cz
web: www.aglight.cz