WPF遵循DRY原则优化RelayCommand重复代码及实现NavigateToCommand的方法
优化实现方案
下面提供两种可落地的优化方式,都可以完全消除重复的RelayCommand定义逻辑。
方案1:使用带参数的通用导航命令(改动最小,无额外依赖)
第一步:修改MainViewModel代码
仅保留1个通用导航命令,通过命令参数区分要跳转的目标视图模型:
public class MainViewModel : BaseViewModel { // 仅需定义一个通用导航命令 public RelayCommand NavigateCommand { get; set; } private BaseViewModel _currentViewModel; public BaseViewModel CurrentViewModel { get => _currentViewModel; set { _currentViewModel = value; OnPropertyChanged(nameof(CurrentViewModel)); // 替换硬编码字符串,避免拼写错误 } } public MainViewModel() { CurrentViewModel = new HomeViewModel(); // 统一导航逻辑:根据传入参数创建对应ViewModel NavigateCommand = new RelayCommand(o => { CurrentViewModel = o switch { "Home" => new HomeViewModel(), "Custody" => new CustodyViewModel(), "Operations" => new OperationsViewModel(), _ => CurrentViewModel }; }); } }
第二步:修改XAML绑定,新增CommandParameter
每个按钮指定对应参数即可复用同一个命令:
<Button Content="Home" Command="{Binding NavigateCommand}" CommandParameter="Home"/> <Button Content="Custody" Command="{Binding NavigateCommand}" CommandParameter="Custody"/> <Button Content="Operations" Command="{Binding NavigateCommand}" CommandParameter="Operations"/>
该方案适合中小项目快速优化,完全消除了重复的Command定义和初始化逻辑。
方案2:进阶版本(结合类型参数+ViewModel工厂,扩展性更强)
如果后续视图模型数量较多,用字符串匹配容易出错,可以进一步优化为按类型导航,配合工厂模式完全符合开闭原则:
第一步:实现ViewModel工厂
public static class ViewModelFactory { public static BaseViewModel CreateViewModel(Type vmType) { return Activator.CreateInstance(vmType) as BaseViewModel; } // 如果使用依赖注入容器,可修改为从容器获取实例,避免每次新建对象: // public static BaseViewModel CreateViewModel(Type vmType) => App.ServiceProvider.GetService(vmType) as BaseViewModel; }
第二步:修改MainViewModel导航逻辑
public class MainViewModel : BaseViewModel { public RelayCommand NavigateCommand { get; set; } private BaseViewModel _currentViewModel; public BaseViewModel CurrentViewModel { get => _currentViewModel; set { _currentViewModel = value; OnPropertyChanged(nameof(CurrentViewModel)); } } public MainViewModel() { CurrentViewModel = ViewModelFactory.CreateViewModel(typeof(HomeViewModel)); NavigateCommand = new RelayCommand(o => { if (o is Type vmType && typeof(BaseViewModel).IsAssignableFrom(vmType)) { CurrentViewModel = ViewModelFactory.CreateViewModel(vmType); } }); } }
第三步:修改XAML,传类型作为参数
<!-- 先在XAML头部引入ViewModel所在的命名空间,示例如下 --> <Window xmlns:vm="clr-namespace:你的项目名.ViewModels"> <Button Content="Home" Command="{Binding NavigateCommand}" CommandParameter="{x:Type vm:HomeViewModel}"/> <Button Content="Custody" Command="{Binding NavigateCommand}" CommandParameter="{x:Type vm:CustodyViewModel}"/> <Button Content="Operations" Command="{Binding NavigateCommand}" CommandParameter="{x:Type vm:OperationsViewModel}"/> </Window>
该方案后续新增视图时只需新增对应按钮,无需修改ViewModel中的导航逻辑,维护成本更低。
内容的提问来源于stack exchange,提问作者WindCheck
相关产品推荐
相关产品推荐

