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

WinUI3下MVVM模式中ObservableCollection绑定ListView的问题

问题解决:WinUI3 ListView绑定ObservableCollection的命令与属性冲突

核心问题原因

ListView的ItemTemplate默认数据上下文是集合中的单个User对象,而非页面的UserViewModel:

  • 若x:DataType设为vm:UserViewModel,会找不到User的Username/Id属性
  • 若x:DataType设为m:User,直接{x:Bind DeleteUserCommand}会失败,因为User模型里没有这个命令

解决方案

1. 修正ItemTemplate的x:DataType并绑定命令到页面ViewModel

将DataTemplate的x:DataType改为m:User,同时通过RelativeSource引用页面的UserViewModel来绑定命令:

修改后的ListView.ItemTemplate代码:

<ListView.ItemTemplate>
    <DataTemplate x:DataType="m:User">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.3*"></ColumnDefinition>
                <ColumnDefinition Width="0.3*"></ColumnDefinition>
                <ColumnDefinition Width="0.3*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{x:Bind Username}" Grid.Column="0"></TextBlock>
            <Button Grid.Column="2" 
                    Command="{x:Bind ViewModel.DeleteUserCommand, RelativeSource={RelativeSource AncestorType=Page}}" 
                    CommandParameter="{x:Bind Id}">X</Button>
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

2. 修复ViewModel中的上下文释放问题

原ViewModel的DeleteUser和AddUser方法中使用using (context)会提前释放数据库上下文,导致后续操作报错,需去掉using块,同时优化逻辑同步UI与数据库:

修改后的DeleteUser方法:

[RelayCommand]
public void DeleteUser(object o)
{
    Debug.WriteLine("Called Delete User");
    if (o != null && int.TryParse(o.ToString(), out int id))
    {
        try
        {
            var userToDelete = context.User.FirstOrDefault(u => u.Id == id);
            if (userToDelete != null)
            {
                context.User.Remove(userToDelete);
                context.SaveChanges();
                // 同步ObservableCollection
                var userInCollection = Users.FirstOrDefault(u => u.Id == id);
                if (userInCollection != null)
                {
                    Users.Remove(userInCollection);
                }
            }
        }
        catch (Exception ex)
        {
            if (!context.User.Any(i => i.Id == id))
            {                        
                return;
            }
            else
            {
                throw ex;
            }
        }
    }
}

修改后的AddUser方法:

[RelayCommand]
public void AddUser(object o)
{
    if (o is string username && !string.IsNullOrEmpty(username))
    {
        var user = new User()
        {                        
            Username = username,
        };                    
        context.User.Add(user);                                       
        context.SaveChanges();
        // 同步ObservableCollection
        Users.Add(user);
    }                                
}

3. 优化ObservableCollection同步逻辑

原OnCollectionChanged直接操作数据库可能导致重复操作(比如手动调用SaveChanges后又触发),建议改为仅在UI操作集合时同步数据库,数据库变更后通过UpdateUsers同步UI,避免逻辑冲突。

关键说明

  • {x:Bind ViewModel.DeleteUserCommand, RelativeSource={RelativeSource AncestorType=Page}}:通过RelativeSource找到页面级别的DataContext(即UserViewModel),从而访问ViewModel中的RelayCommand
  • 移除using (context):ViewModel生命周期内保持数据库上下文实例,避免提前释放导致的异常
  • 手动同步ObservableCollection与数据库:确保UI显示与数据库状态一致

内容的提问来源于stack exchange,提问作者Nuvolari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:06:10