[Silverlight入门系列]右键菜单ContextMenu和SplitButton

来源:转载

Silverlight4 Toolkit提供了ContextMenu和MenuItem控件来实现右键菜单,很方便。另外,Silverlight4 Toolkit提供了PopUp控件来实现弹出式内容,里面可以放任何子控件,利用IsOpen属性来控制显示隐藏。

上下文菜单ContextMenu的Silverlight Demo源码下载请点击这儿,SplitButton的Silverlight Demo源码下载请点击这儿,具体效果如下图:

Silverlight SplitButton

 

Silverlight ContextMenu

 

上下文菜单ContextMenu的Silverlight Demo源码下载请点击这儿,SplitButton的Silverlight Demo源码下载请点击这儿

<splitButton:SplitButton Content="Open" Click="Open_Click">                <splitButton:SplitButton.ButtonMenuItemsSource>
                    <toolkit:MenuItem Header="Open" Click="Open_Click">
                        <toolkit:MenuItem.Icon>
                            <Image Source="/SilverlightApplication3;component/images/search.png" Width="14" Height="14"/>
                        </toolkit:MenuItem.Icon>
                    </toolkit:MenuItem>
                    <toolkit:MenuItem Header="Open read-only" Click="OpenReadOnly_Click"/>
                    <toolkit:MenuItem Header="Open as copy" Click="OpenCopy_Click"/>
                </splitButton:SplitButton.ButtonMenuItemsSource>
            </splitButton:SplitButton>

