2012-03-30 12 views
5

Tôi đang cố gắng mở rộng Nút để thêm sự kiện RightClick.Tôi có thể mở rộng Nút để thêm sự kiện RightClick theo cách mà các hiệu ứng phụ đồ họa cũng được duy trì không?

Khách hàng của tôi muốn một nút để thực hiện những việc khác nhau tùy thuộc vào việc bạn nhấp chuột trái hay nhấp chuột phải. Tôi mong đợi có một sự kiện dễ dàng để nhấp chuột phải, nhưng hóa ra là không có.

Tôi muốn hành vi trực quan của Button giống hệt với sự kiện Nhấp chuột trước đó, nhưng điều đó chứng minh là khó khăn. Nút có nhiều hành vi đồ họa xảy ra khi bạn nhấp và kéo và tắt nút.

  • Khi bạn nhấp xuống, nút này sẽ hạ thấp. Nếu bạn kéo nút giảm xuống, nó sẽ tăng (ví dụ: un-lowers). Bất kỳ nút nào khác bạn kéo qua sẽ bỏ qua nó.
  • Khi bạn kéo trở lại nút gốc, nút này sẽ giảm xuống một lần nữa.
  • Nếu bạn kéo và sau đó nhả ra, trạng thái của nút gốc sẽ được đặt lại (tức là bạn không thể reclick và kéo lại).

Những quirks đồ họa nhỏ này sẽ trông thô ráp nếu hình ảnh nhấp chuột trái không khớp với hình ảnh nhấp chuột phải.

Hiện tại tôi đang bị kẹt: Nếu nhấp chuột phải và giữ nút, sau đó kéo nút, làm cách nào để phát hiện xem người dùng có nhấp chuột không? Tôi cần phải biết điều này vì vậy tôi có thể biết không phải để hạ thấp nút trên tái nhập cảnh.

Câu hỏi rộng hơn: Tôi có đi đúng hướng không? Tôi không thể tìm thấy ai đã làm điều này trước đây. Mã của tôi là dưới đây.

public class RightClickButton : Button 
{ 
    public event RoutedEventHandler RightClick; 

    public RightClickButton() 
    { 
     this.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonDown); 
     this.MouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonUp); 
     this.MouseEnter += new System.Windows.Input.MouseEventHandler(RightClickButton_MouseEnter); 
     this.MouseLeave += new System.Windows.Input.MouseEventHandler(RightClickButton_MouseLeave); 
    } 

    void RightClickButton_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     this.IsPressed = true; 
    } 

    void RightClickButton_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     this.IsPressed = false; 
     if (RightClick != null) 
      RightClick.Invoke(this, e); 
    } 

    void RightClickButton_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e) 
    { 
     if (this.IsPressed) 
      this.IsPressed = false; 
    } 

    void RightClickButton_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e) 
    { 
     if (this.IsFocused && Mouse.RightButton == MouseButtonState.Pressed) 
      this.IsPressed = true; 
    } 
} 
+0

Xem câu hỏi liên quan đến một trong các điểm gắn bó của tôi: [Tôi có thể nhận được sự kiện MouseLeave trong khi Chuột không.Capture() đang hoạt động?] (Http://stackoverflow.com/questions/9961050/can-i-get-a-mouseleave-event-while-mouse-capture-is-active) –

Trả lời

3

Nhờ câu trả lời được đưa ra cho my other question, đây là những gì tôi đã đưa ra.

Dường như có thể có một số khác biệt giữa hành vi XP và Win7. Tôi sẽ cần phải kiểm tra thêm trên Win7.

public class RightClickButton : Button 
{ 
    public event RoutedEventHandler RightClick; 

    private bool _clicked = false; 

    public RightClickButton() 
    { 
     this.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonDown); 
     this.MouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonUp); 
    } 

    // Subclasses can't invoke this event directly, so supply this method 
    protected void TriggerRightClickEvent(System.Windows.Input.MouseButtonEventArgs e) 
    { 
     if (RightClick != null) 
      RightClick(this, e); 
    } 

    void RightClickButton_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     this.IsPressed = true; 
     CaptureMouse(); 
     _clicked = true; 
    } 

    void RightClickButton_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    { 
     ReleaseMouseCapture(); 

     if(this.IsMouseOver && _clicked) 
     { 
      if (RightClick != null) 
       RightClick.Invoke(this, e); 
     } 

     _clicked = false; 
     this.IsPressed = false; 
    } 

    protected override void OnMouseMove(MouseEventArgs e) 
    { 
     base.OnMouseMove(e); 

     if (this.IsMouseCaptured) 
     { 
      bool isInside = false; 

      VisualTreeHelper.HitTest(
       this, 
       d => 
       { 
        if (d == this) 
        { 
         isInside = true; 
        } 

        return HitTestFilterBehavior.Stop; 
       }, 
       ht => HitTestResultBehavior.Stop, 
       new PointHitTestParameters(e.GetPosition(this))); 

      if (isInside) 
       this.IsPressed = true; 
      else 
       this.IsPressed = false; 
     } 
    } 
} 
0

