为什么鼠标移动时MouseMove事件会触发

时间:2016-04-18 19:31:49

标签: c# wpf mousemove

我有一个ItemsControlItemsPresenter响应MouseMove事件。项目在数据源中移动,如果移动项目时鼠标位于控件之上,即使鼠标移动也不会触发MouseMove事件。

下面是一个展示问题的示例。

XAML:

<ItemsControl Name="ladder" ItemsSource="{Binding Rows}">
    <ItemsControl.Template>
        <ControlTemplate>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <TextBlock Text="Header" Grid.Column="0" />
                <ItemsPresenter Grid.Row="1" 
                                MouseMove="OnMouseMove"/>
            </Grid>                 
        </ControlTemplate>
    </ItemsControl.Template>
</ItemsControl>

C#:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        Rows.Add(new Row { Name = "0" });
        Rows.Add(new Row { Name = "1" });
        Rows.Add(new Row { Name = "2" });
        Rows.Add(new Row { Name = "3" });
        Rows.Add(new Row { Name = "4" });

        DispatcherTimer t = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(1000) };
        t.Tick += T_Tick;
        t.Start();
    }

    private void T_Tick(object sender, EventArgs e)
    {
        Rows.Move(4, 0);
    }

    private void OnMouseMove(object sender, MouseEventArgs e)
    {
        Debug.WriteLine(e.Timestamp);
    }

    public ObservableCollection<Row> Rows { get; set; } = new ObservableCollection<Row>();
}

public class Row
{
    public string Name { get; set; }

    public override string ToString()
    {
        return Name;
    }
}

如果您调试/运行此操作,请将鼠标移到ItemsControl上,并将其保留在那里,您将在“输出”窗口中看到MouseMove事件正在作为控制转移。

有什么理由吗?或者有没有办法过滤这些事件,只回应&#34;真实&#34;鼠标移动事件?

1 个答案:

答案 0 :(得分:6)

在您的示例中,这些事件是从您的项目演示者的子控件冒出来的,即来自TextBlocks。如果你这样做:

private void OnMouseMove(object sender, MouseEventArgs e)
{
    var tb=(TextBlock)e.OriginalSource;
    var lastMove = e.GetPosition((IInputElement)e.OriginalSource);
    Debug.WriteLine(tb.Text + ":" + lastMove);
}

每次原始事件源都是不同的文本块(0 1 2 3 4 5)时,您会看到,现在是鼠标下的文本块。从这个文本块的角度来看,鼠标确实被移动了 - 它没有超过它然后结束了。我同意这是可论证的行为,也许甚至可以被认为是错误的。为了解决这个问题,我认为最简单的方法是记住最后一个鼠标移动位置并检查它是否已经改变:

private Point _lastMove;
private void OnMouseMove(object sender, MouseEventArgs e)
{                        
    var p = e.GetPosition((IInputElement)sender);
    if (_lastMove != p) {
        // really moved
        _lastMove = p;
    }
}