Итак, я пытаюсь использовать общие переменные в своем приложении WPF. При этом я реализовал класс ViewModelController для хранения переменных, которые влияют на остальную часть моего приложения, используя eventhandler.
Мой класс ViewModelController таков:
public class ViewModelController
{
private DataRowView _SelectedUniverse;
public MenuViewModel MenuViewModel { get { return new MenuViewModel(this); } }
public GamePageViewModel GamePageViewModel { get { return new GamePageViewModel(this); } }
public PlayersViewModel PlayersViewModel { get { return new PlayersViewModel(this); } }
public event EventHandler UniverseChanged;
public DataRowView SelectedUniverse
{
get { return _SelectedUniverse; }
set
{
_SelectedUniverse = value;
UniverseChanged.Invoke(this, EventArgs.Empty);
Debug.Print("Universe Changed in ViewModelController");
}
}
}
Я тестирую это в своей модели меню ViewModel, чтобы узнать, переходит ли он в другой класс:
MenuViewModel
public class MenuViewModel : ObservableObject
{
ViewModelController _ViewModelController;
private DataView _Universes;
private DataRowView _SelectedUniverse;
public MenuViewModel(ViewModelController controller)
{
_ViewModelController = controller;
_Universes = Controller.UniverseTableAdapter.GetData().DefaultView;
}
public DataView Universes
{
get { return _Universes; }
set
{
_Universes = value;
RaisePropertyChangedEvent("Universes");
}
}
public DataRowView SelectedUniverse
{
get { return _SelectedUniverse; }
set
{
_SelectedUniverse = value;
Debug.Print("Universe Changed from Menu");
_ViewModelController.SelectedUniverse = _SelectedUniverse;
RaisePropertyChangedEvent("SelectedUniverse");
}
}
}
PlayerViewModel Класс
public class PlayersViewModel : ObservableObject
{
private ViewModelController _ViewModelController;
#region Variables
private ObservableCollection<Player> _Players = Controller.GetPlayers(0);
private Player _SelectedPlayer;
private DataView _Colleges = Controller.CollegeTableAdapter.GetData().DefaultView;
private DataView _Universes = Controller.UniverseTableAdapter.GetData().DefaultView;
private long _PlayerID;
private string _PlayerFirstName;
private string _PlayerLastName;
private string _PlayerFullName;
private DataRowView _SelectedCollege;
private DataRowView _SelectedUniverse;
private long _PlayerCollegeID;
private long _UniverseID;
private int _PlayerEnteredYear;
private DataView _RegularSeasonStats = Controller.SeasonView.GetData().DefaultView;
private DataRowView _SelectedSeason;
private DataView _PlayoffStats = Controller.PlayoffsView.GetData().DefaultView;
private DataView _PlayerSchedule = Controller.PlayerScheduleView.GetDataByPersonAndYear(0, 0).DefaultView;
#endregion
public PlayersViewModel(ViewModelController controller)
{
_ViewModelController = controller;
_ViewModelController.UniverseChanged += OnUniverseChanged;
Debug.Print("PlayerViewModel Constructed");
}
public DataRowView SelectedUniverse
{
get { return _SelectedUniverse; }
set
{
_SelectedUniverse = value;
if (_SelectedUniverse != null)
{
_UniverseID = _SelectedUniverse.Row.Field<long>("UniverseID");
RaisePropertyChangedEvent("SelectedUniverse");
}
}
}
private void OnUniverseChanged(object sender, EventArgs e)
{
SelectedUniverse = _ViewModelController.SelectedUniverse;
Debug.Print("Universe was changed");
}
}
Когда SelectedUniverse изменяется, он отправляет эту переменную в ViewModelController, который должен вызвать событие UniverseChanged. Однако я получаю Object Reference Not Set to an Instance of an Object.
Я знаю, что должен создать экземпляр EventHandler, но я не вижу способа создать его без конструктора. Могу я все сделать неправильно?





Проблема здесь в том, что вы принудительно вызываете событие UniverseChanged, но нет слушателя для его обработки, поэтому событие на самом деле может быть нулевым.
Перед вызовом вы должны проверить, есть ли слушатели. Как это:
public DataRowView SelectedUniverse
{
get { return _SelectedUniverse; }
set
{
_SelectedUniverse = value;
UniverseChanged?.Invoke(this, EventArgs.Empty);
// Or if you're using a C# version< 6:
// var evtHandlers = UniverseChanged;
// if (evtHandlers != null) evtHandlers.Invoke(this, EventArgs.Empty);
Debug.Print("Universe Changed in ViewModelController");
}
}
Я надеюсь, что это помогает.
@BradleyUffner Вы правы. Спасибо, что заметили это.
Пример здесь: codeblog.jonskeet.uk/2015/01/30/…
Так что это действительно помогает, хотя не запускает метод OnUniverseChanged в моем PlayersViewModel .... Я добавил к нему слушателя, не так ли?
@ jDave1984 Я говорю об упомянутой вами ошибке Object Reference Not Set to an Instance of an Object. Класс PlayersViewModel (единственный, кто подписывается на указанное событие) никогда не вызывается (нет вызова get) в вашем коде (по крайней мере, в этом примере).
И я не вижу причин, по которым вы должны возвращать новый экземпляр этих объектов на каждом get.
Да, я сейчас занимаюсь рефакторингом. Однако get находится в моей привязке XAML, однако ... по-видимому, нет. Мне может понадобиться лучший и более эффективный способ переключения моделей просмотра и иметь некоторые общие переменные между ними.
@ jDave1984 Итак, чем я могу вам помочь? Мой пост ответил на ваш вопрос?
Он ответил на мой первоначальный вопрос об ошибке Null, поэтому я доверяю вам ответ. Если вы можете помочь мне в чате или по электронной почте улучшить структуру, я был бы очень признателен
@ jDave1984 Давай поговорим в чате, тогда.
Ваш код C# <6 должен сначала сохранить делегат в переменной, а затем работать с этой переменной вместо фактического делегата, чтобы избежать некоторых редких условий гонки.