Dĩ nhiên bạn có thể làm điều đó, tại sao không?

Chỉ cần triển khai Sự kiện cho sự kiện Chuột lên và kiểm tra ở đó nếu nút chuột phải đã được nhấn xuống - nếu đúng, sau đó gọi cho đại biểu/sự kiện bạn đã thêm trước đó, ví dụ: OnRightMouseClick.

Có giao diện trên trang MSDN Routed Events - và có, bạn đang đi đúng hướng.

Chúc mừng,

+0

Các tương tác đồ họa phức tạp hơn có lẽ bạn đang đối xử với họ. Ví dụ: giả sử tôi nhấp chuột phải vào nút và giữ nút đó, sau đó tôi kéo chuột ra khỏi nút. Làm cách nào để nút có thể nhận ra chuột khi con chuột xuất hiện khi chuột ở bên ngoài nút? –

+0

(tiếp theo) Mouse.Capture dường như không hoạt động để nhận ra chuột sau khi di chuột. Khi nút chụp chuột, ảnh chụp này dường như đã làm cho các sự kiện MouseEnter và MouseLeave không hoạt động. –

0

Chắc chắn, wpf cho phép bạn liên kết lệnh với điều khiển. Đầu tiên dây lên các ràng buộc lệnh của cửa sổ.

<Window.CommandBindings> 
    <CommandBinding Command="{x:Static custom:Window1.RightClickCommand}" 
        Executed="YourRightClickMethodInCSharpFile" /> 
</Window.CommandBindings> 

Sau đó đăng ký cho click chuột phải ràng buộc vào nút

<Button Content="Ima Button!"> 
    <Button.InputBindings> 
     <MouseBinding Command="{x:Static custom:Window1.RightClickCommand}" 
         MouseAction="RightClick" /> 
    </Button.InputBindings> 
</Button>  

nguồn: WPF Command bindings - Mouse clicks

+0

Bạn đã đọc toàn bộ bài viết của tôi chưa? Tôi có thể phản ứng với sự kiện nhấp chuột phải, đó là các hiệu ứng phụ đồ họa mà tôi đang cố gắng sao chép. –

0

Bạn có thể sử dụng sự kiện PreviewMouseDown. Nó sẽ là một cái gì đó như thế này

private void buttonTest_PreviewMouseDown(object sender, MouseButtonEventArgs e) 
    { 
     if (e.RightButton == MouseButtonState.Pressed) 
     { 
      MessageBox.Show("Right"); 
     } 
     else if (e.LeftButton == MouseButtonState.Pressed) 
     { 
      MessageBox.Show("Left"); 
     } 

     e.Handled = true; 
    } 
+0

Bạn đã đọc toàn bộ bài viết của tôi chưa? Tôi có thể phản ứng với sự kiện nhấp chuột phải, đó là các hiệu ứng phụ đồ họa mà tôi đang cố gắng sao chép. –

1

Nếu bạn nhìn vào các mã nguồn cho ButtonBase, bạn sẽ thấy rằng nó sẽ rất khó để dễ dàng lặp lại những gì đang xảy ra trong OnMouseLeftButtonDownOnMouseLeftButtonUp ghi đè.

Một hack đơn giản mà dường như làm việc khá tốt là để lấy được từ Button như sau:

public class MyButton : Button 
{ 
    protected override void OnMouseRightButtonDown(MouseButtonEventArgs e) 
    { 
     base.OnMouseRightButtonDown(e); // this line probably optional/not required 
     base.OnMouseLeftButtonDown(e); 
    } 

    protected override void OnMouseRightButtonUp(MouseButtonEventArgs e) 
    { 
     base.OnMouseRightButtonUp(e); // this line probably optional/not required 
     base.OnMouseLeftButtonUp(e); 
    } 
} 

Sau đó sử dụng <MyButton> ở vị trí của <Button> trong XAML của bạn.

Tôi không thể đảm bảo điều này sẽ hoạt động chính xác trong mọi tình huống, nhưng dường như hoạt động theo yêu cầu trong đó hành vi trực quan của nút là giống nhau khi nhấp chuột phải hoặc trái.

+0

Tôi đã thử chính xác điều này và nó không hiệu quả. Nếu bạn nhấp chuột phải và giữ và sau đó kéo ra khỏi nút, nút nâng cao/hành vi thấp hơn là khác với nếu bạn đã làm nó với nhấp chuột trái. –

