基于MVVM模式实现选中对象在新UserControl的详情展示
基于MVVM实现单选按钮触发人员详情UserControl的方案
实现思路
- 新增人员详情UserControl,布局所有字段的展示控件;
- 在ViewModel层添加命令处理单选按钮点击逻辑,同时维护属性控制详情控件的显示状态;
- 将单选按钮的选中项绑定到ViewModel的
SelectedPersonItem,点击事件绑定到新增命令; - 在主界面通过ContentControl加载详情UserControl,并将其DataContext绑定到选中的人员对象。
步骤1:新增人员详情UserControl(PersonDetailUC.xaml)
<UserControl x:Class="PersonMVVM.PersonDetailUC" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="300"> <StackPanel Margin="10" Spacing="8"> <TextBlock Text="人员详情" FontSize="16" FontWeight="Bold"/> <StackPanel Orientation="Horizontal"> <TextBlock Text="ID:" Width="60"/> <TextBlock Text="{Binding PersonID}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="姓名:" Width="60"/> <TextBlock Text="{Binding Name}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="姓氏:" Width="60"/> <TextBlock Text="{Binding Surname}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="年龄:" Width="60"/> <TextBlock Text="{Binding PersonAge}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="地址:" Width="60"/> <TextBlock Text="{Binding PersonAddress}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="部门:" Width="60"/> <TextBlock Text="{Binding PersonDepartmentID}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="组别:" Width="60"/> <TextBlock Text="{Binding PersonGroupID}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="联系方式:" Width="60"/> <TextBlock Text="{Binding PersonContact}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="学历:" Width="60"/> <TextBlock Text="{Binding PersonLevelEductationID}"/> </StackPanel> <StackPanel Orientation="Horizontal"> <TextBlock Text="分部:" Width="60"/> <TextBlock Text="{Binding PersonDivisionID}"/> </StackPanel> </StackPanel> </UserControl>
步骤2:完善ViewModelBase,添加命令基类
在ViewModelBase所在文件中添加通用RelayCommand实现:
namespace PersonMVVM { class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public void OnpropertyChanged([CallerMemberName] string propName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } } // 通用命令实现类 public class RelayCommand : ICommand { private readonly Action<object> _execute; private readonly Func<object, bool> _canExecute; public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } } }
步骤3:修改PersonViewModel,添加命令和显示控制属性
namespace PersonMVVM { class PersonViewModel : ViewModelBase { public ObservableCollection<PersonModel> PersonItems { get; } private PersonModel _selectedPersonItem; public PersonModel SelectedPersonItem { get => _selectedPersonItem; set { _selectedPersonItem = value; OnpropertyChanged(nameof(SelectedPersonItem)); } } // 控制详情控件显示状态的属性 private bool _isDetailVisible; public bool IsDetailVisible { get => _isDetailVisible; set { _isDetailVisible = value; OnpropertyChanged(nameof(IsDetailVisible)); } } // 单选按钮点击命令 public ICommand ShowDetailCommand { get; } private readonly DataRepository dataRepository; public PersonViewModel() { this.PersonItems = new ObservableCollection<PersonModel>(); this.dataRepository = new DataRepository(); ShowDetailCommand = new RelayCommand(ExecuteShowDetail); } private void ExecuteShowDetail(object parameter) { if (SelectedPersonItem != null) { IsDetailVisible = true; } } public void Initialize() { IEnumerable<PersonModel> personModels = this.dataRepository.GetPersonModels(); foreach (PersonModel personModel in personModels) { this.PersonItems.Add(personModel); } } } }
步骤4:修改主窗口,实现单选按钮列表与详情展示
修改MainWindow.xaml,替换原ListBox为单选按钮列表,并添加详情控件容器:
<Window x:Class="PersonMVVM.MainWindow" xmlns:local="clr-namespace:PersonMVVM" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Window.DataContext> <local:MainViewModel/> </Window.DataContext> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="200"/> <ColumnDefinition/> </Grid.ColumnDefinitions> <!-- 单选按钮列表 --> <ItemsControl Grid.Column="0" ItemsSource="{Binding PersonViewModel.PersonItems}" Margin="10"> <ItemsControl.ItemTemplate> <DataTemplate DataType="{x:Type local:PersonModel}"> <RadioButton Content="{Binding Name}" IsChecked="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.SelectedPersonItem, Converter={local:ObjectEqualsConverter}, ConverterParameter={Binding}}" Command="{Binding RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.ShowDetailCommand}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> <!-- 详情控件容器 --> <ContentControl Grid.Column="1" Margin="10" Visibility="{Binding PersonViewModel.IsDetailVisible, Converter={x:Static BooleanToVisibilityConverter.Instance}}"> <local:PersonDetailUC DataContext="{Binding PersonViewModel.SelectedPersonItem}"/> </ContentControl> </Grid> </Window>
步骤5:添加对象相等转换器(ObjectEqualsConverter)
用于绑定单选按钮选中状态与ViewModel的选中项:
namespace PersonMVVM { public class ObjectEqualsConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return Equals(value, parameter); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { return (bool)value ? parameter : Binding.DoNothing; } } }
原代码保留说明
- Model、DataRepository、MainViewModel代码无需修改;
- 原MasterDetailsControl可根据需求保留或移除,本次实现直接在主窗口构建单选列表与详情展示。
内容的提问来源于stack exchange,提问作者mark
相关产品推荐
相关产品推荐

