我有一个带有模板列的数据网格,它嵌套了另一个数据网格。当我在主数据网格上编辑一个人的名字,然后双击编辑嵌套项目时,主要的一个不会失去焦点,以便单元格保持编辑模式。
我通过为嵌套数据网格注册GotFocus事件来处理它,使用自定义FindAncestor函数在可视树中查找父数据网格并在主数据网格上调用CancelEdit()。
private void DataGridItem_GotFocus(object sender, RoutedEventArgs e)
{
var dg =(DataGrid)FindAncestor((DependencyObject)sender, typeof(DataGrid), 2);
dg.CancelEdit();
}
这实在是太过分了。是否有一种不同的MVVM方式可以解决这个问题?
以下是此简化示例的完整代码。
XAML
<Grid>
<DataGrid x:Name="DataGrid1"
ItemsSource="{Binding DataCollection}"
SelectedItem="{Binding DataCollectionSelectedItem}"
AutoGenerateColumns="False"
CanUserAddRows="false" >
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="LightBlue"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="2*" />
<DataGridTemplateColumn Header="Item/Price" Width="3*">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<DataGrid x:Name="DataGridItem"
ItemsSource="{Binding Items}"
SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ItemsSelectedItem}"
GotFocus="DataGridItem_GotFocus"
Background="Transparent"
HeadersVisibility="None"
AutoGenerateColumns="False"
CanUserAddRows="false" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ItemName}" Width="*"/>
<DataGridTextColumn Binding="{Binding Price}" Width="50"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
C#
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace datagrid_focus
{
public class Item : NotifyObject
{
private string _itemName;
public string ItemName
{
get { return _itemName; }
set { _itemName = value; OnPropertyChanged("ItemName"); }
}
private double _price;
public double Price
{
get { return _price; }
set { _price = value; OnPropertyChanged("Price"); }
}
}
public class Person : NotifyObject
{
public ObservableCollection<Item> Items { get; set; }
private string _name;
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
}
public double Total
{
get { return Items.Sum(i => i.Price); }
set { OnPropertyChanged("Total"); }
}
}
public abstract class NotifyObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public class ViewModel : NotifyObject
{
public ObservableCollection<Person> DataCollection { get; set; }
public Person DataCollectionSelectedItem { get; set; }
public Item ItemsSelectedItem { get; set; }
public ViewModel()
{
DataCollection = new ObservableCollection<Person>
{
new Person {Name = "Siegmund Freud", Items = new ObservableCollection<Item> {
new Item { ItemName = "Phone", Price = 220 },
new Item { ItemName = "Tablet", Price = 350 },
} },
new Person {Name = "Karl Popper", Items = new ObservableCollection<Item> {
new Item { ItemName = "Teddy Bear Deluxe", Price = 2200 },
new Item { ItemName = "Pokemon", Price = 100 }
}}
};
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
public DependencyObject FindAncestor(DependencyObject current, Type type, int levels)
{
int currentLevel = 0;
while (current != null)
{
if (current.GetType() == type)
{
currentLevel++;
if (currentLevel == levels)
{
return current;
}
}
current = VisualTreeHelper.GetParent(current);
};
return null;
}
private void DataGridItem_GotFocus(object sender, RoutedEventArgs e)
{
var dg =(DataGrid)FindAncestor((DependencyObject)sender, typeof(DataGrid), 2);
//dg.CancelEdit();
}
}
}