+0

Tôi sẽ thấy mã nguồn cho ButtonBase ở đâu? Tôi đã có ấn tượng rằng nó là nguồn đóng. –

+0

Làm việc cho tôi trong một ứng dụng thử nghiệm đơn giản. Sử dụng Redgate's Reflector hoặc JetBrains DotPeek (miễn phí) để dịch ngược mã nguồn cho ButtonBase (hoặc bất kỳ thứ gì khác). Nếu bạn có Resharper, chỉ cần điều hướng thẳng đến nó. – Phil

1

Chỉ cần thêm 2c của riêng tôi. Này được dựa trên câu trả lời được đưa ra bởi @Grant với những thay đổi sau:

  1. này đúng cách sử dụng _rightButtonDown cờ, không phải là CaptureMouse tài sản để xác định chế biến từ CaptureMouse có thể đã được thiết lập ở nơi khác (ví dụ này tuân thủ đóng gói thích hợp .)

  2. Điều này có hỗ trợ cho thuộc tính ClickMode cho phép giá trị Press.

  3. Điều này sử dụng đúng cách trình xử lý OnRightClick có tên không chỉ bây giờ theo quy ước tiêu chuẩn mà còn xử lý tất cả các cuộc gọi để tăng sự kiện RightClick thay vì sao chép mã. Nó cũng được đánh dấu là virtual để hỗ trợ đúng khả năng phân lớp trong đó nếu bạn ghi đè hàm đó, bạn có thể xử lý/chặn tất cả các sự kiện RightClick.

  4. Tôi đã đặt tên là EnhancedButton trong trường hợp tôi muốn thêm chức năng bổ sung.

  5. tôi đã bao gồm một ví dụ về cách bạn sẽ xác định một phong cách để làm điều này đúng cách xuất hiện trong một ToolBar

Lưu ý: Các cách thích hợp để thực hiện các sự kiện rightclick vào một điều khiển là như một RoutedEvent, không phải là một sự kiện CLR tiêu chuẩn. Tuy nhiên, tôi sẽ để điều đó cho người đọc thực hiện để giữ ví dụ này đơn giản.

Dưới đây là đoạn code cho lớp EnhancedButton:

public class EnhancedButton : Button 
{ 
    private bool _rightButtonDown = false; 

    public EnhancedButton() 
    { 
     MouseRightButtonDown += RightClickButton_MouseRightButtonDown; 
     MouseRightButtonUp += RightClickButton_MouseRightButtonUp; 
    } 

    #region RightClick Event 

     public event RoutedEventHandler RightClick; 

     protected virtual void OnRightClick(MouseButtonEventArgs e) 
     { 
      RightClick?.Invoke(this, e); 
     } 

    #endregion RightClick Event 

    #region Event Handlers 

     private void RightClickButton_MouseRightButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      IsPressed = true; 

      _rightButtonDown = true; 
      CaptureMouse(); 

      if(ClickMode == ClickMode.Press) 
       OnRightClick(e); 
     } 

     private void RightClickButton_MouseRightButtonUp(object sender, MouseButtonEventArgs e) 
     { 
      if(!_rightButtonDown) 
       return; 

      ReleaseMouseCapture(); 

      IsPressed = false; 

      if(IsMouseOver && ClickMode == ClickMode.Release) 
       OnRightClick(e); 

      _rightButtonDown = false; 
     } 

    #endregion Event Handlers 

    #region Overrides 

     protected override void OnMouseMove(MouseEventArgs e) 
     { 
      base.OnMouseMove(e); 

      if(!_rightButtonDown) 
       return; 

      bool isInside = false; 

      VisualTreeHelper.HitTest(this, d => 
      { 
       if (d == this) 
        isInside = true; 

       return HitTestFilterBehavior.Stop; 
      }, 
      ht => HitTestResultBehavior.Stop, 
      new PointHitTestParameters(e.GetPosition(this))); 

      IsPressed = isInside; 
     } 

    #endregion Overrides 
} 

Và đây là cách bạn định nghĩa một kiểu để thể hiện này xuất hiện giống như tất cả các nút thanh công cụ khác. Thêm tài nguyên này vào tài nguyên của Thanh công cụ của bạn, hoặc tốt hơn, hãy tạo kiểu thanh công cụ của bạn để thiết lập kiểu này theo kiểu để bạn không phải thêm nó theo cách thủ công ở mọi nơi.

<Style TargetType="{x:Type myControls:EnhancedButton}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" /> 

Bây giờ, đây là lựa chọn thay thế thả tương thích hơn cho điều khiển tiêu chuẩn Button.

Các vấn đề liên quan