单击未在未选择行中的WPF Datagrid中触发的事件

时间:2011-12-08 13:41:44

标签: c# wpf wpfdatagrid

我有一个像这样的DataGrid(WPF 4):

<DataGrid   Margin="0,0,0,5" VerticalAlignment="Top" Height="192" 
                            BorderBrush="#aaa" Background="White" 
                            HorizontalAlignment="Left" 
                            ItemsSource="{Binding Namen, Mode=OneWay}" 
                            ScrollViewer.VerticalScrollBarVisibility="Visible"
                            AutoGenerateColumns="False" 
                            ColumnHeaderHeight="24" 
                            SelectionChanged="DataGridAuslaendischeAlteNamen_SelectionChanged">
                    <DataGrid.Columns>
                        <DataGridTextColumn Width="*" Header="Namenseintrag" Binding="{Binding DisplayName, Mode=OneWay}" />
                        <DataGridTextColumn Width="75" Header="gültig von" Binding="{Binding GueltigAb, StringFormat=d, Mode=OneWay}" />
                        <DataGridTextColumn Width="75" Header="gültig bis" Binding="{Binding GueltigBis, StringFormat=d., Mode=OneWay}" />
                        <DataGridTemplateColumn Width="20" IsReadOnly="True">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button Style="{DynamicResource CaratRemoveButton}" 
                                            Click="Button_Click" CommandParameter="{Binding}" 
                                            PreviewMouseDown="Button_PreviewMouseDown" 
                                            />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                </DataGrid.Columns>
                </DataGrid>

我遇到的问题是,DataGridTemplateColumn的按钮如果未选中其行,则不会触发点击事件。所以我必须两次单击一个按钮,一次选择它的行然后再提高click事件。 我读过有关复选框列的类似问题,但显然建议使用模板列。 我测试使用按钮的PreviewMouseDown-Event,它可以工作,但不是我想要的,因为那时按钮不遵循其通常的grpahical点击行为。

我在这里缺少什么?无论是否选择了行,如何只需单击一次即可获得该点击事件?

6 个答案:

答案 0 :(得分:8)

基本上,除了使用TemplateColumn并自己管理每一个mouseEvent之外,你没有解决方案。

说明:

点击= mouseDown + MouseUp,对。 所以你的按钮需要能够获得mouseDown + MouseUp事件。

但是...

默认情况下,wpf的DataGrid的行处理MouseDown事件,以便选择你mouseDown上的mouseDown(确认:MouseDownEvent在一个单元格上并按住mouseButton向下,您将看到 BEFORE 选择该行后,您将释放该按钮。)

基本上,Click在到达按钮之前处理,阻止您在按钮上使用PreviewMouseDown事件

Microsoft在他们的文档中告诉我们,在这种情况下,我们应该转向 Preview 类型的事件,但这不适用于click事件,因为你无法拥有 previewClickEvent

因此,我能看到的唯一解决方案是在您的按钮上同时收听PreviewMouseUp Button myButton = new Button(); bool mouseLeftButtonDownOnMyButton; myButton.PreviewMouseLeftButtonDown += (s, e) => { mouseLeftButtonDownOnMyButton = true; }; myButton.PreviewMouseLeftButtonUp += (s, e) => { if (mouseLeftButtonDownOnMyButton) myButton.RaiseEvent( new RoutedEventArgs(Button.ClickEvent,myButton)); mouseLeftButtonDownOnMyButton = false; }; myButton.Click += myButtonCLickHandler; 并自己模拟点击

有点像这样的东西:

mouseLeftButtonDownOnMyButton

(当然,你需要在你的xaml模板中翻译它)

NB:这个还没有完成,你还应该注意用户在按钮上执行mouseDown但是在执行mouseup之前将鼠标移出按钮的情况(在这种情况下)你应该重置{{1}}标志。最好的方法可能是重置一般mouseUpEvent(例如在窗口级别)而不是按钮的标志。

编辑:上面的代码也允许您管理Click事件,并且只有一个代码用于实际和模拟点击事件(因此使用RaiseEvent方法),但是如果你没有不需要这个,你当然可以直接把你的代码放在PreviewMouseUp部分。

答案 1 :(得分:0)

我有同样的问题 - 我在模板列上使用Image并在MouseDown上有事件,但我不得不点击两次。所以我在构造函数上调用了事件处理程序,它对我有用。

你可以试试这个:

constructor() {
    datagridname.AddHandler(Button.ClickEvent, new RoutedEventHandler(Button_Click), true);
}

答案 2 :(得分:0)

另一个解决方案是创建自己的按钮。这样做的一个优点是:您不必为每个按钮连接事件。

public class FireOnPreviewButton : Button
{

    #region Constructor

    public FireOnPreviewButton()
    {
        PreviewMouseLeftButtonDown += OnLeftMouseButtonDownPreview;
    }

    #endregion

    #region Event Handler

    private void OnLeftMouseButtonDownPreview(object sender, MouseButtonEventArgs e)
    {
        // Prevent the event from going further
        e.Handled = true;

        // Invoke a click event on the button
        var peer = new ButtonAutomationPeer(this);
        var invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
        if (invokeProv != null) invokeProv.Invoke();
    }

    #endregion

}

答案 3 :(得分:0)

这可能不适合你,但设置为IsReadonly = true可以解决这个问题。

答案 4 :(得分:0)

我意识到这个问题已经过时但是我使用的是一份使用WPF和XAML的10年合约,我遇到了同样的问题,用户必须在数据网格中点击一行两次以激活鼠标按钮按下事件。这是因为datagrid使用第一次单击来选择行,而第二次单击则用于触发事件。我找到了一个更简单的解决方案,适用于我的应用程序:

        PreviewMouseLeftButtonDown="MainDataGrid_OnMouseLeftButtonDown"

这会在第一次单击时触发鼠标左键按下事件。这就是它在数据网格设置中的外观:

     <DataGrid Name="MainDataGrid" IsSynchronizedWithCurrentItem="True" SelectionMode="Extended" SelectionUnit="FullRow" 
         ...removed other options for brevity
         PreviewMouseLeftButtonDown="MainDataGrid_OnMouseLeftButtonDown"
         ...removed other options for brevity
         RowHeight="30" BorderThickness="0" Background="#99F0F0F0"  Grid.Column="{Binding GridColumn, Mode=TwoWay}" Grid.Row="1">

我用它而不是MouseLeftButtonDown。欢呼声。

答案 5 :(得分:0)

为时已晚,但对其他人则不然。

我一直面临同样的问题,花了近6个小时找到解决方法。我不想让别人再浪费时间。看到所有可能的答案后。这就是我修复它的方法:

我为主/父 DataGrid的已加载事件提供了一种方法。方法定义是:

private void FrameworkElement_OnLoaded(object sender, RoutedEventArgs e)
{
    var grid = sender as DataGrid;
    if (grid != null && grid.CurrentItem == null && grid.SelectedItem != null)
    {
        grid.CurrentItem = grid.SelectedItem;
    }
    else if (grid != null) //Fix when IsSynchronizedWithCurrentItem=True
    {
        var selectedItem = grid.SelectedItem;
        grid.CurrentItem = null;
        grid.SelectedItem = null;
        grid.CurrentItem = selectedItem;
        grid.SelectedItem = selectedItem;
    }
}