使用可观察对象从数据库中使用数据绑定更新数据网格
Update datagrid using data binding from database using observable object
我正在尝试使用尽可能接近 MVVM 的数据绑定来使用数据库中的数据更新 WPF 数据网格。我想我仍然在为这个概念而苦苦挣扎,在我经历过的任何例子中我都没有找到(或理解)答案。 post 中有很多信息,但除非我遗漏了什么,否则我下面的具体问题没有得到解决。
问题:
如何在另一个 class 更新 SQL 数据库时触发 PropertyChangedEventArgs?
我试过如下方法,但是,它不起作用(大概是因为我在新实例中通知)。如果我重新打开 window 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
}
编辑 捕捉评论"from Juan Carlos Rodriguez"
我已按如下方式修改 TableView.xaml.cs,这确实解决了来自视图 class 的更新 SQL 调用的问题,因此感谢您的回复。很有用。
ViewModel co;
public TableView()
{
SQL.InsertNode();
InitializeComponent();
co = new ViewModel();
base.DataContext = co;
}
public void AddNode()
{
SQL.InsertNode();
co.Nodes.Clear();
co.FillList();
}
但是,我需要能够从其他 classes 更新 SQL 数据库,所以我将遇到同样的问题。我知道这行不通,但这是我最想解决的问题。
随机一些class
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。
请编辑您的 post 并说明您调用 AddNode
的位置以及显示视图的方式,以便我告诉您如何修复它。
首先,这不遵循 MVVM,因为您将代码放在视图代码隐藏中:
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
}
话虽这么说,但对于您的实际问题,我建议您使用事件。这实际上取决于您的架构是如何构建的。我会给出一个可能的方法:
创建一个新的 class 来包含您的活动:
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());
我正在尝试使用尽可能接近 MVVM 的数据绑定来使用数据库中的数据更新 WPF 数据网格。我想我仍然在为这个概念而苦苦挣扎,在我经历过的任何例子中我都没有找到(或理解)答案。
问题: 如何在另一个 class 更新 SQL 数据库时触发 PropertyChangedEventArgs?
我试过如下方法,但是,它不起作用(大概是因为我在新实例中通知)。如果我重新打开 window 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
}
编辑 捕捉评论"from Juan Carlos Rodriguez"
我已按如下方式修改 TableView.xaml.cs,这确实解决了来自视图 class 的更新 SQL 调用的问题,因此感谢您的回复。很有用。
ViewModel co;
public TableView()
{
SQL.InsertNode();
InitializeComponent();
co = new ViewModel();
base.DataContext = co;
}
public void AddNode()
{
SQL.InsertNode();
co.Nodes.Clear();
co.FillList();
}
但是,我需要能够从其他 classes 更新 SQL 数据库,所以我将遇到同样的问题。我知道这行不通,但这是我最想解决的问题。
随机一些class
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。
请编辑您的 post 并说明您调用 AddNode
的位置以及显示视图的方式,以便我告诉您如何修复它。
首先,这不遵循 MVVM,因为您将代码放在视图代码隐藏中:
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
}
话虽这么说,但对于您的实际问题,我建议您使用事件。这实际上取决于您的架构是如何构建的。我会给出一个可能的方法:
创建一个新的 class 来包含您的活动:
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());