wpf 在 CellEditEnding 事件上修改 DataGrid 单元格值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34267840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Modifying DataGrid cell values on CellEditEnding event
提问by user5677774
I've been trying to change a different cell value in same row inside CellEditEnding eventhandler in WPF DataGrid control.
我一直在尝试在 WPF DataGrid 控件中的 CellEditEnding 事件处理程序内的同一行中更改不同的单元格值。
If I edit the cell value in an existing row, it works as expected. However, when adding a new row, the change is not reflected to UI if another cell value is clicked by mouse without going into edit mode.
如果我编辑现有行中的单元格值,它会按预期工作。但是,在添加新行时,如果在未进入编辑模式的情况下通过鼠标单击另一个单元格值,则更改不会反映到 UI。
Moving focus to next cell by pressing tab also works as expected, but shouldn't it work for clicking aswell?
通过按 Tab 键将焦点移到下一个单元格也可以按预期工作,但它不应该也适用于单击吗?
public MainWindow()
{
InitializeComponent();
DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn());
dataTable.Columns.Add(new DataColumn());
DataRow existingRow = dataTable.NewRow();
dataTable.Rows.Add(existingRow);
this.MyDataGrid.ItemsSource = dataTable.DefaultView;
this.MyDataGrid.CellEditEnding += MyDataGrid_CellEditEnding;
}
void MyDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
(e.Row.Item as DataRowView).Row[1] = "a string that should be displayed immediatly";
}
So far I've tried to change binding UpdateSourceTrigger, NotifyOnSourceUpdated and NotifyOnTargetUpdated but nothing seems to work. I've also tried to do according fixing by reading related topics : http://codefluff.blogspot.fi/2010/05/commiting-bound-cell-changes.html
到目前为止,我已经尝试更改绑定 UpdateSourceTrigger、NotifyOnSourceUpdated 和 NotifyOnTargetUpdated,但似乎没有任何效果。我也尝试通过阅读相关主题来进行修复:http: //codefluff.blogspot.fi/2010/05/commiting-bound-cell-changes.html
But those doesn't seem to help either..
但这些似乎也无济于事..
One way that I've found to be working is following snippet:
我发现工作的一种方法是以下代码段:
var frameworkElement = this.MyDataGrid.Columns[1].GetCellContent(e.Row);
frameworkElement.SetValue(TextBlock.TextProperty, "a string that should be displayed immediatly");
but I wouldn't want to do dependency on dependencyproperties as I might not know the underlying display type.
但我不想依赖dependencyproperties,因为我可能不知道底层显示类型。
So the question is that what could I do to achieve UI updation in new rows as it works with existing rows without using the provided second code snippet? I feel I am missing something..
所以问题是,在不使用提供的第二个代码片段的情况下,我可以做些什么来在新行中实现 UI 更新,因为它适用于现有行?我觉得我错过了一些东西..
Edit : Using ClipboardPaste will also work for setting new value but the original edited value will be lost for some reason.
编辑:使用 ClipboardPaste 也可用于设置新值,但由于某种原因,原始编辑值将丢失。
Edit2 : The xaml is currently plain DataGrid, I've tried to do columns and their bindings manually but as I haven't got them to work I've removed them to keep the example code simple
Edit2 :xaml 目前是普通的 DataGrid,我尝试手动做列和它们的绑定,但由于我没有让它们工作,我已经删除它们以保持示例代码简单
<DataGrid x:Name="MyDataGrid" />
Edit3 : Added this image to describe the problem better. So after clicking next cell I would like the text to be displayed Example image of the problem
Edit3 :添加此图像以更好地描述问题。因此,单击下一个单元格后,我希望显示文本 问题的示例图像
Edit4 : Using snoop to view the cell seems to set the element visible, also calling .UpdateTarget(); for the binding seems to help, but it's not working automaticly. Still wondering what is the cause..
Edit4:使用 snoop 查看单元格似乎将元素设置为可见,同时调用 .UpdateTarget(); 绑定似乎有帮助,但它不会自动工作。还在想是什么原因。。
Edit5: I would like this to work with DataTable as I need it's other features
Edit5:我希望它与 DataTable 一起使用,因为我需要它的其他功能
采纳答案by user5677774
After testing huge amount of different kind of solutions I ended up adding the row when starting to edit a cell. As the feature I was seeking was working in existing rows it did fix the problem.
在测试了大量不同类型的解决方案后,我最终在开始编辑单元格时添加了该行。由于我正在寻找的功能在现有行中工作,它确实解决了问题。
public class MyDataGrid : DataGrid
{
protected override void OnBeginningEdit(DataGridBeginningEditEventArgs e)
{
base.OnBeginningEdit(e);
this.CommitEdit();
}
protected override void OnCellEditEnding(DataGridCellEditEndingEventArgs e)
{
base.OnCellEditEnding(e);
(e.Row.Item as DataRowView).Row[1] = "a string that should be displayed immediatly";
}
}
回答by Ilan
I suggest you to use the MVVM way and then you will meet your requirements by a built-in notification mechanism of WPF itself, where on upfdate of some property in data context you can trigger update of another property. Example: 1. Xaml code:
我建议您使用 MVVM 方式,然后您将通过 WPF 本身的内置通知机制满足您的要求,在更新数据上下文中的某些属性时,您可以触发另一个属性的更新。示例: 1. Xaml 代码:
<Window x:Class="DataGridSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dataGridSoHelpAttempt="clr-namespace:DataGridSoHelpAttempt"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<dataGridSoHelpAttempt:MainViewModel/>
</Window.DataContext>
<Grid>
<DataGrid x:Name="MyDataGrid" ItemsSource="{Binding DataSource}"/>
</Grid></Window>
2. View model code:
2.查看型号代码:
public class MainViewModel:BaseObservableObject
{
public MainViewModel()
{
DataSource = new ObservableCollection<BaseData>(new List<BaseData>
{
new BaseData {Name = "John"},
new BaseData {Name = "Ron"},
new BaseData {Name = "Bob"},
});
}
public ObservableCollection<BaseData> DataSource { get; set; }
}
3. Model code:
3. 型号代码:
public class BaseData:BaseObservableObject
{
private string _name;
private string _description;
public virtual string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
Description = "a string that should be displayed immediatly";
}
}
public virtual object Description
{
get { return _description; }
set
{
_description = (string) value;
OnPropertyChanged();
}
}
}
4. BaseObservableObject a basic INotifyPropertyChanged implementation:
4. BaseObservableObject 一个基本的 INotifyPropertyChanged 实现:
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
5. Please keep in mind that your model's properties objects can be complex (like images or classes that describe another view models) but in this case you have to template your data grid columns or/and cells (example link: WPF DataGrid Control).
5. 请记住,您的模型的属性对象可能很复杂(如描述另一个视图模型的图像或类),但在这种情况下,您必须对数据网格列或/和单元格进行模板化(示例链接:WPF DataGrid Control)。
I'll really happy to help in case you'll have problems with code. Regards
如果您遇到代码问题,我将非常乐意为您提供帮助。问候
Update1. Code behind - you should update DataTable, but please take in account that update have to be performed on row that already exists in Table:
更新1. 后面的代码 - 您应该更新 DataTable,但请注意必须对 Table 中已存在的行执行更新:
public partial class MainWindow : Window
{
private readonly DataTable _dataTable;
public MainWindow()
{
InitializeComponent();
this.MyDataGrid.CellEditEnding += MyDataGrid_CellEditEnding;
_dataTable = new DataTable();
_dataTable.Columns.Add(new DataColumn());
_dataTable.Columns.Add(new DataColumn());
DataRow existingRow = _dataTable.NewRow();
_dataTable.Rows.Add(existingRow);
this.MyDataGrid.ItemsSource = _dataTable.DefaultView;
}
void MyDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var dataRowView = (e.Row.Item as DataRowView);
var columnIndex = e.Column.DisplayIndex;
var rowIndex = e.Row.GetIndex();
var dv = _dataTable.DefaultView;
var nextColumnIndex = columnIndex + 1;
if (dv.Table.Columns.Count <= nextColumnIndex || dv.Table.Rows.Count <= rowIndex) return;
dv.Table.Rows[rowIndex][nextColumnIndex] = "a string that should be displayed immediatly";
}
}
2. Xaml:
2. Xml:
<Window x:Class="GridViewWitaFDataTableSoHelpAttempt.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="MyDataGrid" />
</Grid></Window>

