I have a DataGrid that contains information from a settings object. Currently there is two-way binding between the DataGrid and settings object. However, I want to put a "Save" button in that only binds changes made in the DataGrid to the object if the user clicks the Save button. However, I'm not sure how to call UpdateSource() for my particular case with my DataGrid.
Here is my xaml.cs code:
public void LoadDataFields(Data d)
{
Grid1.ItemsSource = d.Fields;
}
private void SaveChanges(object sender, RoutedEventArgs e)
{
BindingExpression be = Grid1.GetBindingExpression(DataGrid.ItemsSourceProperty);
be.UpdateSource();
}
Here is my xaml code:
<DataGrid x:Name="Grid1"
IsReadOnly="False"
Height="360"
Margin="20,15,20,15"
VerticalAlignment="Top"
AutoGenerateColumns="False"
CanUserAddRows="False" SelectionUnit="Cell"
ItemsSource="{Binding data}"
>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Field">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=name, Mode=TwoWay, UpdateSourceTrigger=Explicit}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Length of Field">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=length, Mode=TwoWay, UpdateSourceTrigger=Explicit}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Is there an easy way to call UpdateSource() so that the binding only takes place if the Save button is clicked? My guess is that I'm just putting the wrong property in for the the GetBindingExpression method.
Yes, there is a way, but it is not a very very easy way. First of all you need 2 helper methods:
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
Visual visual;
T child = default(T);
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
visual = (Visual)VisualTreeHelper.GetChild(parent, i);
child = visual as T;
if (child == null)
{
child = GetVisualChild<T>(visual);
}
if (child != null)
{
break;
}
}
return child;
}
public T FindVisualChild<T>(DependencyObject obj, string name) where T : DependencyObject
{
DependencyObject child;
FrameworkElement frameworkElement;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
child = VisualTreeHelper.GetChild(obj, i);
frameworkElement = child as FrameworkElement;
if (child != null && child is T && frameworkElement != null && frameworkElement.Name == name)
{
return (T)child;
}
else
{
T childOfChild = FindVisualChild<T>(child, name);
if (childOfChild != null)
{
return childOfChild;
}
}
}
return null;
}
Then you have to give a name to your binded controls. For example "textBox":
<DataGridTemplateColumn Header="Field">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="textBox" Text="{Binding Path=name, Mode=TwoWay, UpdateSourceTrigger=Explicit}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Length of Field">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="textBox" Text="{Binding Path=length, Mode=TwoWay, UpdateSourceTrigger=Explicit}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Then in your SaveChanges
method, you can use this code:
private void SaveChanges(object sender, RoutedEventArgs e)
{
DataGridRow dataGridRow;
DataGridCellsPresenter dataGridCellsPresenter;
DataGridCell dataGridCell;
TextBox textBox;
BindingExpression bindingExpression;
for (int i = 0; i < Grid1.Items.Count; i++)
{
dataGridRow = (DataGridRow)Grid1.ItemContainerGenerator.ContainerFromIndex(i);
dataGridCellsPresenter = GetVisualChild<DataGridCellsPresenter>(dataGridRow);
for (int j = 0; j < Grid1.Columns.Count; j++)
{
dataGridCell = (DataGridCell)dataGridCellsPresenter.ItemContainerGenerator.ContainerFromIndex(j);
textBox = FindVisualChild<TextBox>(dataGridCell, "textBox");
if (textBox != null)
{
bindingExpression = BindingOperations.GetBindingExpression(textBox, TextBox.TextProperty);
bindingExpression.UpdateSource();
}
}
}
}
I hope it can help you.