使用可观察对象使用数据库中的数据绑定更新数据网格

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用可观察对象使用数据库中的数据绑定更新数据网格相关的知识,希望对你有一定的参考价值。

我正在尝试使用尽可能接近MVVM的数据绑定来使用数据库中的数据更新WPF数据网格。我想我仍然在努力学习这个概念,在我所经历过的任何一个例子中,我都没有找到(或理解)这个概念。在this帖子中有很多信息,但除非我遗漏了某些内容,否则我的具体问题不会得到解决。

问题:当另一个类更新SQL数据库时,如何触发PropertyChangedEventArgs?

我尝试了如下的东西,然而,它不起作用(大概是因为我在一个新的实例中通知)。如果我重新打开XAML的窗口,我可以看到其他条目已添加到数据库中,它只是不会自动更新。

TableView.xaml.cs

private void AddNode()
{
    SQL.InsertNode(); //this fires a method to add a row to the database
    ViewModel viewmodel = new ViewModel(); //this fires the messagebox in my viewmodel the the notification is raised
    viewmodel.FillList(); // this doesn't seem to do anything. Cluthing at straws really
}

希望我走在正确的轨道上。为了帮助回答这个问题,我已经提供了我认为你需要的所有内容。

这是我的XAML - TableView.xaml

<DataGrid Grid.Row="2" 
          x:Name="NodeTableDataGrid" 
          ItemsSource="{Binding Nodes, Mode=TwoWay}" 
          Grid.ColumnSpan ="3" 
          CanUserAddRows="False" 
          AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Add Row" IsReadOnly="True" Visibility="Visible"/>
        <DataGridTextColumn Header="Id" Binding="{Binding Path='id'}" IsReadOnly="True" Visibility="Visible"/>
        <DataGridTextColumn Header="Node Name" Binding="{Binding Path='NodeName', Mode=TwoWay}" IsReadOnly="False" />
        <DataGridTextColumn Header="Easting (m)" Binding="{Binding Path='x'}" IsReadOnly="False" />
        <DataGridTextColumn Header="Northing (m)" Binding="{Binding Path='y'}" IsReadOnly="False" />
        <DataGridTextColumn Header="Cover Level (m)" Binding="{Binding Path='z_cover'}" IsReadOnly="False" />
    </DataGrid.Columns>
</DataGrid>

这是后面的代码 - TableView.xaml.cs

public TableView()
{
    InitializeComponent();
    co = new ViewModel();
    base.DataContext = co;
}

和我的视图模型

public class ViewModel : INotifyPropertyChanged
{
    SQLiteCommand command;
    SQLiteDataAdapter adapter;
    DataSet ds;

    private ObservableCollection<MyModel> _nodes;
    public ObservableCollection<MyModel> Nodes
    {
        get
        {
            return this._nodes;
        }
        set
        {
            if (_nodes != value)
            {
                MessageBox.Show("Table changed");
                OnPropertyChanged("Nodes");
            }

            this._nodes = value;
        }
    }


    public ViewModel()
    {            
        FillList();
    }

    public void FillList()
    {
        try
        {
            string sql = "SELECT * FROM node_table";
            command = new SQLiteCommand(sql, SQL.m_dbConnection);
            adapter = new SQLiteDataAdapter(command);
            ds = new DataSet();
            adapter.Fill(ds, "node_table");

            if (Nodes == null)
                Nodes = new ObservableCollection<MyModel>();

            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                Nodes.Add(new MyModel
                {
                    id = Convert.ToInt32(dr[0].ToString()),
                    NodeName = dr[1].ToString(),
                    x = Convert.ToInt32(dr[2].ToString()),
                    y = Convert.ToInt32(dr[3].ToString()),
                    z_cover = Convert.ToInt32(dr[4].ToString())

                });
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show("The table view has failed to load from the database with the following error: " + ex.ToString());
        }
        finally
        {
            ds = null;
            adapter.Dispose();
        }
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion


}

编辑捕获评论“来自Juan Carlos Rodriguez”

我修改了TableView.xaml.cs,如下所示,它修复了View类更新的SQL调用的问题,所以感谢您的回复。很有用。

