WPF - 如何从子视图更改 ContentControl 视图?

问题描述 投票:0回答:1

我是 WPF/MVVM 新手,正在构建一个运行“作业”的应用程序。 该应用程序当前如下所示:

MainView
包含一些按钮和
ContentControl
ContentControl
显示一些子视图,如
JobsView
ApplicationSettingsView
,具体取决于所选的菜单项。

JobsView
包含代表作业的块。它显示了一些作业信息、作业功能和用于编辑/配置作业的编辑按钮 (Bewerk)。

当我单击“Bewerk”按钮时,特定于作业的编辑视图应显示在

ContentControl
MainView
中。我正在寻找处理此导航的最佳方法。重要的是,我在
JobEditViewModel
中有相关工作的实例。

我试过:

  1. 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()); });
        }
    }
}
  1. 使用事件和委托。 (https://www.tutorialsteacher.com/csharp/csharp-event)这也不起作用。由于某种原因,
    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 方法是什么?

wpf mvvm delegates
1个回答
1
投票

当我单击“Bewerk”按钮时,主视图的 ContentControl 中应显示特定于作业的编辑视图。我正在寻找处理此导航的最佳方法。

这个要求意味着 MainViewModel 负责导航,而不是 JobsViewModel。所以 EditJobCmd 命令应该位于 MainViewModel 中,而不是在 JobsViewModel 中(并且它消除了通过构造函数传递委托的必要性)

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.