5

我有一个包含来自设置对象的信息的 DataGrid。目前 DataGrid 和设置对象之间存在双向绑定。但是,我想放置一个“保存”按钮,如果用户单击“保存”按钮,它只会将 DataGrid 中所做的更改绑定到对象。但是,我不确定如何使用我的 DataGrid 为我的特殊情况调用 UpdateSource()。

这是我的 xaml.cs 代码:

public void LoadDataFields(Data d)
        {
            Grid1.ItemsSource = d.Fields;
        }

private void SaveChanges(object sender, RoutedEventArgs e)
        {
            BindingExpression be = Grid1.GetBindingExpression(DataGrid.ItemsSourceProperty);
            be.UpdateSource();
        }

这是我的 xaml 代码:

<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>

是否有一种简单的方法可以调用 UpdateSource() 以便仅在单击“保存”按钮时才进行绑定?我的猜测是我只是为 GetBindingExpression 方法输入了错误的属性。

4

2 回答 2

4

是的,有一种方法,但这不是一个非常简单的方法。首先,您需要 2 个辅助方法:

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;
}

然后,您必须为绑定的控件命名。例如“文本框”:

<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>

然后在您的SaveChanges方法中,您可以使用以下代码:

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();
            }
        }
    }
}

我希望它可以帮助你。

于 2015-06-11T20:28:24.960 回答
2

您可以尝试使用以下语法命名您的文本框:

 BindingExpression be = tbName.GetBindingExpression(TextBox.TextProperty);
 be.UpdateSource();

 BindingExpression be2 = tbLength.GetBindingExpression(TextBox.TextProperty);
 be2.UpdateSource();

但是如果我不想立即应用更改,我会绑定到辅助集合或对象的副本,并应用户请求将更新保存到主列表。当有界列表再次修改,项目更改,删除或添加时,您可以清除二级列表并重新复制。或者..如果用户可能想要还原更改,请清除有界的并从后面复制项目。

于 2015-06-11T20:25:24.887 回答