    ViewModel co;

    public TableView()
    {
        SQL.InsertNode();
        InitializeComponent();
        co = new ViewModel();
        base.DataContext = co;
    }

    public void AddNode()
    {
        SQL.InsertNode();
        co.Nodes.Clear();
        co.FillList();
    }

但是,我需要能够从其他类更新SQL数据库,因此我将遇到同样的问题。我知道这不起作用,但这是我要修复的bext位。

一些随机的课

    public void AddNodeFromRandomClass()
    {
        //Updates the database succesafully, however raises the change in the wrong instance of TableView.
        TableView tableView = new TableView();
        tableView.AddNode();
    }
答案

它不会永远不会引发Nodes的集合,因为你没有创建一个新的ObservableCollection实例,你正在向它添加不会引发集合的项目。更改实例时会引发ObservableCollection集。

Nodes.Add( new MyModel()) -> "Doesn't raise the set."

ObservableCollection<MyModel> myModelOC = new ObservableCollection<MyModel>() { "Declare 3 items" };
Nodes = myModelOC -> "This will raise the set".

现在我解释了这个(我希望我解释一下,如果不是让我知道的话)我想问你几个问题。我看到了这个:

public TableView()
{
  InitializeComponent();
  co = new ViewModel();
  base.DataContext = co;
}

这是你的xaml.cs?

无论如何,我想说你的问题是你正在设置一个DataContext然后从另一个私有方法创建一个新的VM,所以你的DataContext的VM实例和你在私有中创建的VM完全不同,这就是为什么你不是'更新您的DataGrid,您正在更新未在视图中设置为DataContext的VM。

请编辑您的帖子,并指出您在哪里调用AddNode以及如何显示您的视图,以便我可以告诉您如何解决它。


首先,这不会跟随MVVM,因为您将代码置于View代码隐藏中:

ViewModel co;

public TableView()
{
    SQL.InsertNode();
    InitializeComponent();
    co = new ViewModel();
    base.DataContext = co;
}

public void AddNode()
{
    SQL.InsertNode();
    co.Nodes.Clear();
    co.FillList();
}

在你做TableView.Show()之前,你必须创建一个ViewModel并设置TableView DataContext。它会是这样的:

ViewModel yourViewModel = new ViewModel();
TableView tableView = new TableView();
tableView.DataContext = yourViewModel;
tableView.Show();

你的TableView.xaml.cs构造函数应该是这样的:

public TableView()
{
  InitializeComponent();
}

你的ViewModel构造函数应该是这样的:

public ViewModel()
{   
    FillList();
    Nodes.Clear();// You could do this if you need it to be cleared
}

话虽如此,对于你真正的问题,我建议你使用事件。这实际上取决于您的架构是如何构建的。我会给出一个可能的方法:

创建一个包含您的事件的新类,如下所示:

public static class UpdaterEvent 
{
    public static event EventHandler DataUpdated;

    public static void PublishDataUpdated(EventArgs args) 
    {
        var updaterEvent = DataUpdated;
        if (updaterEvent != null)
            updaterEvent(null, args);
    }
}

现在在您的ViewModel构造函数中添加以下内容:

public ViewModel()
{   
    FillList();
    Nodes.Clear();// You could do this if you need it to be cleared
    UpdaterEvent.DataUpdated += OnDataUpdated;        
}

private void OnDataUpdated(object sender, EventArgs e)
{
  FillList();
}

无论何时需要更新数据,只需执行以下操作:

UpdaterEvent.PublishDataUpdated(new EventArgs());

以上是关于使用可观察对象使用数据库中的数据绑定更新数据网格的主要内容,如果未能解决你的问题,请参考以下文章

刷新 WPF Datagrid 未绑定到可观察集合?

Combine + SwiftUI 中的最佳数据绑定实践?

KendoUI:将视图模型绑定到数据源更改

WPF 数据网格绑定工具提示在表格内容绑定刷新时闪烁

正确单击数据网格中的按钮时,Telerik RadGridView 选定项绑定不起作用

Clarity Datagrid-尝试使用克隆对象设置选择不起作用