Reputation: 2583
I have a datagrid linked with an observable collection.
They have a large number of columns/properties I have to operate on.
I need to do a string replace on a column chosen by the user at the runtime through a combobox.
So what I do at first is to find out the index of the column (in our case Description index=2 starting from 0) and then operate the substitutions with the code below. The variable iii indicates the current row
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;
}
}
}
In our example we can change the string "pcacd" with "AAA"
So that "graphically" works but the observable collection is not back-updated with the command obcCfgPartPrograms = (ObservableCollection < CfgPartPrograms >) dtgFeatures.ItemsSource;
I know I could do that through each properties but that would be ackward for
--EDIT-- Sorry from the comments I see I have not made it clear. My bad.
So I have a very large number of properties (here 9 but potentially many many more) so I would not write something like:
if(comboBoxValue="Description")
obc.Description = dtgFeatures[2,row];
else if(comboBoxValue="Notes")
obc.Description = dtgFeatures[4,row];
...
Since I can MANUALLY edit the datagrid and reflect the changes on the observable collection
datagrid MANUAL EDIT ---> changes on observable collection
why not having the possibility of PROGRAMMATICALLY (e.g. with string compare) edit the datagrid and reflect the changes on the obc?
datagrid AUTOMATIC EDIT ---> changes on observable collection
So in short: 1. I am able to change the datagrid --> dtgFeatures[property_X,row_Y] = "AAAAAA"; 2. I would like to be able to automatically change obc[Y].X = "AAAAAA";
there are a very large number of them.
Thanks for any help Patrick
Upvotes: -1
Views: 1094
Reputation: 169200
If the TextBlock
is bound to a source property of the CfgPartPrograms
object, you could get the name of this property using the GetBindingExpression
method. You could then use reflection to set the property to a new value:
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);
}
}
}
}
}
Upvotes: 1
Reputation:
Yes, that can be done. The path to go through is the following:
imagine having the following 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;
}
}
So now we can create and fill the obc:
var obc = new ObservableCollection<MyClass>();
obc.Add(new MyClass("a1","a2","a3"));
obc.Add(new MyClass("b1", "b2","b3"));
We can modify it with:
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");
}
}
and the result is:
You might even use extensions:
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;
}
}
and use it like that:
obc.SetValue(numRow, numCol, strNewValue);
Upvotes: 2
Reputation: 5042
You should modify the data in the ObservableCollection
instead. Generally, always avoid manipulating the UI controls. Modify your data and, if necessary, raise OnPropertyChanged
event.
Upvotes: 0