gpt4 book ai didi

c# - Mode=TwoWay 返回 Null

转载 作者:太空宇宙 更新时间:2023-11-03 12:21:06 25 4
gpt4 key购买 nike

经过很多小时,我终于找到了导致该错误的问题所在。在显示出现问题的代码之前,我需要解释一下情况。

绑定(bind)和属性结构

在我的应用程序中有一个 ComboBox绑定(bind)为 ItemSource Rounds 的列表和 SelectedItem Round由用户从列表中选择。

ComboBox有这样的结构:

<ComboBox ItemsSource="{Binding Rounds}" DisplayMemberPath="RoundName" SelectedItem="{Binding SelectedRound, Mode=TwoWay}" />

如你所见,我已经作为模态 TwoWay这允许我更新属性 SelectedRound当用户更改 Item 时自动已选中。

这是类 Round :

public class Round
{
public int Id { get; set; }
public string Link { get; set; }
public bool Selected { get; set; }
public string RoundName { get; set; }
}

这是 ComboBox 使用的属性:

//List of rounds available
private List<Round> _rounds;
public List<Round> Rounds
{
get { return _rounds; }
set
{
_rounds = value;
OnPropertyChanged();
}
}

//Selected round on ComboBox
private Round _selectedRound;
public Round SelectedRound
{
get { return _selectedRound; }
set
{
_selectedRound = value;
OnPropertyChanged();
}
}

这两个属性都实现了 OnPropertyChanged() .

属性增值如何运作

在应用程序中有一个名为 LoadRounds() 的方法每次用户按下按钮时调用,此方法有以下指令:

public void LoadRounds(Team team)
{
//Fill the source of ComboBox with the rounds of the new team
Rounds = team.Rounds.ToList(); //<- Create a copy, so no reference

//Get the selected round
SelectedRound = Rounds?.FirstOrDefault(x => x.Id == team.CurrentRound.Id);
}

SelectedRound取自 team属性名为 CurrentRound ,特别是每个 team有一个回合,所以作为一个练习示例:

[Rounds id available in Rounds property]
37487
38406
38405
37488
37486
...

[CurrentRound id of team]
38405

所以SelectedRound将包含 RoundId 38405 和 linq查询运行良好。

问题

我设置了一个 breakpoint_selectedRound = value; , 第一次触发时间 valueRound项目 (38405),但还有第二个触发时间(不应该是)的值为 null .

我在电脑上花了很多时间来理解为什么会发生这种情况。

似乎 ComboBox (TwoWay 模式)不知道如何映射 SelectedRound来自 ItemSource ,所以本质上:

1. [Item Source updated with new Rounds]
2. [SelectedRound updated from the new `Rounds` available]
3. [SelectedRound setter called again with a null value]

我还使用了堆栈调用窗口来查看是否有任何方法再次调用 setter 属性,但是没有调用 setter 的外部方法,所以我猜是 TwoWay再次触发二传手的模式。

我该如何解决这种情况?我知道这篇文章有点复杂,我可以回答所有问题,并在需要时提供更多详细信息。

谢谢大家,祝你有美好的一天。

更新#1

这是我的 INotifyPropertyChanged实现:

public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
}

更新#2

  1. 方法LoadRounds当用户更改 DataGrid 上的选择时调用, DataGrid包含所有 teams ,所以我得到了 team由用户在 DataGrid 上选择, 然后调用方法 LoadRounds .

  2. 所有团队都包含在 DataGrid 中, ItemSourceList<Team> .

  3. 方法结束LoadRounds我保存当前RoundTeam在名为 SelectedRoundSaved 的特性上,简单地做:

    SelectedRoundSaved = Clone(SelectedRound);

通过这种方式我可以防止重新加载 Rounds如果SelectedRoundSaved等于SelectedRound .

Clone方法允许我克隆对象,并具有以下结构:

 public T Clone<T>(T source)
{
if (ReferenceEquals(source, null))
{
return default(T);
}

var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}

它使用 NewtonSoft.Json图书馆。

这些信息根本不是必需的,但正如我所说,我会添加所有要求您提供的信息,感谢您的关注。

最佳答案

你确定这个顺序是正确的吗?

1. [Item Source updated with new Rounds]
2. [SelectedRound updated from the new `Rounds` available]
3. [SelectedRound setter called again with a null value]

最初绑定(bind)组合框后,我希望顺序是(交换#2 和#3 的顺序)

1. [Item Source updated with new Rounds]
2. [SelectedRound setter called again with a null value]
3. [SelectedRound updated from the new `Rounds` available]

此行为符合我对组合框的预期。当您更新 ItemSource 时,ComboBox 会转储其项目并使用新集合重新加载。因为 ComboBox 是一个选择器,所以它必须检查其 SelectedItem。如果在新集合中未找到其 SelectedItem,它会将其 SelectedItem 更新为 null。所有这一切的发生仅仅是因为 Rounds setter 中的 OnPropertyChanged(); 调用。(注意:您只会在加载和绑定(bind)组合框后看到此行为)

现在有很多方法可以处理这个问题,但在我看来最简单的就是改变操作顺序:

public void LoadRounds(Team team)
{
//Fill the source of ComboBox with the rounds of the new team
var newRounds = team.Rounds.ToList(); //<- Create a copy, so no reference

//Get the selected round
SelectedRound = newRounds.FirstOrDefault(x => x.Id == team.CurrentRound.Id);
Rounds = newRounds;
}

关于c# - Mode=TwoWay 返回 Null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47179883/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com