You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 23:17:43