[英]How can I prevent the ObservableCollection from being refreshed for no reason in WPF?
I have C# WPF project that is save data from DataGrid
into a Table in SQL Server Database我有C# WPF项目,它将DataGrid
中的数据保存到 SQL 服务器数据库中的表中
In Database I have two tables as Factor
and Commodity
that related to each other and在数据库中,我有两个表作为Factor
和Commodity
,它们相互关联,并且
The DataGrid ItemsSource
filled by an ObservableCollection
is named WHOLE_DATA_FACTOR
that is from Factor
Table由ObservableCollection
填充的 DataGrid ItemsSource
名为WHOLE_DATA_FACTOR
,它来自Factor
表
and ItemsSource
of DataGridComboBoxColumn
it is filled only once when loading the program, After I Insert into Factor
table in RowEditEnding
event I want to Reload data for DataGrid,和DataGridComboBoxColumn
的ItemsSource
在加载程序时仅填充一次,在RowEditEnding
事件中插入Factor
表后,我想为 DataGrid 重新加载数据,
The DataGridComboBoxColumn
items were filled once by a query in the SELECT CommodityCode, CommodityName FROM dbo.Commodity
, but I noticed that after LoadDataAgian
, the items that were in the collection started to refresh (as if moving on each item), and this made the program slow down, and also The DataGridComboBoxColumn
ItemsSource
starts to fill again, while I didn't do that DataGridComboBoxColumn
项目由SELECT CommodityCode, CommodityName FROM dbo.Commodity
中的查询填充一次,但我注意到在LoadDataAgian
之后,集合中的项目开始刷新(好像在每个项目上移动),这使得程序变慢,并且DataGridComboBoxColumn
ItemsSource
再次开始填充,而我没有这样做
Here is the Video what happened :这是发生了什么的视频:
mp4: https://ufile.io/p5azjp40 mp4: https://ufile.io/p5azjp40
Full Source Code and DB : https://ufile.io/uxneng9r完整源代码和数据库: https://ufile.io/uxneng9r
XAML : XAML :
<DataGridComboBoxColumn Width="160" Header="DataGridComboBoxColumn"
SelectedValueBinding="{Binding CommodityID}"
DisplayMemberPath="CommodityName"
SelectedValuePath="CommodityCode"
>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=TheCommodityCombo_DATA, RelativeSource={RelativeSource AncestorType=Window}}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=TheCommodityCombo_DATA, RelativeSource={RelativeSource AncestorType=Window}}" />
<Setter Property="IsEditable" Value="True"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
<DataGridComboBoxColumn Width="200" Header="Status ComboBoxColumn"
SelectedValueBinding="{Binding STATUS}"
DisplayMemberPath="STATUS_NAME"
SelectedValuePath="STATUS">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.STATUS_COMBO_DATA, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.STATUS_COMBO_DATA, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<Setter Property="IsEditable" Value="True"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="True"/>
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"/>
<Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
Code Behind :代码背后:
public partial class MainWindow : Window
{
/// <summary>
/// For Ensuring the new data is getting in Row end edit
/// </summary>
private bool _handle = true;
MyerEntities dbms = new MyerEntities();
#region Models and Collections
/// <summary>
/// For Factor Table
/// </summary>
public class MyCustomModel_Factor
{
public long? NUMBER { get; set; }
public string CustomerName { get; set; }
public long? CommodityID { get; set; }
public long? STATUS { get; set; }
}
public ObservableCollection<MyCustomModel_Factor> WHOLE_DATA_FACTOR { get; set; } = new ObservableCollection<MyCustomModel_Factor>();
/// <summary>
/// For Commodity Table for ComboBox Items
/// </summary>
public ObservableCollection<MyCustomModel_Commodity> TheCommodityCombo_DATA { get; set; } = new ObservableCollection<MyCustomModel_Commodity>();
public class MyCustomModel_Commodity
{
public long CommodityCode { get; set; }
public string CommodityName { get; set; }
}
//STATUS
public ObservableCollection<CutsomStatus_Model> STATUS_COMBO_DATA { get; set; } = new ObservableCollection<CutsomStatus_Model>();
public class CutsomStatus_Model
{
public long? STATUS { get; set; }
public string STATUS_NAME { get; set; }
}
#endregion
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Filling DataGrid by ObservableCollection
WHOLE_DATA_FACTOR.Clear();
var RST = dbms.Database.SqlQuery<MyCustomModel_Factor>("SELECT * FROM Factor").ToList();
foreach (var item in RST)
{ WHOLE_DATA_FACTOR.Add(item); }
//Filling ComboBox from Another Table that Related to Factor Table
TheCommodityCombo_DATA.Clear();
var RST2 = dbms.Database.SqlQuery<MyCustomModel_Commodity>("SELECT CommodityCode, CommodityName FROM dbo.Commodity").ToList();
foreach (var item2 in RST2)
{
TheCommodityCombo_DATA.Add(item2);
}
//STATUS Filling
STATUS_COMBO_DATA.Add(new CutsomStatus_Model { STATUS = 1, STATUS_NAME = "Undone" });
STATUS_COMBO_DATA.Add(new CutsomStatus_Model { STATUS = 2, STATUS_NAME = "Done" });
STATUS_COMBO_DATA.Add(new CutsomStatus_Model { STATUS = 3, STATUS_NAME = "Canceled" });
}
private void MainDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
try
{
var WhatWasRow = e.Row.Item as MyCustomModel_Factor;
var TheCurrentColumnName = MainDataGrid.CurrentColumn.SortMemberPath;
var test = WhatWasRow.GetType().GetProperty(TheCurrentColumnName).GetValue(WhatWasRow);
var Editedrow = (e.EditingElement as ComboBox);
var test3 = ((System.Windows.Controls.Primitives.Selector)e.EditingElement).SelectedValue;
}
catch (Exception)
{ goto OnErrorResumeNext; }
OnErrorResumeNext:;
}
private void MainDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
if (_handle)
{
_handle = false;
MainDataGrid.CommitEdit();
var ROW_ITM = e.Row.Item as MyCustomModel_Factor;
//...Do Insert
dbms.Database.ExecuteSqlCommand($"INSERT INTO dbo.Factor (CustomerName,CommodityID,STATUS) VALUES (N'{ROW_ITM.CustomerName}',{ROW_ITM.CommodityID},{ROW_ITM.STATUS})");
//I think i need somthing like this ↓_________________________________
//ObservableCollection.WHOLE_DATA_FACTOR.IsEnabled = false;
//ObservableCollection.TheCommodityCombo_DATA.IsEnabled = false;
//ObservableCollection.STATUS_COMBO_DATA.IsEnabled = false;
LoadDataAgian();
_handle = true;
//ObservableCollection.WHOLE_DATA_FACTOR.IsEnabled = true;
//ObservableCollection.TheCommodityCombo_DATA.IsEnabled = true;
//ObservableCollection.STATUS_COMBO_DATA.IsEnabled = true;
//_______________________________________________________________________
return;
//After this line , most stop continue ,
//but it will go for → ObservableCollections property { get; set; } to refreshing every item , it feels Requery
}
}
private void LoadDataAgian()
{
WHOLE_DATA_FACTOR.Clear();
var RST = dbms.Database.SqlQuery<MyCustomModel_Factor>("SELECT * FROM Factor").ToList();
foreach (var item in RST)
{ WHOLE_DATA_FACTOR.Add(item); }
}
}
Related link: Updating an ObservableCollection in WPF causes screen flicker;相关链接: 更新 WPF 中的 ObservableCollection 会导致屏幕闪烁; How can I prevent it? 我该如何预防?
Can I somehow temporarily disable WPF data binding changes? 我可以以某种方式暂时禁用 WPF 数据绑定更改吗?
Update : -The ItemsSource
of the DatGrid
is filled from the Factor
table -The ItemsSource
of the DataGridComboBoxColumn
is filled with Commoditiy
更新: DataGridComboBoxColumn
的ItemsSource
由Factor
表填充DatGrid
的ItemsSource
由Commoditiy
填充
When I want to Realod DataGrid's Data by "select * from Factor"
I Only Reloaded the DataGrid's ItemsSource not The ItemsSource of the DataGridComboBoxColumn why DataGridComboBoxColumn's ItemsSource will refresh (as if moving on each item)当我想通过"select * from Factor"
重新加载 DataGrid 的数据时,我只重新加载了 DataGrid 的 ItemsSource 而不是 DataGridComboBoxColumn 的 ItemsSource 为什么 DataGridComboBoxColumn 的 ItemsSource 会刷新(好像在每个项目上移动)
NOTE: if explanation was not good please check the video and comment in my code注意:如果解释不好,请查看我的代码中的视频和评论
Best Regards此致
Whenever you modify (add/remove) the ObservableCollection
, the Target
will be triggered and will start calling the getters {set; get;}
每当您修改(添加/删除) ObservableCollection
时,都会触发Target
并开始调用 getter {set; get;}
{set; get;}
of the collections' items to update itself. {set; get;}
集合的项目来更新自己。
If this behaviour does not meet your needs, you can do the following:如果此行为不能满足您的需求,您可以执行以下操作:
Replace ObservableCollection
with List
.将ObservableCollection
替换为List
。
Let the class implement INotifyPropertyChanged
interface, like so (based on your code):让 class 实现INotifyPropertyChanged
接口,如下所示(基于您的代码):
public partial class MainWindow : Window, INotifyPropertyChanged {
// ..
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// ..
}
OnPropertyChanged
:每当您想从代码中更新 UI 时,您都可以使用OnPropertyChanged
显式执行此操作:private void Window_Loaded(object sender, RoutedEventArgs e)
{
//Filling DataGrid by ObservableCollection
WHOLE_DATA_FACTOR = new List<MyCustomModel_Commodity>();
var RST = dbms.Database.SqlQuery<MyCustomModel_Factor>("SELECT * FROM Factor").ToList();
foreach (var item in RST)
WHOLE_DATA_FACTOR.Add(item);
OnPropertyChanged(nameof(WHOLE_DATA_FACTOR));
// ..
}
NOTE that I've created a new List<MyCustomModel_Commodity>()
, so to update the Target
that is bound to a List
, you have to give it a new reference, you could also just do WHOLE_DATA_FACTOR = WHOLE_DATA_FACTOR.ToList()
just before calling OnPropertyChanged
请注意,我创建了一个new List<MyCustomModel_Commodity>()
,因此要更新绑定到List
的Target
,您必须为其提供新的参考,您也可以在之前执行WHOLE_DATA_FACTOR = WHOLE_DATA_FACTOR.ToList()
调用OnPropertyChanged
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.