MVVM模式中DataModel与ViewModel共存的正确实现方案
WinUI中基于不可修改DataModel实现DataGrid的MVVM协同方案
核心原则
遵循MVVM的核心分离逻辑:视图(DataGrid)负责展示,视图模型(ViewModel)作为中间层处理UI逻辑与数据交互,完全不修改原始DataModel,确保它能正常复用在其他项目中。
1. ViewModel中定义可绑定数据源
不要在ViewModel里直接定义DataGrid控件,而是用ObservableCollection<T>(T为你的DataModel类型)作为可绑定集合——WinUI的DataGrid天然支持绑定这个类型,集合变更会自动通知UI更新。
示例代码:
using System.Collections.ObjectModel; public class YourViewModel { // 绑定给DataGrid的ItemsSource public ObservableCollection<YourDataModel> DataItems { get; } = new ObservableCollection<YourDataModel>(); public YourViewModel() { // 替换为实际的数据加载逻辑(API、本地存储等) LoadInitialData(); } private void LoadInitialData() { DataItems.Add(new YourDataModel { Id = 1, Title = "示例数据1" }); DataItems.Add(new YourDataModel { Id = 2, Title = "示例数据2" }); } }
2. XAML视图绑定DataGrid
在页面XAML中设置DataContext为ViewModel,将DataGrid的ItemsSource绑定到ViewModel的集合,再通过列绑定直接映射DataModel的现有属性,无需修改DataModel。
示例XAML:
<Page x:Class="YourWinUIApp.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:YourWinUIApp"> <Page.DataContext> <local:YourViewModel /> </Page.DataContext> <Grid> <DataGrid ItemsSource="{x:Bind DataItems, Mode=OneWay}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="ID" Binding="{x:Bind Id, Mode=OneWay}" /> <DataGridTextColumn Header="标题" Binding="{x:Bind Title, Mode=OneWay}" /> <!-- 其他列直接对应DataModel的属性 --> </DataGrid.Columns> </DataGrid> </Grid> </Page>
3. 处理UI交互逻辑(命令/过滤/排序)
所有UI相关操作(删除、排序、过滤等)都在ViewModel中实现,操作DataItems集合即可,完全不触碰DataModel。比如实现删除命令:
using System.Windows.Input; public class YourViewModel { // ... 现有DataItems定义 ... public ICommand DeleteItemCommand { get; } public YourViewModel() { LoadInitialData(); DeleteItemCommand = new RelayCommand<YourDataModel>(DeleteSelectedItem); } private void DeleteSelectedItem(YourDataModel item) { if (item != null && DataItems.Contains(item)) { DataItems.Remove(item); } } } // 基础RelayCommand实现(无第三方框架时可用) public class RelayCommand<T> : ICommand { private readonly Action<T> _execute; private readonly Func<T, bool> _canExecute; public event EventHandler CanExecuteChanged; public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter); public void Execute(object parameter) => _execute((T)parameter); public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); }
对应XAML绑定命令:
<DataGridTemplateColumn Header="操作"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="删除" Command="{x:Bind DataContext.DeleteItemCommand, Mode=OneWay}" CommandParameter="{x:Bind}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
4. 处理DataModel属性变更通知(可选)
如果原始DataModel未实现INotifyPropertyChanged,但需要UI在属性变更时自动更新,不要修改DataModel,而是创建包装类(Wrapper),内部持有DataModel实例并实现属性变更通知:
using CommunityToolkit.Mvvm.ComponentModel; public class YourDataModelWrapper : ObservableObject { private readonly YourDataModel _innerModel; public YourDataModelWrapper(YourDataModel innerModel) { _innerModel = innerModel; } public int Id { get => _innerModel.Id; set { if (_innerModel.Id != value) { _innerModel.Id = value; OnPropertyChanged(); } } } public string Title { get => _innerModel.Title; set { if (!string.Equals(_innerModel.Title, value)) { _innerModel.Title = value; OnPropertyChanged(); } } } // 暴露原始模型供其他项目调用 public YourDataModel InnerModel => _innerModel; }
此时ViewModel的集合改为ObservableCollection<YourDataModelWrapper>,既保留了DataModel的复用性,又实现了UI实时更新。
内容的提问来源于stack exchange,提问作者miniHessel
相关产品推荐
相关产品推荐

