2015-09-09 19 views
1

我正在开发一个简单的WPF应用程序。目前,该应用程序仅管理ComboBox中的视频游戏列表。游戏列表将序列化到XML文件或从XML文件中进行序列化。为什么DependencyProperty.UnsetValue被传入Equals()

当前破坏的功能是从ComboBox中选择一个游戏,使其成为“活动”游戏进行管理的功能。活动游戏将作为应用程序设置存储。为了达到这个目的,我使用双向数据绑定并将ComboBox中的SelectedItem绑定到ViewModel中的SelectedGame。

当我运行应用程序并从ComboBox中选择一个项目时,我在Game.Equals(Game other)方法上得到一个空引用异常。在调试时,我看到DependencyProperty.UnsetValue被作为参数传递给被覆盖的Game.Equals(object obj)方法,该方法导致obj as Game使obj为空。

我不明白为什么当Equals被首先调用时,我正在从ComboBox值中选择一个项目,所以我猜这是WPF原生的东西。该代码似乎没有击中任何其他断点前,等于方法,所以我甚至不知道如何调试问题。我也不明白DependencyProperty.UnsetValue来自哪里。我只是完全迷失在这里,并希望得到任何见解,包括如何进一步调试。

编辑:正如Glen所提到的,Equals必须由WPF的某个基础组件调用。至少现在,我的解决方案是简单地在我的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); 
    } 
} 

视图模型

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

查看

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

你的Equals方法是非常懒惰。你应该能够处理这个,而不会抛出NRE。 – Will

+0

我很满意一个空检查。我只想了解为什么null首先被传入。 – SeeSharpCode

回答

1

SelectedItem从您的ComboBox视图中更改,您会发现您的源媒体资源(SelectedGame)可能会设置两次,一次使用值null(因为不再选择上一个项目),然后一次用于新选择的项目。

如果您有依赖于不被空的对象代码,这通常处理的方法是使用一个简单的空值检查:

if (value != null) 
{ 
    // Code that relies on value not being null 
} 
+0

在这一点上,我真的没有专门依赖空检查的代码。我将来可能需要这样做,但对于早期的开发目的,我只有2个游戏在ComboBox中,所以我的选择永远不会为空。 可能你知道为什么Equals方法被调用时,我所做的只是在ComboBox中选择一个项目? – SeeSharpCode

+0

您的SelectedGame属性的setter具有ActiveGame.Equals(value)....... –

+0

这是我第一次猜测。我在SelectedGame属性的setter上设置了一个断点,但Equals方法在setter被击中之前抛出异常。 – SeeSharpCode

相关问题