WPF C#战舰游戏点击单元格触发INotifyPropertyChanged空引用异常
问题分析与解决方案
核心错误点1:ViewModelBase未处理PropertyChanged事件为空的情况
你的ViewModelBase类中,Set和Fire方法直接调用PropertyChanged事件,未判断事件是否为null,当没有订阅者时会直接抛出NullReferenceException。
修复代码:
internal class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected void Set<T>(ref T field, T value, [CallerMemberName] string propName = "") { if (!EqualityComparer<T>.Default.Equals(field, value)) { field = value; // 使用空条件运算符避免空引用 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } } protected void Fire(params string[] names) { foreach (var name in names) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } } }
注:改用EqualityComparer<T>.Default.Equals避免字段为null时调用Equals引发的额外空引用。
核心错误点2:MainWindow构造函数中DataContext实例不一致
你先将DataContext赋值给初始的bs,随后又重新实例化BattleshipVM覆盖bs,导致界面绑定的是旧实例,后续操作的却是新实例,引发逻辑混乱甚至绑定异常。
修复代码:
调整构造函数顺序,保证DataContext指向正确的实例:
public MainWindow() { InitializeComponent(); bs = new BattleshipVM(); DataContext = bs; }
或直接使用字段声明时初始化的实例:
public MainWindow() { InitializeComponent(); DataContext = bs; }
核心错误点3:CellModel中Miss和Shot共用同一字段
CellModel里Miss和Shot属性绑定到同一个visibility字段,设置其中一个属性时会触发另一个属性的绑定,导致状态完全混乱,也可能引发绑定层面的异常。
修复代码:
为两个属性分别设置独立字段:
public class CellModel : ViewModelBase { Visibility _missVisibility = Visibility.Collapsed; Visibility _shotVisibility = Visibility.Collapsed; bool _isShip; public CellModel(char state) { _isShip = state == 'X'; } public Visibility Miss { get => _missVisibility; private set => Set(ref _missVisibility, value); } public Visibility Shot { get => _shotVisibility; private set => Set(ref _shotVisibility, value); } public void SetState() { if (_isShip) Shot = Visibility.Visible; else Miss = Visibility.Visible; } }
额外优化:MapFabric方法的字符串分割逻辑
原始代码用空格分割地图字符串,会因每行前的空格导致分割结果异常,改为按换行符分割并清理空白:
CellModel[][] MapFabric(string str) { // 按换行分割,过滤空行并清理每行前后空格 var mp = str.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries) .Select(line => line.Trim()) .ToArray(); var map = new CellModel[10][]; for (int i = 0; i < 10; i++) { map[i] = new CellModel[10]; for (int j = 0; j < 10; j++) { map[i][j] = new CellModel(mp[i][j]); } } return map; }
内容的提问来源于stack exchange,提问作者Funshack
相关产品推荐
相关产品推荐