Silverlight SplitButton源码

  1 using System;
  2 using System.Collections.ObjectModel;
  3 using System.Windows;
  4 using System.Windows.Controls;
  5 using System.Windows.Input;
  6 
  7 namespace Delay
  8 {
  9     /// <summary>
 10     /// Implements a "split button" for Silverlight and WPF.
 11     /// </summary>
 12     [TemplatePart(Name = SplitElementName, Type = typeof(UIElement))]
 13     public class SplitButton : Button
 14     {
 15         /// <summary>
 16         /// Stores the public name of the split element.
 17         /// </summary>
 18         private const string SplitElementName = "SplitElement";
 19 
 20         /// <summary>
 21         /// Stores a reference to the split element.
 22         /// </summary>
 23         private UIElement _splitElement;
 24 
 25         /// <summary>
 26         /// Stores a reference to the ContextMenu.
 27         /// </summary>
 28         private ContextMenu _contextMenu;
 29 
 30 
 31         /// <summary>
 32         /// Stores the initial location of the ContextMenu.
 33         /// </summary>
 34         private Point _contextMenuInitialOffset;
 35 
 36         /// <summary>
 37         /// Stores the backing collection for the ButtonMenuItemsSource property.
 38         /// </summary>
 39         private ObservableCollection<object> _buttonMenuItemsSource = new ObservableCollection<object>();
 40 
 41         /// <summary>
 42         /// Gets the collection of items for the split button's menu.
 43         /// </summary>
 44         public Collection<object> ButtonMenuItemsSource { get { return _buttonMenuItemsSource; } }
 45 
 46         /// <summary>
 47         /// Gets or sets a value indicating whetherthe mouse is over the split element.
 48         /// </summary>
 49         protected bool IsMouseOverSplitElement { get; private set; }
 50 
 51         /// <summary>
 52         /// Initializes a new instance of the SplitButton class.
 53         /// </summary>
 54         public SplitButton()
 55         {
 56             DefaultStyleKey = typeof(SplitButton);
 57         }
 58 
 59         /// <summary>
 60         /// Called when the template is changed.
 61         /// </summary>
 62         public override void OnApplyTemplate()
 63         {
 64             // Unhook existing handlers
 65             if (null != _splitElement)
 66             {
 67                 _splitElement.MouseEnter -= new MouseEventHandler(SplitElement_MouseEnter);
 68                 _splitElement.MouseLeave -= new MouseEventHandler(SplitElement_MouseLeave);
 69                 _splitElement = null;
 70             }
 71             if (null != _contextMenu)
 72             {
 73                 _contextMenu.Opened -= new RoutedEventHandler(ContextMenu_Opened);
 74                 _contextMenu.Closed -= new RoutedEventHandler(ContextMenu_Closed);
 75                 _contextMenu = null;
 76             }
 77 
 78             // Apply new template
 79             base.OnApplyTemplate();
 80 
 81             // Hook new event handlers
 82             _splitElement = GetTemplateChild(SplitElementName) as UIElement;
 83             if (null != _splitElement)
 84             {
 85                 _splitElement.MouseEnter += new MouseEventHandler(SplitElement_MouseEnter);
 86                 _splitElement.MouseLeave += new MouseEventHandler(SplitElement_MouseLeave);
 87 
 88                 _contextMenu = ContextMenuService.GetContextMenu(_splitElement);
 89                 if (null != _contextMenu)
 90                 {
 91 
 92                     _contextMenu.Opened += new RoutedEventHandler(ContextMenu_Opened);
 93                     _contextMenu.Closed += new RoutedEventHandler(ContextMenu_Closed);
 94                 }
 95             }
 96         }
 97 
 98         /// <summary>
 99         /// Called when the Button is clicked.
100         /// </summary>
101         protected override void OnClick()
102         {
103             if (IsMouseOverSplitElement)
104             {
105                 OpenButtonMenu();
106             }
107             else
108             {
109                 base.OnClick();
110             }
111         }
112 
113         /// <summary>
114         /// Called when a key is pressed.
115         /// </summary>
116         protected override void OnKeyDown(KeyEventArgs e)
117         {
118             if (null == e)
119             {
120                 throw new ArgumentNullException("e");
121             }
122 
123             if ((Key.Down == e.Key) || (Key.Up == e.Key))
124             {
125                 // WPF requires this to happen via BeginInvoke
126                 Dispatcher.BeginInvoke((Action)(() => OpenButtonMenu()));
127             }
128             else
129             {
130                 base.OnKeyDown(e);
131             }
132         }
133 
134         /// <summary>
135         /// Opens the button menu.
136         /// </summary>
137         protected void OpenButtonMenu()
138         {
139             if ((0 < _buttonMenuItemsSource.Count) && (null != _contextMenu))
140             {
141                 _contextMenu.HorizontalOffset = 0;
142                 _contextMenu.VerticalOffset = 0;
143                 _contextMenu.IsOpen = true;
144             }
145         }
146 
147         /// <summary>
148         /// Called when the mouse goes over the split element.
149         /// </summary>
150         /// <param name="sender">Event source.</param>
151         /// <param name="e">Event arguments.</param>
152         private void SplitElement_MouseEnter(object sender, MouseEventArgs e)
153         {
154             IsMouseOverSplitElement = true;
155         }
156 
157         /// <summary>
158         /// Called when the mouse goes off the split element.
159         /// </summary>
160         /// <param name="sender">Event source.</param>
161         /// <param name="e">Event arguments.</param>
162         private void SplitElement_MouseLeave(object sender, MouseEventArgs e)
163         {
164             IsMouseOverSplitElement = false;
165         }
166 
167         /// <summary>
168         /// Called when the ContextMenu is opened.
169         /// </summary>
170         /// <param name="sender">Event source.</param>
171         /// <param name="e">Event arguments.</param>
172         private void ContextMenu_Opened(object sender, RoutedEventArgs e)
173         {
174             // Offset the ContextMenu correctly
175 
176             _contextMenuInitialOffset = _contextMenu.TransformToVisual(null).Transform(new Point());
177 
178             UpdateContextMenuOffsets();
179 
180             // Hook LayoutUpdated to handle application resize and zoom changes
181             LayoutUpdated += new EventHandler(SplitButton_LayoutUpdated);
182         }
183 
184         /// <summary>
185         /// Called when the ContextMenu is closed.
186         /// </summary>
187         /// <param name="sender">Event source.</param>
188         /// <param name="e">Event arguments.</param>
189         private void ContextMenu_Closed(object sender, RoutedEventArgs e)
190         {
191             // No longer need to handle LayoutUpdated
192             LayoutUpdated -= new EventHandler(SplitButton_LayoutUpdated);
193 
194             // Restore focus to the Button
195             Focus();
196         }
197 
198         /// <summary>
199         /// Called when the ContextMenu is open and layout is updated.
200         /// </summary>
201         /// <param name="sender">Event source.</param>
202         /// <param name="e">Event arguments.</param>
203         private void SplitButton_LayoutUpdated(object sender, EventArgs e)
204         {
205             UpdateContextMenuOffsets();
206         }
207 
208         /// <summary>
209         /// Updates the ContextMenu's Horizontal/VerticalOffset properties to keep it under the SplitButton.
210         /// </summary>
211         private void UpdateContextMenuOffsets()
212         {
213             // Calculate desired offset to put the ContextMenu below and left-aligned to the Button
214 
215             Point currentOffset = _contextMenuInitialOffset;
216             Point desiredOffset = TransformToVisual(Application.Current.RootVisual).Transform(new Point(0, ActualHeight));
217 
218             _contextMenu.HorizontalOffset = desiredOffset.X - currentOffset.X;
219             _contextMenu.VerticalOffset = desiredOffset.Y - currentOffset.Y;
220             // Adjust for RTL
221             if (FlowDirection.RightToLeft == FlowDirection)
222             {
223                 _contextMenu.UpdateLayout();
224                 _contextMenu.HorizontalOffset -= _contextMenu.ActualWidth;
225 
226             }
227         }
228 
229     }
230 }

本文来自Mainz的博客,原文地址:http://www.cnblogs.com/Mainz/archive/2011/06/25/2090159.html


分享给朋友:
您可能感兴趣的文章:
随机阅读: