2012-03-30 1 views
5

Я пытаюсь расширить Button, чтобы добавить событие RightClick.Могу ли я продлить кнопку, чтобы добавить событие RightClick таким образом, чтобы также сохранялись графические побочные эффекты?

Мой клиент хочет, чтобы кнопка делала разные вещи в зависимости от того, нажали ли вы щелкнуть левой кнопкой мыши или щелкнуть правой кнопкой мыши. Я ожидал, что это будет простое событие для щелчка правой кнопкой мыши, но, оказывается, нет.

Я бы предпочел, чтобы визуальное поведение кнопки было идентично предыдущему событию Click, но оно оказалось жестким. Кнопка имеет много графических действий, которые возникают, когда вы нажимаете и перетаскиваете и выключаете кнопку.

  • Когда вы нажимаете вниз, кнопка опускается. Если вы перетаскиваете опустившуюся кнопку, она поднимается (например, уменьшается). Любые другие кнопки, которые вы перетаскиваете, игнорируют его.
  • Когда вы перетащите назад исходную кнопку, она снова опустится.
  • Если вы перетаскиваете и отпускаете, состояние исходной кнопки должно быть сброшено (т. Е. Вы не можете снова и снова перетаскивать).

Эти маленькие графические причуды будут выглядеть грубыми, если визуальные эффекты с левым кликом не соответствуют визуальным щелчкам правой кнопки мыши.

В настоящее время я застрял в этом: Если щелкнуть правой кнопкой мыши и удерживать кнопку, а затем перетащить кнопку, как определить, будет ли пользователь щелкать? Мне нужно знать это, поэтому я могу не забывать о повторном нажатии кнопки при повторном входе.

Более широкий вопрос: Я даже на правильном пути? Я не мог найти никого, кто делал это раньше. Мой код ниже.

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

См. Соответствующий вопрос для одной из моих точек крепления: [Могу ли я получить событие MouseLeave во время мыши.Capture() активен?] (Http://stackoverflow.com/questions/9961050/can-i-get-a-mouseleave-event-while-mouse-capture-is-active) –

ответ

3

Благодаря ответу my other question, это то, что я придумал.

Похоже, что могут возникнуть некоторые различия между поведением XP и Win7. Мне нужно будет продолжить тестирование на 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

Конечно, вы можете это сделать, почему бы и нет?

Просто выполните события для события Mouse-Up и проверьте там, если нажата правая кнопка мыши - если это правда, затем вызовите добавленный вами делегат/событие, например, OnRightMouseClick.

Посмотрите на странице MSDN Routed Events - и да, вы на правильном пути.

Привет,

+0

Графические взаимодействия сложнее, чем, возможно, вы обращаетесь с ними. Например, скажем, я нажимаю правой кнопкой мыши и удерживаю ее, затем я вытаскиваю мышь с кнопки. Как кнопка распознает мышь, если мышь появляется, когда мышь находится за кнопкой? –

+0

(продолжение) Mouse.Capture, похоже, не работает, чтобы распознать мышь после выключения мыши. Когда кнопка захватывает мышь, этот захват, похоже, предотвращает работу MouseEnter и MouseLeave. –

0

Конечно, МОФ позволяет связать команды управления. Сначала подключите привязки команд окна.

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

Затем зарегистрировать для связывания правой кнопки мыши по кнопке

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

Источник: WPF Command bindings - Mouse clicks

+0

Вы прочитали мою полную рецензию? Я могу реагировать на событие щелчка правой кнопкой мыши, это графические побочные эффекты, которые я пытаюсь дублировать. –

0

Вы можете использовать PreviewMouseDown события. Было бы что-то вроде этого

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

Вы прочитали мою полную рецензию? Я могу реагировать на событие щелчка правой кнопкой мыши, это графические побочные эффекты, которые я пытаюсь дублировать. –

1

Если вы посмотрите на исходный код для ButtonBase, вы увидите, что это будет трудно легко дублировать то, что происходит в OnMouseLeftButtonDown и OnMouseLeftButtonUp переопределениях.

Простой хак, который, кажется, работает достаточно хорошо, чтобы извлечь из Button следующим образом:

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); 
    } 
} 

Затем используйте <MyButton> вместо <Button> в вашем Xaml.

Я не могу гарантировать, что это будет работать правильно во всех сценариях, но, похоже, оно работает по мере необходимости, так как визуальное поведение кнопки одинаково при щелчке правой или левой кнопкой мыши.

+0

Я пробовал это точно, и это не эффективно. Если вы щелкнете правой кнопкой мыши и удерживаете, а затем перетащите кнопку, поведение повышения/понижения кнопки отличается от того, что вы сделали это нажатием левой кнопки мыши. –

+0

Где я могу увидеть исходный код ButtonBase? У меня сложилось впечатление, что он был закрытым. –

+0

Работает для меня в простом тестовом приложении. Используйте Reflector Redgate или JetBrains DotPeek (который является бесплатным), чтобы декомпилировать исходный код ButtonBase (или что-то еще). Если у вас есть Resharper, просто перейдите прямо к нему. – Phil

1

Просто добавьте свои собственные 2c. Это основано на ответ дается @Grant со следующими изменениями:

  1. Это правильно использует _rightButtonDown флаг, а не CaptureMouse свойство определяет обработку, поскольку CaptureMouse может быть установлен в другом месте (т.е. это прилипает к надлежащей герметизации .)

  2. Это свойство имеет свойство ClickMode, учитывающее значение Press.

  3. Это правильно использует обработчик OnRightClick, чье имя не только теперь следует стандартным соглашениям, но также обрабатывает все вызовы, чтобы поднять событие RightClick, а не дублировать код. Он также был помечен как virtual для правильной поддержки возможностей подкласса, поскольку если вы переопределяете эту функцию, вы можете обрабатывать/блокировать все события RightClick.

  4. Я назвал его EnhancedButton в случае, если я хочу добавить дополнительную функциональность.

  5. Я включил пример того, как вы определили бы стиль, чтобы сделать это правильно отображаться в ToolBar

Примечание: Правильный способ реализации события RightClick элемента управления является как RoutedEvent, а не стандартное событие CLR. Тем не менее, я оставлю это до читателя, чтобы реализовать этот простой пример.

Вот код класса 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 
} 

А вот как определить стиль, чтобы сделать это выглядеть как все остальные кнопки на панели инструментов. Добавьте это в свои ресурсы панели инструментов или, еще лучше, создайте свои панели инструментов, чтобы установить это в стиле, поэтому вам не нужно добавлять его вручную повсюду.

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

Теперь это более-совместимая капля в замена для стандартного Button управления.

 Смежные вопросы

  • Нет связанных вопросов^_^