我有一个像这样的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点击行为。
我在这里缺少什么?无论是否选择了行,如何只需单击一次即可获得该点击事件?
答案 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;
}
}