MVVM模式:Command绑定和ViewModel之间的中间视图执行

时间:2015-04-29 10:30:05

标签: c# wpf user-interface mvvm datagrid

方案 将某个日期加载到程序中(例如,对每个学生是具有他/她的评估数据的不同实体的类中的学生进行评估),并且在数据网格上显示它们的摘要。用户选择选择一些学生,并对他们的评估进行分析。分析过程需要一些参数,因此在分析之前弹出一个窗口并让用户指定他的首选参数;然后执行分析过程。

实施摘要 数据网格被定义为跟随并绑定到ViewModel:

<DataGrid x:Name="CachedSamplesDG" ItemsSource="{Binding cachedDataSummary}">                    
   <DataGrid.Columns>
      <DataGridTextColumn Header="name" Binding="{Binding name}"/>
      <DataGridTextColumn Header="score" Binding="{Binding score}"/>
   </DataGrid.Columns>
</DataGrid>

启动流程的按钮定义如下:

<Button x:Name="AnalysisBT" Content="Analyze" Command="{Binding AnalyzeCommand}" CommandParameter="{Binding ElementName=CachedSamplesDG, Path=SelectedItems}"/>

ViewModel非常基础,总结如下:

internal class CachedDataSummaryViewModel
    {
        public CachedDataSummaryViewModel()
        {
            _cachedDataSummary = new ObservableCollection<CachedDataSummary>();
            AnalyzeCommand = new SamplesAnalyzeCommand(this);
        }


        private ObservableCollection<CachedDataSummary> _cachedDataSummary;
        public ObservableCollection<CachedDataSummary> cachedDataSummary { get { return _cachedDataSummary; } }


        public ICommand AnalyzeCommand { get; private set; }
    }

以下是分析命令的定义:

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
        }
    }

这是我当前流程的图表以及我下一步要做的事情

the diagram

问题 单击按钮时

  1. MainWindow
  2. 上应用一些UI更改
  3. 弹出 ProcessOptionsWindow
  4. ProcessOptionsWindow
  5. 获取设置参数
  6. 将选定的数据网格行和用户指定的参数传递给SamplesAnalyzeCommand
  7. 达到此要求的最佳方式是什么?

2 个答案:

答案 0 :(得分:1)

只需使用Good or bad practice for Dialogs in wpf with MVVM?等对话服务。

然后您可以在ViewModel中执行类似的操作

var marker = new google.maps.Marker({
    position: new google.maps.LatLng(-25.363882,131.044922),
    map: map,
    title: 'Our Office'
});

答案 1 :(得分:0)

您可以为Process Options定义另一个Model和ViewModel,然后在SamplesAnalyzeCommand中显示ProcessOptionsView。当用户完成ProcessOptionsView时,主ViewModel会得到通知(例如通过事件处理程序)并完成Process。

这样的事情:

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
}

希望它有所帮助。

修改(1):

正如blindmeis建议的那样,您可以使用一些Dialog Service来建立视图之间的连接。

修改(2):

按钮单击后的Immidiate UI更改可以在ShowProcessOptions的ShowProcessOptions方法中完成。我不认为你想要在用户使用它时将选项窗口的ui更改反映到主窗口。用户关闭选项窗口后的UI更改可以在PerformProcess中完成。

如果你想为选项选择做一个抽象(例如从文件中读取),你可以定义一个IOptionsProvider接口,并将ProcessOptionsView和View-Model放在后面,但你仍然使用它模型。

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
    }

}

请注意,在这种情况下,我删除了OK事件,因为GetProcessOptions应该阻塞,直到用户关闭主窗口。如果您想在FromFile案例中采用响应式方法,则可能需要处理异步内容,可能需要定义GetProcessOptionsAsync。

在这种情况下,事情可能会有点复杂,但我想这是可以实现的。