无法使用 PRISM 5、MVVM 和 EF 6 在 WPF 中刷新 DataGrid

Posted

技术标签:

【中文标题】无法使用 PRISM 5、MVVM 和 EF 6 在 WPF 中刷新 DataGrid【英文标题】:Cannot refresh DataGrid in WPF using PRISM 5, MVVM, and EF 6 【发布时间】:2014-09-09 17:47:42 【问题描述】:

我的问题似乎很常见,但是,对于我在此处和其他网站上阅读的所有帖子,我仍然没有找到解决方案。

我有一个相当简单的数据输入 WPF 模块 - 2 个文本框、3 个组合框、1 个数据网格,然后是提交和清除按钮。 (该应用程序/表单用于在会计数据库中创建总分类帐帐户。)我正在使用 PRISM 5 构建我的整个解决方案。(这是我第一次涉足如此复杂的远程事物,目前,它是一个证明——概念的努力。)无论如何,我将所有 WPF 屏幕(用户控件/视图)绑定到适当的视图模型。 ViewModel 反过来通过 EF 6 实体(DB First)从 MSSS db 获取其数据。当用户打开这个特定的 WPF 屏幕时,DataGrid 会显示数据库中的所有现有记录。

除了一个例外,提交(新记录)过程按我的意愿工作:一个新条目被推送到 MSSS 数据库,文本框被清除,ComboBoxes 重置。然而,我想要的是 1)要刷新的 DataGrid,显示新记录,以及 2)在网格中突出显示该新记录。不过,就我的一生而言,我无法让它发挥作用。注意:DataGrid 绑定到数据库中的视图而不是表可能会有所不同。 (同样,当应用首次打开时,DataGrid 会正确显示。)

那么,如何让 DataGrid 更新??????

这是 WPF 视图的(精简的)XAML:

    <UserControl x:Class="AcctMappingWpfModule.Views.CreateGLAcctsView"
         other namespace declarations...
         xmlns:vms="clr-namespace:AcctMappingWpfModule.ViewModels">
<UserControl.DataContext>
        <vms:CreateGLAcctsViewModel />
    </UserControl.DataContext>
    ... 
    <StackPanel ...>
    <!-- Layout controls for 2 Text boxes & 3 ComboBoxes -->
        ...
    <!-- Data grid of all Genl Ledger accts -->
    <DataGrid x:Name="dgGLAccts" 
        IsReadOnly="True"
        SelectionUnit="FullRow"
        ...
            ItemsSource="Binding Path=GLAccounts" />
    <WrapPanel >
        <!-- Submit & Clear Buttons here -->
    </WrapPanel>
</StackPanel>

这是(精简的)ViewModel 代码(省略了 try/catch 块):

    namespace AcctMappingWpfModule.ViewModels

公共类 CreateGLAcctsViewModel : BindableBase, ICreateGLAcctsViewModel 私有 TBLOADEntities 上下文; 私人 int _glAcctID = 0; // 其他私有字段...

// Ctor...
    public CreateGLAcctsViewModel( )
    
        this.SubmitCommand = new DelegateCommand(OnSubmit);

        // Populate ICollectionViews - i.e., properties...
        using (context = new TBLOADEntities())
        
            // 3 properties behind ComboBoxes populated, then the DataGrid ppt...
            List<vwGLAcct> accts = new List<vwGLAcct>();
            accts = (from a in context.vwGLAcct select a).ToList<vwGLAcct>();
            GLAccounts = CollectionViewSource.GetDefaultView(accts);
        

        // Hook up selection change delegates, including...
        GLAccounts.CurrentChanged += GLAccounts_CurrentChanged;
    

    private void OnSubmit()
    
        GLAccount glAcct = new GLAccount()
        
    // Various properties set, then...
            GlFsAcctTypeComboFK = this.SelectedFSAcctTypeComboID
        ;
        using (context = new TBLOADEntities())
        
    context.GlAcct.Add(glAcct);
    context.SaveChanges();
    // vwGLAcct is the EF entity of the MSSS db view...
    List<vwGLAcct> accts = new List<vwGLAcct>();
            accts = (from a in context.vwGLAcct select a).ToList<vwGLAcct>();
            GLAccounts = CollectionViewSource.GetDefaultView(accts);
            SelectedGLAcctID = glAcct.GlAcctID;
            GLAccounts.Refresh();
    
    

    private void GLAccounts_CurrentChanged(object sender, EventArgs e)
    
        vwGLAcct current = GLAccounts.CurrentItem as vwGLAcct;
        SelectedGLAcctID = current.GlAcctID;
    

    public ICommand SubmitCommand  get; private set; 

    public int SelectedGLAcctID
    
        get
         return _glAcctID; 
        set
        
            SetProperty(ref _glAcctID, value);
        
    

    public ICollectionView GLAccounts  get; private set; 

