【问题标题】:UI not updating with WPF MVVM?UI 不使用 WPF MVVM 更新?
【发布时间】:2014-11-23 14:57:05
【问题描述】:

我认为Datagrid 绑定到ObservableCollection<T>。该集合是从使用 Linq to EF 方法在 viewmodel 构造函数中调用的方法填充的。从我的 SQL Server 数据库中的视图中选择记录:

属性:

private ObservableCollection<vwAccountHeader> _accountHeaderCollection;
public ObservableCollection<vwAccountHeader> AccountHeaderCollection
{
    get { return _accountHeaderCollection; }
    set
    {
        _accountHeaderCollection = value;
        OnPropertyChanged("AccountHeaderCollection");
    }
}

方法:

private void GetAccountHeaders()
{
    var query = from a in _context.vwAccountHeaders
        select a;

    AccountHeaderCollection = new ObservableCollection<vwAccountHeader>(query);
}

所选项目:

private vwAccountHeader _selectedAccountHeader;
public vwAccountHeader SelectedAccountHeader
{
    get { return _selectedAccountHeader; }
    set
    {
        _selectedAccountHeader = value;
        OnPropertyChanged("SelectedAccountHeader");
    }
}

集合在初始化时按预期填充。然后,我可以让用户从 Datagrid 中选择一行并编辑该行:

所选项目的更改被持久化回一个 sql 表,而不是绑定到 DataGrid 的 sql 视图,但是该表是视图的父级,因此更改也会持久化到视图。例如这里是我的SaveEdits 命令:

private void SaveAccountEditsCommandAction()
{
    var query = from a in _context.tbAccounts
                where SelectedAccount.accountId == a.accountId
                select a;

    foreach (var a in query)
    {
        a.Div1AccNo = SelectedAccount.Div1AccNo;
        a.AccountName = SelectedAccount.AccountName;
        a.CompanyName = SelectedAccount.CompanyName;
        a.ContactEmail = SelectedAccount.ContactEmail;
        a.ContactName = SelectedAccount.ContactName;
        a.SubscriptionLevel = SelectedAccount.SubscriptionLevel;
        a.Responsible = SelectedAccount.Responsible;
        a.notes = SelectedAccount.notes;
        a.IsActive = SelectedAccount.IsActive;
    }

    _context.SaveChanges();
}   

这些更改保留在我的 SQL Server 中的VWAccountHeaders 视图中。我正在实现INotifyPropertyChnaged,并且 Xaml 绑定设置为在“PropertyChanged”上更新:

<DataGrid x:Name="AccountsHeaderDataGrid" Margin="10" ItemsSource="{Binding AccountHeaderCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" SelectedItem="{Binding SelectedAccountHeader, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            IsReadOnly="True" CanUserAddRows="False" SelectionMode="Single" VerticalScrollBarVisibility="Auto" Height="350">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Account No" Binding="{Binding Path=div1accno, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="SizeToHeader"/>
            <DataGridTextColumn  Header="Company Name" Binding="{Binding Path=companyname, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="SizeToHeader"/>
            <DataGridTextColumn  Header="Subscription Level" Binding="{Binding Path=subscriptionlevel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="SizeToHeader"/>
            <DataGridTextColumn  Header="Region List" Binding="{Binding Path=region_list, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="SizeToHeader"/>
            <DataGridCheckBoxColumn Header="Is Active" Binding="{Binding Path=IsActive, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="SizeToHeader"/>
        </DataGrid.Columns>
<DataGrid/>

尽管如此,如果不关闭应用程序并重新运行,我就无法让 UI 反映基础数据的变化。我可以看到DataGrid 在保存时闪烁,因此可以看到它正在重新绑定,但它只是没有获取基础视图中的更改。我是否需要以某种方式刷新我的数据上下文,还是我在这里遗漏了一些简单的东西?

【问题讨论】:

    标签: c# sql wpf xaml datagrid


    【解决方案1】:

    问题可能是因为集合没有改变,因此事件可能不会自动触发。所以在 SaveAccountEditsCommandAction 尝试提高 AccountHeaderCollection

    的属性更改

    【讨论】:

    • 不,您不应该在 Collection 上提出属性更改,因为 Collection 没有更改。这是内部项目绑定不起作用。
    • 正确,ObservableCollection 没有改变,实体对象没有绑定到改变。但是如何纠正呢?..
    • @Hardgraf SelectedAccount 是原始帐户的克隆还是引用集合中的同一对象?
    • 否,所选帐户是一个 vwAccountHeader 对象,而不是集合中的所选行。我正在更新 tbAccounts 表,并且更改将保留在 VWArticleHeaders 视图中,这是您在 UI 中看到的绑定到 DataGrid 的内容。我已经在 SaveChanges() 上检查了数据库,并且所有内容都按我的预期保存回数据库。在问题中包含 selectedItem 属性。干杯
    【解决方案2】:

    您的收藏只创建一次,以后不会神奇地刷新。 尝试在 SaveAccountEditsCommandAction() 结束时调用 GetAccountHeaders()。

    【讨论】:

    • 试过这个,收藏是一样的。看起来 vwAccountHeader EF 对象尚未从 db 中获取更改
    • 所以更改存储在 db 中,但除非您重新启动应用程序,否则 EF 不会选择它们?单击保存后,您是否尝试过从数据库中选择数据。他们已经在数据库中了吗?您也可以在 SaveAccountEditsCommandAction() 的末尾调用 GetAccountHeaders() 时设置断点。那么下载的数据是最新的吗?
    • 没错。 db 中的数据已在调用 GetAccountHeaders() 时保持不变,但 linq 查询不会从 _context.vwAccountHeaders... 中获取更改
    • 能否在创建新集合之前尝试调用 context.refresh?
    • VS2013 和 EF 6。不幸的是,这种方法不存在。我尝试在上下文中调用 Dispose() 并更新上下文但结果相同:(
    【解决方案3】:

    好的,伙计们。我终于解决了这个问题!

    这是我的 RefreshEntities() 方法,它调用 MergeOption.OverwriteChanges;,它基本上覆盖了上下文实体并使用数据库中的新数据重新加载集合。您是在告诉 EF 覆盖您传入的实体。无论我在何时对该视图进行持久更改,我都会调用此方法:

        private void RefreshEntities()
        {
            var objectContext = ((IObjectContextAdapter)_context).ObjectContext;
            var objectSet = objectContext.CreateObjectSet<vwAccountHeader>();
            objectSet.MergeOption = MergeOption.OverwriteChanges;
            AccountHeaderCollection = new ObservableCollection<vwAccountHeader>(objectSet);
        }
    

    看起来很冗长,但效果很好。对于任何 MVVM WPF 应用程序,我建议您尝试更新 UI 中的视图,该视图已因用户与 EF 框架模型中的关联表的交互而发生更改。本质上,表和视图之间存在交叉关系,您需要在 UI 中更新该视图。

    MergeOption.OverwriteChanges 会覆盖所有待处理的更改,但您可以使用 MergeOption.PreserveChanges 将重新加载的值合并到您编辑的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      • 2016-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多