C# MVVM模式:命令绑定和ViewModel执行之间的中间视图
场景 一些数据被加载到一个程序中(例如,在一个班级中,每个学生都是一个具有他/她的评估数据的独立实体,对学生的评估),并在数据网格上显示这些数据的摘要。用户选择一些学生,并对他们的评估进行分析。分析过程需要一些参数,因此在分析之前会弹出一个窗口,让用户指定自己喜欢的参数;然后执行分析过程 实施总结 datagrid定义如下,并绑定到ViewModel:C# MVVM模式:命令绑定和ViewModel执行之间的中间视图,c#,wpf,user-interface,mvvm,datagrid,C#,Wpf,User Interface,Mvvm,Datagrid,场景 一些数据被加载到一个程序中(例如,在一个班级中,每个学生都是一个具有他/她的评估数据的独立实体,对学生的评估),并在数据网格上显示这些数据的摘要。用户选择一些学生,并对他们的评估进行分析。分析过程需要一些参数,因此在分析之前会弹出一个窗口,让用户指定自己喜欢的参数;然后执行分析过程 实施总结 datagrid定义如下,并绑定到ViewModel: <DataGrid x:Name="CachedSamplesDG" ItemsSource="{Binding cachedDataSu
<DataGrid x:Name="CachedSamplesDG" ItemsSource="{Binding cachedDataSummary}">
<DataGrid.Columns>
<DataGridTextColumn Header="name" Binding="{Binding name}"/>
<DataGridTextColumn Header="score" Binding="{Binding score}"/>
</DataGrid.Columns>
</DataGrid>
a这是我当前流程的示意图,以及我下一步要做的事情
问题
单击按钮时
SamplesAnalyzeCommand
实现此要求的最佳方法是什么?只需使用dialogservice,如 然后可以在ViewModel中执行类似操作
var result = this.uiDialogService.ShowDialog("Prozess Options Window", prozessOptionVM);
...
var parameter1 = prozessOptionVM.Parameter1;
您可以为流程选项定义另一个模型和ViewModel,然后在SamplesAnalyze命令中显示流程选项视图。当用户完成ProcessOptionView时,主ViewModel会收到通知(例如通过事件处理程序)并完成该过程 大概是这样的:
internal class SamplesAnalyzeCommand : ICommand {
...
public void Execute(object parameter)
{
this._viewModel.ShowProcessOptions(parameter);
}
}
internal class CachedDataSummaryViewModel {
public string Status {
get {
return this.status;
}
set {
if (!string.Equals(this.status, value)) {
this.status = value;
// Notify property change to UI
}
}
}
...
internal void ShowProcessOptions(object paramter) {
// Model
var processOptions = new ProcessOptionsModel() {
otherInfo = parameter
};
// View-Model
var processOptionsViewModel = new ProcessOptionsViewModel();
processOptionsViewModel.Model = processOptions;
// View
var processOptionsView = new ProcessOptionsView(
processOptionsViewModel
);
// Edit2: Update status
this.Status = "Selecting process options...";
// You can use the event handler or dialog result
processOptionsViewModel.OK += this.PerformProcess;
processOptionsView.ShowDialog();
}
private void PerformProcess(object sender, EventArgs e) {
var processOptionsView = sender as ProcessOptionsView;
var processOptionsModel = processOptionsView.Model;
var processOptions = processOptionsModel.Model;
// Edit2: Update status
this.Status = "Performing process...";
// use processOptions.OtherInfo for initial info
// use processOptions.* for process options info
// and perform the process here
// Edit2: Update status
this.Status = "Process Done.";
}
...
}
class ProcessOptionsModel {
public object OtherInfo {
get;
set;
public int Parameter1 {
get;
set;
}
public IList<ProcessItem> SelectedItems {
get;
set;
}
...
}
class ProcessOptionsViewModel {
public event EventHandler OK;
private SamplesAnalyzeCommand model;
private ICommand okCommand;
public ProcessOptionsViewModel() {
this.okCommand = new OKCommand(this.OnOK);
}
public SamplesAnalyzeCommand Model {
get {
return model;
}
set {
this.model = value;
// Property changed stuff here
}
}
private void OnOK(object parameter) {
if (this.OK != null) {
this.OK = value;
}
}
}
class ProcessOptionsView {
// Interacts with it's view-model and performs OK command if
// user pressed OK or something
}
}
请注意,在本例中,我删除了OK事件,因为GetProcessOptions应该一直阻止,直到用户关闭主窗口。如果您希望在FromFile案例中采用响应性方法,那么可能需要处理异步的内容,可以定义getProcessOptionAsync
在这种情况下,事情可能会变得有点复杂,但我想通过这种方式是可以实现的。这是一种好的、实用的方法,但仍然不能完全解决我的问题。我想做的第一件事是在父UI上更改UI。我还想将
选项窗口从CachedDataSummaryViewModel
中排除。我希望,CachedDataSummaryViewModel
只包含用户定义的参数,而不管它们来自何处。这使得it独立于获取此类参数的逻辑发生的任何更改(例如,我可以将其更改为从持久化存储器读取),我更新了答案。我希望我明白你的意思。
internal class SamplesAnalyzeCommand : ICommand
{
public SamplesAnalyzeCommand(CachedDataSummaryViewModel viewModel)
{
_viewModel = viewModel;
}
private CachedDataSummaryViewModel _viewModel;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
// canExecute logic
}
public void Execute(object parameter)
{
// process mess ...
// Here I need the selected rows of datagird, which "parameter" delegates them.
// I also need some other parameters for analysis which user can set through another view
}
}
var result = this.uiDialogService.ShowDialog("Prozess Options Window", prozessOptionVM);
...
var parameter1 = prozessOptionVM.Parameter1;
internal class SamplesAnalyzeCommand : ICommand {
...
public void Execute(object parameter)
{
this._viewModel.ShowProcessOptions(parameter);
}
}
internal class CachedDataSummaryViewModel {
public string Status {
get {
return this.status;
}
set {
if (!string.Equals(this.status, value)) {
this.status = value;
// Notify property change to UI
}
}
}
...
internal void ShowProcessOptions(object paramter) {
// Model
var processOptions = new ProcessOptionsModel() {
otherInfo = parameter
};
// View-Model
var processOptionsViewModel = new ProcessOptionsViewModel();
processOptionsViewModel.Model = processOptions;
// View
var processOptionsView = new ProcessOptionsView(
processOptionsViewModel
);
// Edit2: Update status
this.Status = "Selecting process options...";
// You can use the event handler or dialog result
processOptionsViewModel.OK += this.PerformProcess;
processOptionsView.ShowDialog();
}
private void PerformProcess(object sender, EventArgs e) {
var processOptionsView = sender as ProcessOptionsView;
var processOptionsModel = processOptionsView.Model;
var processOptions = processOptionsModel.Model;
// Edit2: Update status
this.Status = "Performing process...";
// use processOptions.OtherInfo for initial info
// use processOptions.* for process options info
// and perform the process here
// Edit2: Update status
this.Status = "Process Done.";
}
...
}
class ProcessOptionsModel {
public object OtherInfo {
get;
set;
public int Parameter1 {
get;
set;
}
public IList<ProcessItem> SelectedItems {
get;
set;
}
...
}
class ProcessOptionsViewModel {
public event EventHandler OK;
private SamplesAnalyzeCommand model;
private ICommand okCommand;
public ProcessOptionsViewModel() {
this.okCommand = new OKCommand(this.OnOK);
}
public SamplesAnalyzeCommand Model {
get {
return model;
}
set {
this.model = value;
// Property changed stuff here
}
}
private void OnOK(object parameter) {
if (this.OK != null) {
this.OK = value;
}
}
}
class ProcessOptionsView {
// Interacts with it's view-model and performs OK command if
// user pressed OK or something
}
interface IOptionsProvider {
ProcessOptionsModel GetProcessOptions();
}
class ProcessOptionsView : IOptionsProvider {
public ProcessOptionsModel GetProcessOptions() {
if (this.ShowDialog()) {
return this.ModelView.Model;
}
return null;
}
}
class ProcessOptionsFromFile : IOptionsProvider {
public ProcessOptionsModel GetProcessOptions() {
// Create an instance of ProcessOptionsModel from File
}