Datagrid 模板列更新源触发器显式仅更新第一行

Datagrid templatecolumn update source trigger explicit only updates first row

我的XAML:

<DataGridTemplateColumn Header=" Student ID" Width="Auto">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBox x:Name="StudentIdTextBox"  Text="{Binding Path=StudentID, UpdateSourceTrigger=Explicit, Mode=TwoWay}" PreviewTextInput="ID_OnPreviewTextInput" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

我的 StudentManagementClass:

public class StudentManagement:INotifyPropertyChanged
{
    private string StudId;
    public bool Check { get; set; }
    public int ID { get; set; }
    public string StudentID
    {
        get { return StudId; }
        set
        {
            StudId = value;
            PropertyChanged(this, new PropertyChangedEventArgs("StudentID"));
        }
    }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Gender { get; set; }
    public string Birthdate { get; set; }
    public string MobileNumber { get; set; }
    public string Year { get; set; }
    public string Section { get; set; }
    public string Department { get; set; }
    public string Course { get; set; }
    public string Semester { get; set; }
    public List<string> AccessLevel { get; set; }
    public string AccessLevels { get; set; }
    public bool SetTime { get; set; }
    public string StartDate { get; set; }
    public string Expiration { get; set; }
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

示例代码:

public ObservableCollection<SM> StudentManagements { get; set; }

临时列表(我实际上只是在测试)

StudentManagements = new ObservableCollection<SM>();
List<string> AccessLevel = new List<string>();
AccessLevel.Add("a");
AccessLevel.Add("b");
AccessLevel.Add("c");
AccessLevel.Add("d");
AccessLevel.Add("e");
StudentManagements.Add(new SM()
{
    StudentID = "1111",
    AccessLevel = AccessLevel,
    AccessLevels = "a,c",
    Birthdate = "1/1/1993",
    Course = "",
    Department = "",
    Expiration = "1/1/1993",
    FirstName = "",
    Gender = "Male",
    LastName = "",
    MobileNumber = "09497740052",
    Section = "",
    Semester = "1st",
    StartDate = "1/1/1993",
    Year = "2nd",
    SetTime = true,
    ID = 1
});
StudentManagements.Add(new SM()
{
    StudentID = "2222",
    AccessLevel = AccessLevel,
    AccessLevels = "e,d",
    Birthdate = "1/1/1992",
    Course = "",
    Department = "",
    Expiration = "1/1/1992",
    FirstName = "",
    Gender = "Male",
    LastName = "",
    MobileNumber = "09497740052",
    Section = "",
    Semester = "1st",
    StartDate = "1/1/1994",
    Year = "2nd",
    SetTime = true,
    ID = 1
});

仅更新​​第一行而不是所有已编辑行的显式更新源按钮(请注意,我只是在测试它,这就是为什么我只在一列上尝试此操作的原因):

x = FindChild<TextBox>(AccessGrid, "StudentIdTextBox");
BindingExpression a = x.GetBindingExpression(TextBox.TextProperty);
a.UpdateSource();

我从这个人那里得到了 FindChild FindChild

我几乎和这个人有同样的问题,但没有人回答他的问题:dude with le same issue

然后我通过一个按钮刷新它们:

AccessGrid.ItemsSource = null;
AccessGrid.ItemsSource = StudentManagements;

现在,它有点工作了,我的 updatesourcetrigger 属性 设置为显式,所以我可以在单击按钮后保存更改,但只有第一行得到更新,还有其他方法可以更新sourcetrigger 属性 明确?

借助查找所有视觉后代的小方法(= 从模板定义实例化的框架元素)和一些检查后代是否为具有给定名称的文本框的 Linq 函数,您可以显式更新所有行的绑定视觉树。

这是帮手:

public static class VisualTreeHelperExtension
{
    struct StackElement
    {
        public FrameworkElement Element { get; set; }
        public int Position { get; set; }
    }
    public static IEnumerable<FrameworkElement> FindAllVisualDescendants(this FrameworkElement parent)
    {
        if (parent == null)
            yield break;
        Stack<StackElement> stack = new Stack<StackElement>();
        int i = 0;
        while (true)
        {
            if (i < VisualTreeHelper.GetChildrenCount(parent))
            {
                FrameworkElement child = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
                if (child != null)
                {
                    if (child != null)
                        yield return child;
                    stack.Push(new StackElement { Element = parent, Position = i });
                    parent = child;
                    i = 0;
                    continue;
                }
                ++i;
            }
            else
            {
                // back at the root of the search
                if (stack.Count == 0)
                    yield break;
                StackElement element = stack.Pop();
                parent = element.Element;
                i = element.Position;
                ++i;
            }
        }
    }
}

在按钮点击时,只需要调用helper :

private void Button_Click(object sender, RoutedEventArgs e)
{
    // to check :
    MessageBox.Show(StudentManagements[1].StudentID.ToString());

    var textboxes = AccessGrid.FindAllVisualDescendants()
        .Where(elt => elt.Name == "StudentIdTextBox" )
        .OfType<TextBox>();
    foreach (var textbox in textboxes)
    {
        BindingExpression binding = textbox.GetBindingExpression(TextBox.TextProperty);
        binding.UpdateSource();
    }
    // to check :
    MessageBox.Show(StudentManagements[1].StudentID.ToString());
}

应该有帮助,祝你好运