开发者

WPF: MouseEnter doesn't work on several buttons when mouse is pressed

I have a list of toggle-buttons in wpf and I want the user to be able to toggle several buttons by dragging over them. To do this, I used the MouseEnter-Event for each button. This does work, when I press the mousebutton outside the buttons and start dragging. But when I press the mousebutton on a button and start dragging, the MouseEnter-Event is only fired for the first button, where I pressed the mousebutton (also none of the other events like mouseover or mousemove are fired).

Here's the code:

public void AddButton()
{
    ToggleButton btn = new ToggleButton();
    btn.MouseEnter += VisibilityButton_Enter;
    this.gridButtons.Children.Add(btn);
}

private void VisibilityButton_Enter(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed || e.RightButton == MouseButtonState.Pressed)
    {
       开发者_运维知识库 ToggleButton btn = sender as ToggleButton;
        btn.IsChecked = !btn.IsChecked;
    }
}

I found a solution to use "drag and drop" and the dragover-event, but I think there must be an easier solution?


As Kent mentioned, the ToggleButton captures the mouse. If we handle the PreviewMouseDown event ourselves we can prevent that. The rest is just keeping track of the mouse state so the we don't click twice during a single roll-over. Here is a behavior you can add to your button to enable roll-over clicking.

First add this namespace:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

and the corresponding reference to your project.

Then the XAML looks like this (notice the RollOverBehavior):

<Grid>
    <ItemsControl>
        <ItemsControl.ItemsSource>
            <PointCollection>
                <Point/>
                <Point/>
                <Point/>
                <Point/>
                <Point/>
            </PointCollection>
        </ItemsControl.ItemsSource>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ToggleButton Width="25" Height="25">
                    <i:Interaction.Behaviors>
                        <local:RollOverBehavior/>
                    </i:Interaction.Behaviors>
                </ToggleButton>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

and here is the behavior itself:

public class RollOverBehavior : Behavior<ToggleButton>
{
    bool mouseOver;
    bool clicked;

    protected override void OnAttached()
    {
        AssociatedObject.PreviewMouseLeftButtonDown += (s, e) =>
        {
            AssociatedObject.IsChecked = !AssociatedObject.IsChecked;
            e.Handled = true;
        };
        AssociatedObject.MouseEnter += (s, e) =>
        {
            mouseOver = true;
            clicked = false;
        };
        AssociatedObject.MouseLeave += (s, e) =>
        {
            mouseOver = false;
        };
        AssociatedObject.MouseMove += (s, e) =>
        {
            if (mouseOver && !clicked && e.LeftButton == MouseButtonState.Pressed)
            {
                AssociatedObject.IsChecked = !AssociatedObject.IsChecked;
                clicked = true;
            }
        };
    }
}


The problem is that the default behavior of the ToggleButton is to capture the mouse when the left mouse button is clicked. Because the mouse is captured, all mouse events are sent to the first ToggleButton.

Sounds like what you want to do is override this default behavior such that the mouse isn't captured, but to be honest I couldn't really follow exactly what it is you're trying to achieve.


I had the same problem with normal Buttons. The solution, that worked for me, is to set e.Handled = true in the PreviewMouseButtonDown event (I implemented this too). It seems, that just by down-click with the mouse, the previous action is not fully handled until the mouse button is released, so the MouseEnter event is not able to raise.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