C# 为什么DependencyProperty.UnsetValue被传递到Equals()中
我正在开发一个简单的WPF应用程序。目前,该应用程序仅管理组合框中的视频游戏列表。游戏列表被序列化到XML文件中/从XML文件中序列化 当前被破坏的功能是从组合框中选择游戏的能力,这使其成为要管理的“活动”游戏。活动游戏将存储为应用程序设置。为了实现这一点,我使用双向数据绑定,并将组合框中的SelectedItem绑定到ViewModel中的SelectedName 当我运行应用程序并从组合框中选择一个项目时,我在Game.Equals(Game-other)方法上得到一个空引用异常。调试时,我看到DependencyProperty.UnsetValue作为参数传递给重写的Game.Equals(object obj)方法,该方法导致C# 为什么DependencyProperty.UnsetValue被传递到Equals()中,c#,wpf,mvvm,combobox,C#,Wpf,Mvvm,Combobox,我正在开发一个简单的WPF应用程序。目前,该应用程序仅管理组合框中的视频游戏列表。游戏列表被序列化到XML文件中/从XML文件中序列化 当前被破坏的功能是从组合框中选择游戏的能力,这使其成为要管理的“活动”游戏。活动游戏将存储为应用程序设置。为了实现这一点,我使用双向数据绑定,并将组合框中的SelectedItem绑定到ViewModel中的SelectedName 当我运行应用程序并从组合框中选择一个项目时,我在Game.Equals(Game-other)方法上得到一个空引用异常。调试时,我
obj as Game
将obj设为null
我不明白为什么当我所做的只是从ComboBox值中选择一个项时,首先会调用Equals,所以我猜这是WPF的固有特性。代码在转到Equals方法之前似乎没有碰到任何其他断点,因此我甚至不确定如何调试该问题。我也不明白DependencyProperty.UnsetValue是从哪里来的。我在这里完全迷失了方向,希望能有任何见解,包括如何进一步调试
编辑:正如格伦所提到的,WPF的某些底层组件必须调用Equals。至少就目前而言,我的解决方案是简单地在Equals覆盖中添加一个空检查
模型类
public class Game : IEntity, IEquatable<Game>
{
[XmlElement("Name")]
public string Name { get; set; }
[XmlElement("ExecutablePath")]
public string ExecutablePath { get; set; }
public Game(string name, string executablePath)
{
Name = name;
ExecutablePath = executablePath;
}
private Game() { } // Required for XML serialization.
public bool Equals(Game other)
{
return Name.EqualsIgnoreCase(other.Name);
}
public override bool Equals(object obj)
{
return Equals(obj as Game);
}
}
公共类游戏:易学,易学
{
[XmlElement(“名称”)]
公共字符串名称{get;set;}
[XmlElement(“可执行路径”)]
公共字符串可执行路径{get;set;}
公共游戏(字符串名称、字符串可执行路径)
{
名称=名称;
可执行路径=可执行路径;
}
XML序列化需要private Game(){}//。
公共布尔等于(游戏其他)
{
返回Name.EqualsIgnoreCase(其他.Name);
}
公共覆盖布尔等于(对象对象对象)
{
回报相等(obj作为游戏);
}
}
视图模型
public class GamesViewModel
{
// The GameRepository retrieves the game collection from the XML file.
private readonly GameRepository _gameRepository;
public ObservableCollection<Game> Games
{
get { return new ObservableCollection<Game>(_gameRepository.Items); }
}
public Game SelectedGame
{
get { return Settings.Default.ActiveGame; }
set
{
if (!Settings.Default.ActiveGame.Equals(value))
{
Settings.Default.ActiveGame = value;
Settings.Default.Save();
}
}
}
public GamesViewModel()
{
_gameRepository = RepositorySingletons.GameRepository;
}
}
public class GamesViewModel
{
//GameRepository从XML文件检索游戏集合。
私有只读游戏存储库\u游戏存储库;
公开募捐小游戏
{
获取{returnnewobserveCollection(_gameRepository.Items);}
}
公共游戏选择名称
{
获取{return Settings.Default.ActiveGame;}
设置
{
如果(!Settings.Default.ActiveGame.Equals(value))
{
Settings.Default.ActiveGame=值;
Settings.Default.Save();
}
}
}
公共游戏可视模型()
{
_gameRepository=repositorySingleton.gameRepository;
}
}
查看
<UserControl x:Class="ENBOrganizer.UI.Views.GamesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ENBOrganizer.UI.ViewModels"
mc:Ignorable="d" >
<UserControl.DataContext>
<local:GamesViewModel />
</UserControl.DataContext>
<Grid>
<ComboBox Name="GamesComboBox" ItemsSource="{Binding Games}" SelectedItem="{Binding SelectedGame}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" Padding="5,0,0,0" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</UserControl>
当您的
组合框的SelectedItem
从视图中更改时,您会发现您的源属性(SelectedName
)可能会设置两次,一次设置值为null
(因为不再选择上一项),然后设置一次新选择的项
如果您有依赖于对象不为null的代码,通常处理这种情况的方法是使用简单的null值检查:
if (value != null)
{
// Code that relies on value not being null
}
在这一点上,我没有专门依赖于空检查的代码。我可能需要在未来,但为了早期开发的目的,我只有2个游戏的组合框,所以我的选择将永远不会为空。你知道为什么当我所做的只是在组合框中选择一个项目时会调用Equals方法吗?这是我的第一个猜测。我在SelectedName属性的setter上设置了一个断点,但是Equals方法在setter被命中之前抛出了一个异常。Object.Equals在.NET后台用于许多不同的事情,重写该方法时应该非常小心。看,你的Equals方法相当懒惰。你应该能够在不抛出NRE的情况下处理这个问题。我接受空检查。我只是想了解为什么要首先传入null。