当用户点击它时,我需要折叠WPF DataGrid的详细信息行,并在再次单击时重新显示它。我还想使用单一选择来保留VisibleWhenSelected的DataGridRoDetailsVisibilityMode。
我想出了这个解决方案,基于其他地方的帖子:http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/0a45b3a7-46d0-45a9-84b2-0062f07f6fec#eadc8f65-fcc6-41df-9ab9-8d93993e114c
private bool _rowSelectionChanged;
private void dgCompletedJobs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_rowSelectionChanged = true;
}
private void dgCompletedJobsMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
DependencyObject dep = (DependencyObject)e.OriginalSource;
//navigate up the tree
while (dep != null &&
!(dep is DataGridCell) &&
!(dep is DataGridColumnHeader))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
{
return;
}
DataGridCell dgc = dep as DataGridCell;
if (dgc != null)
{
//navigate further up the tree
while (dep != null && !(dep is DataGridRow))
{
dep = VisualTreeHelper.GetParent(dep);
}
DataGridRow dgr = dep as DataGridRow;
DataGrid dg = sender as DataGrid;
if (dg != null && dgr != null)
{
if (dgr.IsSelected && !_rowSelectionChanged)
{
dg.RowDetailsVisibilityMode =
(dg.RowDetailsVisibilityMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
? DataGridRowDetailsVisibilityMode.Collapsed
: DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
}
else
{
dg.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
}
}
}
_rowSelectionChanged = false;
}
这似乎可以很好地解决我的问题,但我有一种令人难以置信的怀疑,这可以更简单和优雅地完成,特别是因为我在这个项目上使用MVVM。但是,我认为这是事件驱动的代码隐藏的可接受用法,因为它纯粹是表示逻辑。
有没有人有更清洁的解决方案?
答案 0 :(得分:5)
要使用“正确的”MVVM执行此操作,您应该将RowDetailsVisibilityMode绑定到视图模型上的属性:
<DataGrid x:Name="dgCompletedJobs" RowDetailsVisibilityMode="{Binding RowDetailsVisible}"/>
您的视图模型属性类似于:
private DataGridRowDetailsVisibilityMode _rowDetailsVisible;
public DataGridRowDetailsVisibilityMode RowDetailsVisible
{
get { return _rowDetailsVisible; }
set {
_rowDetailsVisible = value;
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("RowDetailsVisible"));
}
}
}
要将鼠标单击事件链接到更改属性,您可以按指示here执行某些花哨的附加行为,或者只使用后面的代码直接调用视图模型(我经常自己这样做)对于简单的任务):
private void dgCompletedJobsMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Window1ViewModel viewModel = (Window1ViewModel)DataContext;
if (viewModel.RowDetailsVisible == DataGridRowDetailsVisibilityMode.Collapsed) {
viewModel.RowDetailsVisible = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
} else {
viewModel.RowDetailsVisible = DataGridRowDetailsVisibilityMode.Collapsed;
}
}
答案 1 :(得分:1)
为什么不使用发件人参数?如果在DataGrid上定义了事件,则发件人始终是DataGrid!使用安全强制转换检查null是安全的,但这应该可以解决问题。
当您通过可视树从原始源恢复到DataGrid时,代码似乎不必要复杂。
private void dataGridMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DataGrid dg = sender as DataGrid;
if (dg == null)
return;
if (dg.RowDetailsVisibilityMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
dg.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed;
else
dg.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
}
答案 2 :(得分:0)
我想出了一个不同的方式,但不是&#34;正确的&#34; MVVM的方式,因为它使用了代码(正如上面提出的答案中的一些代码一样),但只需几行代码即可实现。
通过对PreviewMouseUp事件进行编码,我能够获得所需的确切行为。代码确保您实际上点击了网格中的某些内容并将其折叠,它必须是已经打开的同一行。
private void UIElement_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
DataGrid grid = sender as DataGrid;
if (grid != null)
{
FrameworkElement element = e.OriginalSource as FrameworkElement;
if (element?.DataContext is MyCustomObject)
{
if (grid.SelectedItem == (MyCustomObject) ((FrameworkElement) e.OriginalSource).DataContext)
{
grid.SelectedIndex = -1;
e.Handled = true;
}
}
}
}
答案 3 :(得分:0)
这结合了 Grafix 的答案和 Prethen 的答案。
如果您希望仅在已选择行时切换行详细信息,请使用它:
private void DataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is DataGrid dataGrid &&
e.OriginalSource is FrameworkElement frameworkElement &&
frameworkElement.DataContext == dataGrid.SelectedItem)
{
if (dataGrid.RowDetailsVisibilityMode == DataGridRowDetailsVisibilityMode.VisibleWhenSelected)
dataGrid.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.Collapsed;
else
dataGrid.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
}
}