今天要做一个在ListBox上的项上右击弹出菜单,菜单上有一项 “重命名”,来重命名ListBox里的项,实现过程中发现一个问题,就是在ListBox的空白处右击也可以重命名,因为其实没有选中项,所以会重命名上次选中的项,上网查了一下,找到一篇解决类似问题的博客,解决方案是捕捉ListBox的PreviewMouseButtonDown事件,然后根据Sender和EventArgs 来判断鼠标是否点击到了ListBox里的项,因为我的项目用的是MVVM模式,所以把Sender和EventArgs传给ViewModel有些困难,最后在网上查到用MvvmLight这个库可以传一个RouteEventArgs过去,我就试着弄了一下,果然可以了,代码如下:
class="code_img_closed" src="/Upload/Images/2017101221/0015B68B3C38AA5B.gif" alt="">1 xmlns:cmd="http://www.galasoft.ch/mvvmlight" 2 3 4 <i:EventTrigger EventName="PreviewMouseRightButtonDown" > 5 <cmd:EventToCommand Command="{Binding cmdListBoxPreMouseRBtnDown}" PassEventArgsToCommand="True"/> 6 </i:EventTrigger>logs_code_collapse">XAML代码
1 bool isItemSelected = false; //Determines whether any items are selected when the rename is performed 2 private void ListBox_PreviewMouseRightButtonDown(RoutedEventArgs e) 3 { 4 MouseButtonEventArgs mouseEventArgs = (MouseButtonEventArgs)e; 5 object item = GetElementFromPoint((ItemsControl)e.Source, mouseEventArgs.GetPosition((ItemsControl)e.Source)); 6 //用e.source就可以获得发送事件所在的控件,相当于 object sender, 所以这一个RouteEventArgs 就顶了 7 //PreviewMouseRightButtonDown(object sender, MouseEventArgs e)的两个参数(我目前这么觉得) 8 //GetElementFromPoint方法根据鼠标点击的控件和鼠标点击的点相对于该控件的位置返回点击到的item,如果点击到了就返回item,如果没点击到就返回null 9 isItemSelected = (item != null); 10 } 11 12 private object GetElementFromPoint(ItemsControl itemsControl, System.Windows.Point point) 13 { 14 UIElement element = itemsControl.InputHitTest(point) as UIElement; 15 //ItemsControl的InputHitTest可以获取到点击到的最里层的元素,并不是继承关系上的最里层, 16 //而是UI组合方式上的最里层,因为我如果点到空白处,获取父级元素的顺序是ScrollViewer->Border->ItemsControl 17 //我查了MSDN,这几个元素并没有继承关系 18 while (element != null) //如果啥都没点到就直接返回null 19 { 20 if (element == itemsControl) //如果是ItemsControl,那就是点到了ListBox上,没点到他的子项ListBoxItem上,返回null 21 return null; 22 object item = itemsControl.ItemContainerGenerator.ItemFromContainer(element); 23 //上面这句代码的功能是获取到能显示在UI上的item(我猜的),比如如果element是ListBoxItem,那么就会返回 24 //ListBoxItem的text(“模板1”,“模板2”...) 25 if (!item.Equals(DependencyProperty.UnsetValue))//如果上面没获取到内容,item的值就是DependencyProperty.UnsetValue 26 return item; 27 //然后就去获取这个元素的父级,直到ItemsControl.ItemContainerGenerator.ItemFromContainer(element)获取到内容 28 //或者element已经是ItemsControl 29 element = (UIElement)VisualTreeHelper.GetParent(element); 30 } 31 return null; 32 }ViewModel代码
好了,到这里就大功告成啦,这个是我参考的那位大神的帖子http://www.cnblogs.com/TianFang/archive/2010/02/10/1667186.html, 他里面还有一个方法是同时捕捉ListBox和ListBoxItem的PreviewMouseRightButtonDown事件,然后在ListBox的事件里把IsItemSeleted设置为false, 在ListBoxItem的事件里设置为true,就也可以了,不过我的ListBox的项是自动生成的,不知道该在哪里设置,所以就用了第一种,有知道的人也请给我说下,谢谢啦。以后要每天把解决的问题记录下来,加深理解和记忆,也就离成为大神的目标更近了一步,Fighting!