wpf 您如何调用 UpdateSource() 以在 DataGrid 上进行显式绑定?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30789890/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:12:16  来源:igfitidea点击:

How do you call UpdateSource() for explicit binding on a DataGrid?

c#wpfxamldatagridupdatesourcetrigger

提问by reubonwry

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.

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

Here is my xaml.cs code:

这是我的 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();
        }

Here is my xaml code:

这是我的 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>

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.

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

采纳答案by Il Vic

Yes, there is a way, but it is not a very very easy way. First of all you need 2 helper methods:

是的,有一种方法,但它不是一个非常容易的方法。首先,您需要 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;
}

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 SaveChangesmethod, you can use this code:

然后在您的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();
            }
        }
    }
}

I hope it can help you.

我希望它能帮助你。

回答by Olaru Mircea

You can try to name your TextBoxes unde use the following syntax:

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

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

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

But i would bind to a secondary collection or a copy of an object if i do not want changes to apply immediately, and save the updates to the main list at the user request. When the bounded list is modified again, items changed, removed or added, you may clear the secondary list and do a fresh copy. Or .. if maybe the user wants to revert the changes, clear the bounded one and copy the items from the back.

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