我是 WPF/MVVM 新手,正在构建一个运行“作业”的应用程序。 该应用程序当前如下所示:
MainView
包含一些按钮和 ContentControl
。 ContentControl
显示一些子视图,如 JobsView
或 ApplicationSettingsView
,具体取决于所选的菜单项。
JobsView
包含代表作业的块。它显示了一些作业信息、作业功能和用于编辑/配置作业的编辑按钮 (Bewerk)。
当我单击“Bewerk”按钮时,特定于作业的编辑视图应显示在
ContentControl
的 MainView
中。我正在寻找处理此导航的最佳方法。重要的是,我在 JobEditViewModel
中有相关工作的实例。
我试过:
JobsViewModel
中创建函数时,将函数传递给 MainViewModel
(https://linuxhint.com/passing-function-as-parameter-c-sharp/)。这不起作用,因为
JobsViewModel
被以某种方式调用了两次(在调试过程中注意到)。一次来自 MainViewModel
,一次来自 ???。第二次,它调用不带参数的构造函数,因此我无法调用传递的函数。经过一些研究,我还了解到将参数传递给 ViewModel
构造函数是不好的做法。...
namespace ECRO.MVVM.ViewModel
{
internal class MainViewModel : ObservableObject
{
private object _currentView;
private Engine engine;
public JobsViewModel JobsVm { get; set; }
public SettingsViewModel SettingsVm { get; set; }
public RelayCommand JobViewCommand { get; set; }
public RelayCommand SettingsViewCommand { get; set; }
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
Task.Run(() =>
{
engine = Engine.Instance;
});
JobsVm = new JobsViewModel((viewModel) => { this._currentView = viewModel; });
SettingsVm = new SettingsViewModel();
_currentView = JobsVm;
// Initialize relay commands
JobViewCommand = new RelayCommand(o => { CurrentView = JobsVm; });
SettingsViewCommand = new RelayCommand(o => { CurrentView = SettingsVm; });
}
}
}
...
namespace ECRO.MVVM.ViewModel
{
class JobsViewModel
{
private ObservableCollection<RJob> _jobs;
public ObservableCollection<RJob> Jobs { get => _jobs; set { _jobs = value; } }
public RelayCommand ForceRunJobOnceCmd { get; set; }
public RelayCommand StartJobCmd { get; set; }
public RelayCommand StopJobCmd { get; set; }
public RelayCommand EnableJobCmd { get; set; }
public RelayCommand DisableJobCmd { get; set; }
public RelayCommand EditJobCmd { get; set; }
public string btnEnableDisableContent { get => "test"; }
public JobsViewModel() {
}
public JobsViewModel(Action<BaseViewModel> changeContentView)
{
_jobs = Engine.Instance.RJobs;
ForceRunJobOnceCmd = new RelayCommand(o => { ((RJob)o).ForceRunOnce(); });
StartJobCmd = new RelayCommand(o => { ((RJob)o).Start(); });
StopJobCmd = new RelayCommand(o => { ((RJob)o).Stop(); });
EnableJobCmd = new RelayCommand(o => { ((RJob)o).Enable(); });
DisableJobCmd = new RelayCommand(o => { ((RJob)o).Disable(); });
EditJobCmd = new RelayCommand(o => { changeContentView(new VerzamelqueryViewModel()); });
}
}
}
MainView
中的事件处理程序未被调用/触发。采用这个解决方案也感觉不太好,因为我不知道当子视图不是从MainView
而是从另一个子视图创建/启动时如何注册事件处理程序。 (例如,EditJobView
将获得一个子子视图来显示相关Job
的日志,并包含一个后退按钮以返回到EditJobView
)它也感觉不是真正通用/可重用的。 (需要为每个处理导航的子视图实现一个新的事件和事件处理程序)...
namespace ECRO.MVVM.ViewModel
{
internal class MainViewModel : ObservableObject
{
private object _currentView;
private Engine engine;
public JobsViewModel JobsVm { get; set; }
public SettingsViewModel SettingsVm { get; set; }
public RelayCommand JobViewCommand { get; set; }
public RelayCommand SettingsViewCommand { get; set; }
public object CurrentView
{
get { return _currentView; }
set
{
_currentView = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
Task.Run(() =>
{
engine = Engine.Instance;
});
//JobsVm = new JobsViewModel((viewModel) => { });
JobsVm = new JobsViewModel();
JobsVm.ChangeView += (object sender, BaseViewModel newView) => { _currentView = newView; };
SettingsVm = new SettingsViewModel();
_currentView = JobsVm;
// Initialize relay commands
JobViewCommand = new RelayCommand(o => { CurrentView = JobsVm; });
SettingsViewCommand = new RelayCommand(o => { CurrentView = SettingsVm; });
}
}
}
...
namespace ECRO.MVVM.ViewModel
{
class JobsViewModel
{
private ObservableCollection<RJob> _jobs;
public ObservableCollection<RJob> Jobs { get => _jobs; set { _jobs = value; } }
public RelayCommand ForceRunJobOnceCmd { get; set; }
public RelayCommand StartJobCmd { get; set; }
public RelayCommand StopJobCmd { get; set; }
public RelayCommand EnableJobCmd { get; set; }
public RelayCommand DisableJobCmd { get; set; }
public RelayCommand EditJobCmd { get; set; }
public string btnEnableDisableContent { get => "test"; }
public event EventHandler<BaseViewModel> ChangeView;
public JobsViewModel()
{
_jobs = Engine.Instance.RJobs;
ForceRunJobOnceCmd = new RelayCommand(o => { ((RJob)o).ForceRunOnce(); });
StartJobCmd = new RelayCommand(o => { ((RJob)o).Start(); });
StopJobCmd = new RelayCommand(o => { ((RJob)o).Stop(); });
EnableJobCmd = new RelayCommand(o => { ((RJob)o).Enable(); });
DisableJobCmd = new RelayCommand(o => { ((RJob)o).Disable(); });
EditJobCmd = new RelayCommand(o => { ChangeView?.Invoke(this, new VerzamelqueryViewModel()); });
}
}
}
处理我的案例的最佳实践/WPF-MVVM 方法是什么?
当我单击“Bewerk”按钮时,主视图的 ContentControl 中应显示特定于作业的编辑视图。我正在寻找处理此导航的最佳方法。
这个要求意味着 MainViewModel 负责导航,而不是 JobsViewModel。所以 EditJobCmd 命令应该位于 MainViewModel 中,而不是在 JobsViewModel 中(并且它消除了通过构造函数传递委托的必要性)