MVVMをテストして(コードビハインドなしで)ビューを切り替えるために、かなり単純なWPFアプリケーションを構築しようとしています。起動時に、Def.xamlをロードしてボタンをクリックすると、ビューを切り替えることになっています。私が抱えている問題は、RelayCommandがボタンクリックイベントで発生していないようで、ビューは変更されていないということです。また、最初のビューを正しい方法で設定しているかどうかはわかりません。この点に関する助けがあれば、非常に感謝しています。次のように私のコードは次のとおりです。RelayCommandがコード内で実行されていません
AppViewModel.cs - これはMainWindow.xaml
namespace Test
{
class AppViewModel : ObservableObject
{
private ICommand ActivateView { get; set; }
private ICommand DeactivateView { get; set; }
public AppViewModel()
{
ActiveView = new DefViewModel();
ActivateView = new RelayCommand(UnsetDef);
DeactivateView = new RelayCommand(SetDef);
}
private void UnsetDef(object obj)
{
ActiveView = new AltViewModel();
MessageBox.Show("Done!");
}
private void SetDef(object obj)
{
ActiveView = new DefViewModel();
}
}
}
MainWindow.xaml
<Window x:Class="Test.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:Test"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:DefViewModel}">
<local:def/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:AltViewModel}">
<local:Alt/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:AppViewModel/>
</Window.DataContext>
<Grid>
<ContentControl Content="{Binding Path=ActiveView}"/>
</Grid>
</Window>
Def.xamlためのViewModelにある - これは、私のデフォルトビューです
<UserControl x:Class="Test.def"
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:Test"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Padding="15,15,15,15" Text="Default View Active"/>
<Button Padding="1,1,1,1" Content="Activate Alt View" Command="{Binding Path=ActivateView}"/>
</StackPanel>
</Grid>
</UserControl>
Alt.xaml - この私の代替図である
<UserControl x:Class="Test.Alt"
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:Test"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Padding="15,15,15,15" Text="Alt View Active"/>
<Button Padding="1,1,1,1" Content="Deactivate Alt View" Command="{Binding Path=DeactivateView}"/>
</StackPanel>
</Grid>
</UserControl>
ObservableObject.cs - これは私がINotifyPropertyChangedの
namespace Test
{
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string prop)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
private object activeView;
public object ActiveView
{
get { return activeView; }
set { activeView = value; OnPropertyChanged("ActiveView"); }
}
}
}
RelayCommand.cs
を実装するために作られた抽象クラスですnamespace Test
{
class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
public RelayCommand(Action<object> execute) : this(execute, null) { }
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute ?? throw new ArgumentNullException("execute"); _canExecute = canExecute;
}
//private Action<object> _action;
//public RelayCommand(Action<object> action)
//{
// _action = action;
//}
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
//if(parameter != null)
//{
// _action(parameter);
//}
//else
//{
// _action("Nyet!");
//}
}
#endregion
}
}
UPDATE:親のdatacontextが参照するためのバインディングを変更するbwingの提案。ありがとうございました!
私はすでに試してみましたが、まだ動作させることはできません。コマンドを読み取り専用にすることについてのヒントをありがとう! – pkoganti
デバッグ用のバインディングの問題スヌープをダウンロードすることをお勧めします。 https://snoopwpf.codeplex.com/バインディングエラーを見つけるのに役立ちます。また、Visual Studioの[出力]ウィンドウでバインディングの失敗を確認することもできます。 – bwing
それは働いた!具体的には、バインドを親データコンテキストを参照するように変更すると、そのトリックが実行されました。本当にありがとうございます! ActivateViewコマンドをDefViewModelに移動して、その動作を確認します。しかし、MVVMアーキテクチャに違反すると私は理解しています。あれは正しいですか? また、スヌープをおすすめしてくれてありがとうございます。私はより複雑なものを構築するので、私はそれを大いに活用するでしょう。 – pkoganti