Я работаю над приложением WPF (игрой Реверси) для школы.Я очень новичок в MVVM, так что извините за noobishness .
У меня есть StartScreen.xaml
, привязанный к StartViewModel
, который представляет экран в начале игры, и BoardScreen.xaml
привязан к BoardViewModel
, то есть к экрану с платой реверси.
Я использую ContentControl
в MainWindow.xaml
для отображения экранов.ViewModels реализует абстрактный класс Screen
, и я использую навигатор для переключения между ними.
В моем BoardScreen.xaml.cs
я пытаюсь привязать событие к BoardViewModel
.Событие называется GameEnded
и вызывается по окончании игры.Я хотел бы подписаться на событие из кода (BoardScreen.xaml.cs
), чтобы проигрывать звук по окончании игры.Примерно так:
GameEnded += BoardScreen_GameEnded
...
private void BoardScreen_GameEnded(object sender, EventArgs e)
{
PlaySound(WinSound);
}
Проблема в том, что я действительно не знаю, как добраться до этого события.Кажется, я не могу получить к нему доступ с помощью свойств DataContext
или Content
.
Кто-нибудь знает, как это сделать?Если мне нужно уточнить, пожалуйста, спросите.Спасибо!:)
MainWindow.xaml
<Window x:Class="View.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:View"
xmlns:vm="clr-namespace:ViewModel;assembly=ViewModel"
mc:Ignorable="d"
Title="Reversi"
SizeToContent="WidthAndHeight">
<ContentControl Content="{Binding CurrentScreen}" Margin="30" />
</Window>
App.xaml
<Application x:Class="View.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml"
xmlns:view="clr-namespace:View"
xmlns:vm="clr-namespace:ViewModel;assembly=ViewModel">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins\blue.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate DataType="{x:Type vm:StartViewModel}">
<view:StartScreen />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:BoardViewModel}">
<view:BoardScreen />
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
Navigation.cs
public abstract class Screen
{
protected readonly Navigator navigator;
protected Screen(Navigator navigator)
{
this.navigator = navigator;
}
protected void SwitchTo(Screen screen)
{
this.navigator.CurrentScreen = screen;
}
}
public class Navigator : INotifyPropertyChanged
{
private Screen currentScreen;
public Navigator()
{
this.currentScreen = new StartViewModel(this);
}
public Screen CurrentScreen
{
get
{
return currentScreen;
}
set
{
this.currentScreen = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentScreen)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class SimpleCommand : ICommand
{
private readonly Action action;
public SimpleCommand(Action action)
{
this.action = action;
}
public event EventHandler CanExecuteChanged
{
add { }
remove { }
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
action();
}
}
BoardScreen.xaml
public partial class BoardScreen : UserControl
{
public System.Windows.Media.MediaPlayer ClickSound { get; private set; }
public System.Windows.Media.MediaPlayer WinSound { get; private set; }
public BoardScreen()
{
// Initialize sounds
ClickSound = new MediaPlayer();
WinSound = new MediaPlayer();
ClickSound.Open(new Uri(@"..\..\Sounds\click.mp3", UriKind.Relative));
WinSound.Open(new Uri(@"..\..\Sounds\win.mp3", UriKind.Relative));
}
private void BoardScreen_GameEnded(object sender, EventArgs e)
{
PlaySound(WinSound);
}
private void PlaySound(MediaPlayer sound)
{
sound.Stop();
sound.Position = TimeSpan.Zero;
sound.Play();
}
internal void PlayClickSound(object sender, RoutedEventArgs e)
{
PlaySound(ClickSound);
}
internal void PlayWinSound(object sender, RoutedEventArgs e)
{
PlaySound(WinSound);
}
}
ОБНОВЛЕНИЕ
Как @Spongebrot упоминается в комментарияхЯ смог подписаться на событие, сделав это внутри события DataContextChanged.Проверка типов необходима, так как в противном случае я получу исключение NullPointerException.
DataContextChanged += (o, e) => {
if(DataContext is BoardViewModel)
{
var viewModel = DataContext;
(DataContext as BoardViewModel).GameEnded += BoardScreen_GameEnded;
}
};