【问题讨论】:

【参考方案1】:

1) 为什么你又得到了默认视图? (CollectionViewSource.GetDefaultView(accts)) 提交后?确保 accts 是 ObservableCollection 并且只获取一次默认视图,然后点击刷新它。

2) 那是Window背后的代码吗?如果是,dgGLAccts.GetBindingExpression(DataGrid.ItemsSourceProperty).UpdateTarget()

【讨论】:

1) 在 GLAccounts 上单独运行 refresh() 不会做任何事情(至少不会在视图中显示任何内容)。我正在重新创建默认视图,认为我需要在 MSSS 中“重新查询”视图。 (不过显然没有运气。) 2) 不,C# 代码是视图模型中的代码。作为 MVVM 的标准,窗口后面的唯一代码是 InitializeComponent();在 ctor 内部调用。【参考方案2】:

您可以尝试将这些从您的更改为地雷

     <DataGrid x:Name="dgGLAccts" 
              IsReadOnly="True"
              SelectionUnit="FullRow"
              SelectedItem="Binding SelectedGLAccount"
              ItemsSource="Binding Path=GLAccounts" />

    private vwGLAcct selectedGLAccount;
    public vwGLAcct SelectedGLAccount
    
        get
        
            return selectedGLAccount;
        
        set
        
            if (selectedGLAccount != value)
            
                selectedGLAccount = value;
                this.RaisePropertyChanged(() => this.SelectedGLAccount);
            
        
    

    private System.Collections.ObjectModel.ObservableCollection<vwGLAcct> gLAccounts;
    public System.Collections.ObjectModel.ObservableCollection<vwGLAcct> GLAccounts
    
        get
        
            return gLAccounts ?? (gLAccounts = new System.Collections.ObjectModel.ObservableCollection<vwGLAcct>());
        
    

public CreateGLAcctsViewModel( )

    this.SubmitCommand = new DelegateCommand(OnSubmit);

    // Populate ICollectionViews - i.e., properties...
    using (context = new TBLOADEntities())
    
        // 3 properties behind ComboBoxes populated, then the DataGrid ppt...
        List<vwGLAcct> accts = new List<vwGLAcct>();
        accts.ForEach(a => this.GLAccounts.Add(a));
    


private void OnSubmit()

    GLAccount glAcct = new GLAccount()
    
// Various properties set, then...
        GlFsAcctTypeComboFK = this.SelectedFSAcctTypeComboID
    ;
    using (context = new TBLOADEntities())
    
context.GlAcct.Add(glAcct);
context.SaveChanges();
// vwGLAcct is the EF entity of the MSSS db view...
this.GLAccounts.Add(glAcct);
this.SelectedGLAccount = glAcct;

【讨论】:

【参考方案3】:

(1) 在 ViewModel 中将您的 GLAccts 更改为 ObservableCollection 上的任何帐户类。别忘了NotifyPropertyChanged

(2) 将 CollectionViewSource(如果您需要的话)放入您的 xaml 中,并将您的 VM 属性绑定到那里的源,如下所示:

&lt;CollectionViewSource Source="Binding GLAccts" x:Key="AccountsCollection" &gt;

(3) 然后您可以像这样将数据网格绑定到该集合:

&lt;DataGrid ItemsSource="Binding Source=StaticResource AccountsCollection" ...

每当您对该 GLAccts 属性中的项目进行更改并提交更改时,只需在您的上下文中再次加载即可刷新它。

为了处理数据网格中选定/突出显示的最新添加项,您只需设置一个绑定到名为 SelectedAccount(或类似名称)的新 VM 属性,并且在 DataGrid 上具有 SelectedItem="Binding SelectedAccount, Mode=TwoWay"

当您提交一个新项目时,您可以将该项目保留为 SelectedAccount,或者在刷新整个集合时,您可以确定哪个是新项目(通过键或其他方式)。

【讨论】:

以上是关于无法使用 PRISM 5、MVVM 和 EF 6 在 WPF 中刷新 DataGrid的主要内容,如果未能解决你的问题,请参考以下文章

C# WPF MVVM模式Prism框架从零搭建(经典)

使用 Prism 和 MVVM 模式在 WPF 中创建模态对话框的“漂亮”方式

Prism/MVVM (MEF/WPF):从模块中公开导航 [例如菜单]

.NET Core 3 WPF MVVM框架 Prism系列之导航系统

六从GitHub浏览Prism示例代码的方式入门WPF下的Prism之MVVM中的FilteringEvents

带有 Prism 4 的新 LOB Silverlight 4(mvvm、mef、unity)