C# WPF 如何在以编程方式更新数据网格后更新可观察集合 - 无 MVVM
C# WPF how to update observable collection after having programmatically updated datagrid - No MVVM
我有一个与可观察集合链接的数据网格。
他们有大量columns/properties我要操作。
我需要在运行时通过组合框对用户选择的列进行字符串替换。
所以我首先要做的是找出列的索引(在我们的例子中 Description index=2 从 0 开始)然后用下面的代码进行替换。变量 iii 表示当前行
DataGridRow row = (DataGridRow)dtgFeatures.ItemContainerGenerator.ContainerFromIndex(iii);
if (row != null)
{
var content = dtgFeatures.Columns[indexColumnToOperateOn].GetCellContent(row);
if (content != null)
{
string str = ((TextBlock)content).Text;
if (str.ToUpper().Trim().Contains(tbxSrc.Text.ToUpper().Trim()))
{
((TextBlock)content).Text = str.Replace(tbxSrc.Text, tbxDest.Text);
obcCfgPartPrograms = (ObservableCollection < CfgPartPrograms >) dtgFeatures.ItemsSource;
}
}
}
在我们的示例中,我们可以将字符串 "pcacd" 更改为 "AAA"
因此 "graphically" 可以工作,但可观察集合不会使用命令 obcCfgPartPrograms = (ObservableCollection < CfgPartPrograms >) dtgFeatures.ItemsSource;
进行备份更新
我知道我可以通过每个属性来做到这一点,但这对
--编辑--
抱歉,从我看到的评论中我没有说清楚。我的错。
所以我有很多属性(这里有 9 个,但可能更多)所以我不会写这样的东西:
if(comboBoxValue="Description")
obc.Description = dtgFeatures[2,row];
else if(comboBoxValue="Notes")
obc.Description = dtgFeatures[4,row];
...
因为我可以手动编辑数据网格并将更改反映在可观察集合上
datagrid MANUAL EDIT ---> changes on observable collection
为什么不能以编程方式(例如使用字符串比较)编辑数据网格并将更改反映在 obc 上?
datagrid AUTOMATIC EDIT ---> changes on observable collection
简而言之:
1. 我可以更改数据网格 --> dtgFeatures[property_X,row_Y] = "AAAAAA";
2.我希望能够自动改变obc[Y].X = "AAAAAA";
数量非常多。
感谢您的帮助
帕特里克
您应该改为修改 ObservableCollection
中的数据。通常,始终避免操纵 UI 控件。修改您的数据,并在必要时引发 OnPropertyChanged
事件。
如果 TextBlock
绑定到 CfgPartPrograms
对象的源 属性,您可以使用 GetBindingExpression
获取此 属性 的名称方法。然后,您可以使用反射将 属性 设置为新值:
DataGridRow row = (DataGridRow)dtgFeatures.ItemContainerGenerator.ContainerFromIndex(iii);
if (row != null)
{
var content = dtgFeatures.Columns[indexColumnToOperateOn].GetCellContent(row);
if (content != null)
{
TextBlock textBlock = (TextBlock)content;
if (textBlock.Text.ToUpper().Trim().Contains(tbxSrc.Text.ToUpper().Trim()))
{
string str = textBlock.Text.Replace(tbxSrc.Text, tbxDest.Text);
textBlock.Text = str;
BindingExpression be = textBlock.GetBindingExpression(TextBlock.TextProperty);
if (be != null && be.ParentBinding != null && be.ParentBinding.Path != null && !string.IsNullOrEmpty(be.ParentBinding.Path.Path))
{
object cfgPartPrograms = textBlock.DataContext;
if (cfgPartPrograms != null)
{
System.Reflection.PropertyInfo pi = typeof(CfgPartPrograms).GetProperty(be.ParentBinding.Path.Path);
if (pi != null)
pi.SetValue(cfgPartPrograms, str);
}
}
}
}
}
是的,可以做到。要经过的路径如下:
想象一下 class:
public class MyClass
{
public string s1 { get; set; }
public string s2 { get; set; }
public string s3 { get; set; }
public MyClass(string _s1, string _s2, string _s3)
{
s1 = _s1;
s2 = _s2;
s3 = _s3;
}
}
现在我们可以创建并填充 obc:
var obc = new ObservableCollection<MyClass>();
obc.Add(new MyClass("a1","a2","a3"));
obc.Add(new MyClass("b1", "b2","b3"));
我们可以修改为:
foreach (var itemObc in obc)
{
PropertyInfo[] Fields = itemObc.GetType().GetProperties();
foreach (PropertyInfo field in Fields)
{
var currentField = field.GetValue(itemObc, null);
var t = currentField.GetType();
if (t == typeof(string))
field.SetValue(itemObc, "XXXX");
}
}
结果是:
您甚至可以使用扩展程序:
public static class ObservableCollectionExtensions
{
public static ObservableCollection<T> SetValue<T>(this ObservableCollection<T> obc, int rowNumFromZero, int propNumFromZero, string str)
{
int rowCounter = -1;
foreach (var itemObc in obc)
{
rowCounter++;
PropertyInfo[] Fields = itemObc.GetType().GetProperties();
int propCounter = -1;
foreach (PropertyInfo field in Fields)
{
propCounter++;
if (rowCounter == rowNumFromZero)
{
var currentField = field.GetValue(itemObc, null);
if (currentField != null)
{
var t = currentField.GetType();
if (t == typeof(string) && propCounter == propNumFromZero)
field.SetValue(itemObc, str);
}
}
}
}
return obc;
}
}
并像这样使用它:
obc.SetValue(numRow, numCol, strNewValue);
我有一个与可观察集合链接的数据网格。
他们有大量columns/properties我要操作。
我需要在运行时通过组合框对用户选择的列进行字符串替换。
DataGridRow row = (DataGridRow)dtgFeatures.ItemContainerGenerator.ContainerFromIndex(iii);
if (row != null)
{
var content = dtgFeatures.Columns[indexColumnToOperateOn].GetCellContent(row);
if (content != null)
{
string str = ((TextBlock)content).Text;
if (str.ToUpper().Trim().Contains(tbxSrc.Text.ToUpper().Trim()))
{
((TextBlock)content).Text = str.Replace(tbxSrc.Text, tbxDest.Text);
obcCfgPartPrograms = (ObservableCollection < CfgPartPrograms >) dtgFeatures.ItemsSource;
}
}
}
在我们的示例中,我们可以将字符串 "pcacd" 更改为 "AAA"
因此 "graphically" 可以工作,但可观察集合不会使用命令 obcCfgPartPrograms = (ObservableCollection < CfgPartPrograms >) dtgFeatures.ItemsSource;
进行备份更新我知道我可以通过每个属性来做到这一点,但这对
--编辑-- 抱歉,从我看到的评论中我没有说清楚。我的错。
所以我有很多属性(这里有 9 个,但可能更多)所以我不会写这样的东西:
if(comboBoxValue="Description")
obc.Description = dtgFeatures[2,row];
else if(comboBoxValue="Notes")
obc.Description = dtgFeatures[4,row];
...
因为我可以手动编辑数据网格并将更改反映在可观察集合上
datagrid MANUAL EDIT ---> changes on observable collection
为什么不能以编程方式(例如使用字符串比较)编辑数据网格并将更改反映在 obc 上?
datagrid AUTOMATIC EDIT ---> changes on observable collection
简而言之: 1. 我可以更改数据网格 --> dtgFeatures[property_X,row_Y] = "AAAAAA"; 2.我希望能够自动改变obc[Y].X = "AAAAAA";
数量非常多。
感谢您的帮助 帕特里克
您应该改为修改 ObservableCollection
中的数据。通常,始终避免操纵 UI 控件。修改您的数据,并在必要时引发 OnPropertyChanged
事件。
如果 TextBlock
绑定到 CfgPartPrograms
对象的源 属性,您可以使用 GetBindingExpression
获取此 属性 的名称方法。然后,您可以使用反射将 属性 设置为新值:
DataGridRow row = (DataGridRow)dtgFeatures.ItemContainerGenerator.ContainerFromIndex(iii);
if (row != null)
{
var content = dtgFeatures.Columns[indexColumnToOperateOn].GetCellContent(row);
if (content != null)
{
TextBlock textBlock = (TextBlock)content;
if (textBlock.Text.ToUpper().Trim().Contains(tbxSrc.Text.ToUpper().Trim()))
{
string str = textBlock.Text.Replace(tbxSrc.Text, tbxDest.Text);
textBlock.Text = str;
BindingExpression be = textBlock.GetBindingExpression(TextBlock.TextProperty);
if (be != null && be.ParentBinding != null && be.ParentBinding.Path != null && !string.IsNullOrEmpty(be.ParentBinding.Path.Path))
{
object cfgPartPrograms = textBlock.DataContext;
if (cfgPartPrograms != null)
{
System.Reflection.PropertyInfo pi = typeof(CfgPartPrograms).GetProperty(be.ParentBinding.Path.Path);
if (pi != null)
pi.SetValue(cfgPartPrograms, str);
}
}
}
}
}
是的,可以做到。要经过的路径如下:
想象一下 class:
public class MyClass
{
public string s1 { get; set; }
public string s2 { get; set; }
public string s3 { get; set; }
public MyClass(string _s1, string _s2, string _s3)
{
s1 = _s1;
s2 = _s2;
s3 = _s3;
}
}
现在我们可以创建并填充 obc:
var obc = new ObservableCollection<MyClass>();
obc.Add(new MyClass("a1","a2","a3"));
obc.Add(new MyClass("b1", "b2","b3"));
我们可以修改为:
foreach (var itemObc in obc)
{
PropertyInfo[] Fields = itemObc.GetType().GetProperties();
foreach (PropertyInfo field in Fields)
{
var currentField = field.GetValue(itemObc, null);
var t = currentField.GetType();
if (t == typeof(string))
field.SetValue(itemObc, "XXXX");
}
}
结果是:
您甚至可以使用扩展程序:
public static class ObservableCollectionExtensions
{
public static ObservableCollection<T> SetValue<T>(this ObservableCollection<T> obc, int rowNumFromZero, int propNumFromZero, string str)
{
int rowCounter = -1;
foreach (var itemObc in obc)
{
rowCounter++;
PropertyInfo[] Fields = itemObc.GetType().GetProperties();
int propCounter = -1;
foreach (PropertyInfo field in Fields)
{
propCounter++;
if (rowCounter == rowNumFromZero)
{
var currentField = field.GetValue(itemObc, null);
if (currentField != null)
{
var t = currentField.GetType();
if (t == typeof(string) && propCounter == propNumFromZero)
field.SetValue(itemObc, str);
}
}
}
}
return obc;
}
}
并像这样使用它:
obc.SetValue(numRow, numCol, strNewValue);