WPF 如何控制右鍵菜單ContextMenu的彈出

      在具體作一些項目的時候,有時候須要須要先左鍵點擊某個節點,而後再右鍵點擊節點的時候才彈出右鍵菜單,因此直接右鍵點擊時須要禁用掉右鍵菜單,這裏好比咱們爲Grid添加了ContextMenu,可是咱們須要設置一個bool型的變量isSelected,當咱們執行到MouseLeftButtonDown事件中的時候,咱們就能夠將isSelected設置爲true,而後在Grid中添加PreviewMouseRightButtonUp="OnMouseRightButtonUp"(隧道事件路由)事件或者是MouseRightButtonUp(冒泡事件路由)事件,在本項目中二者均可以,可是不要添加在<Grid.ContextMenu/>及其子節點下面,這個稍後會介紹,而後在主程序中執行下面的代碼:編程

     private void OnMouseRightButtonUp(object  sender,MouseButtonEventArgs  e)
      {
         if(isSelected==true)
          {
           //使消息能夠傳遞
           e.Handled=false;
         }
        else
        {
           e.Handled=true;
        }
       isSelected=false;
     }  

      這樣當咱們先左鍵點擊某一個節點的時候,而後再點擊右鍵的時候才能彈出ContextMenu,這裏咱們須要正確理解Handled的含義,Handled將路由事件標記爲已處理的值。若是 Handled 的值爲 true,則能夠防止事件路由路徑上的大多數處理程序再次處理同一事件。這在實際的事件處理中是很是有用的,由於WPF的這種層層嵌套的UI設計思想,使得某一個事件,例如UIElement.MouseLeftButtonDown在不少元素上都會觸發,根據事件的不一樣類型,能夠有冒泡觸發或者是隧道的這種方式來觸發,但事實上只有一個元素最終執行該事件,若是某一個元素已經執行過該事件,那麼它就會將Handled 的值設爲 true,這樣事件就不會向下或者向上路由了,若是想讓事件繼續路由就要將Handled設置爲false這個是很是重要的,下面的內容參考一下別人寫的一篇博客,頗有意義。函數

  在讀《WPF高級編程》,看到事件的上傳和下傳。有個例子:this

  前臺代碼:spa

<Window x:Class="TunnelingBubbling.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" >
    <Grid MouseLeftButtonDown="Grid_MouseLeftButtonDown" 
    PreviewMouseLeftButtonDown="Grid_PreviewMouseLeftButtonDown"
     Width="313" Height="271" Name="mygrid">
        <Button PreviewMouseLeftButtonDown="Button_PreviewMouseLeftButtonDown"
         MouseLeftButtonDown="Button_MouseLeftButtonDown" Click="Button_Click" Name="btnGo">
            <TextBox Name="textBox1" Width="173" Height="27"
            MouseLeftButtonDown="textBox1_MouseLeftButtonDown"
             PreviewMouseLeftButtonDown="textBox1_PreviewMouseLeftButtonDown">
            </TextBox>
        </Button>
    </Grid>
</Window>  

  分別爲Grid,Button,TextBox定義了PreviewMouseLeftButtonDown和MouseLeftButtonDown事件,而且爲Button定義的Click事件。設計

  後臺代碼以下:xml

   public partial class Window1 : Window
   {
       public Window1()
       {
           InitializeComponent();
       }

       private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("Grid_PreviewMouseLeftButtonDown");
       }

       private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("Button_PreviewMouseLeftButtonDown");
       }
       private void textBox1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("textBox1_PreviewMouseLeftButtonDown");
       }

       private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("Grid_MouseLeftButtonDown");
       }
       private void Button_Click(object sender, RoutedEventArgs e)
       {
           Debug.WriteLine("Button_Click");
       }
       private void textBox1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("textBox1_MouseLeftButtonDown");
       }
       private void Button_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("Button_MouseLeftButtonDown");
       }
   } 

  可是在執行的時候,MouseLeftButtonDown事件老是沒法觸發。查看了一些資料,才知道這是一個設計原則上的問題。控件在捕獲了MouseLeftButtonDown事件後,會將該事件的「Handled」設置爲True,這個屬性是用在事件路由中的,當某個控件獲得一個RoutedEvent,就會檢測Handled是否爲true,爲true則忽略該事件。對象

    而且,控件自己的Click事件,至關於將MouseLeftButtonDown事件抑制(Supress)掉了,轉換成了Click事件。因此,若是必定要使用這個事件的話,須要在初始化的函數裏利用UIElement的AddHandler方法,顯式的增長這個事件。blog

---------方法說明:---------------------------------------------------------------------------------事件

UIElement.AddHandler 方法 (RoutedEvent, Delegate, Boolean)ci

  爲指定的路由事件添加路由事件處理程序,並將該處理程序添加到當前元素的處理程序集合中。將 handledEventsToo 指定爲 true 時,可爲已標記爲由其餘元素在事件路由過程當中處理的路由事件調用所提供的處理程序。

參數說明: 

  handledEventsToo類型:System..::.Boolean

若是爲 true,則將按如下方式註冊處理程序:即便路由事件在其事件數據中標記爲已處理,也會調用該處理程序;若是爲 false,則使用默認條件註冊處理程序,即當路由事件被標記爲已處理時,將不調用處理程序。

默認值爲 false。 

修改後的程序代碼以下:

 public Window1()
      {
          InitializeComponent();
          mygrid.AddHandler(Grid.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.Grid_MouseLeftButtonDown), true);
          btnGo.AddHandler(Button.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.Button_MouseLeftButtonDown), true);
          textBox1.AddHandler(TextBox.MouseLeftButtonDownEvent, new MouseButtonEventHandler(this.textBox1_MouseLeftButtonDown), true);
      }   

  再次運行,調用成功,事件的執行順序是:

次序

控件

事件

事件類型

1

Grid PreviewMouseLeftButtonDown

下傳

2

Button PreviewMouseLeftButtonDown

下傳

3

TextBox PreviewMouseLeftButtonDown

下傳

4

TextBox MouseLeftButtonDown

上傳

5

Button MouseLeftButtonDown

上傳

6

Grid MouseLeftButtonDown

上傳

   若是點擊Button,則事件的執行順序是:

次序

控件

事件

事件類型

1

Grid PreviewMouseLeftButtonDown

下傳

2

Button PreviewMouseLeftButtonDown

下傳

3

Button MouseLeftButtonDown

上傳

4

Grid MouseLeftButtonDown

上傳

5

Button Click

 

  最後補充一點:

  在事件處理程序中,能夠取消事件處理,查找事件的源元素

  例如在下面的代碼中:

private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
       {
           Debug.WriteLine("Button_PreviewMouseLeftButtonDown");
          // e.Handled = true;
          // Button myButton = e.Source as Button;
       }  

  1.取消事件處理:  設置 e.Handled = true;

  2.在事件處理程序中查找源元素:  e.Source 傳遞一個實際對象實例,能夠將其強制轉換爲System.Windows.Controls.Button類型,經過這個變量,能夠訪問這個控件提供的全部本地屬性,方法和事件。

相關文章
相關標籤/搜索