c# - WPF 不会始终刷新组合框项目列表
问题描述
我正在 WPF 中做一个小宠物项目,我对此很陌生。
我的(部分)目标如下:
- 打开主窗口,其中包含两个标记为系统和文档的组合框
- 加载此窗口后,我连接到一个 .mdb 文件,该文件包含一个带有 System 和 Document 列的表。
- 它创建存储在数据库文件中的所有不同系统名称的 ObservableCollection,并将它们存储为我的“系统”组合框绑定到的 arrayList。它成功填满组合框并选择列表的第一个成员作为选定项。
- “System”组合的 selectedItem 是 OneWayToSource 绑定到名为 SystemFilter 的字符串。每当我更改选择时,此字符串都会成功更新。
- 使用此 SystemFilter,我设法过滤文档并获取存储在 TitleList 可观察集合中的相关标题列表,并正确填充“文档”组合框。
它工作正常,但是每次我过滤数据库时,我都会创建与文件的连接,过滤内容提取它并关闭连接。在这里,为了避免每次都打开此连接,我决定将所有项目加载到一个名为 DocumentList 的 ObservableCollection 中,并打算在其上运行 LINQ 查询。以及我存储在绑定到组合框的列表中的查询结果。问题:但是在这种情况下,当我选择另一个系统时,组合框项目列表不想自动更新。这可能是什么原因?
/注意:我在 BaseViewModel 中应用了 INotifyPropertyChanged,并使用 FodyWeaver 来编织我的程序集)
原始工作版本:
两个组合框:
<!--System--> <TextBlock Margin="5 0 0 0" Text="System" FontWeight="Bold" HorizontalAlignment="Left"/> <ComboBox SelectionChanged="Combobox_Doc_Sys_SelectionChanged" x:Name="Combobox_Doc_Sys" ItemsSource="{Binding SystemList}" SelectedItem="{Binding SystemFilter,Mode=OneWayToSource}" SelectedIndex="{Binding SystemIndex, Mode=TwoWay}" Padding="2" Margin="5 0 5 0" > </ComboBox> <!--Document--> <TextBlock Margin="5 10 0 0" Text="Document" FontWeight="Bold" HorizontalAlignment="Left"/> <ComboBox x:Name="Combobox_Doc_Doc" SelectionChanged="Combobox_Doc_Doc_SelectionChanged" ItemsSource="{Binding TitleList}" SelectedItem="{Binding TitleFilter, Mode=OneWayToSource}" Padding="2" Margin="5 0 5 0" SelectedIndex="0"> </ComboBox>
MainWindow 的代码隐藏
public MainWindow() { InitializeComponent(); //Create ViewModel correalating to mainwindow this.DataContext = new MainWindowViewModel(); } /// <summary> /// Event correlating the change of the selected item in Document section's System combobox ///// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Combobox_Doc_Sys_SelectionChanged(object sender, SelectionChangedEventArgs e) { //Call ViewModel's function to filter documentlist based on the Selected system MainWindowViewModel.GetListOfTitle(); //MainWindowViewModel.GetListOfTitle2(); // Restores the selection to the first item in Document section's Document combobox Combobox_Doc_Doc.SelectedIndex = 0; }
连接到 .mdb 文件的 GetListOfTitle() 函数:
public static void GetListOfTitle() { //List that will store the list of the title //filtering SQL string sysFilterSQL = $"SELECT * FROM DocList WHERE System='{SystemFilter}'"; //Clear List for safety sake TitleList.Clear(); using (OleDbConnection MyConnection = new OleDbConnection(ConnectStringDocList)) { OleDbCommand command = new OleDbCommand(sysFilterSQL, MyConnection); command.Connection = MyConnection; MyConnection.Open(); OleDbDataReader reader = command.ExecuteReader(); //We fill up TitleList with the list of the titles filtered by "system" while (reader.Read()) { var item = reader.GetString(2); TitleList.Add(item); } //Close reader reader.Close(); //Close connection MyConnection.Close(); } }
参数
public static ObservableCollection<string> TitleList { get; set; } = new ObservableCollection<string>();
公共静态字符串 SystemFilter { 获取;放; } = 字符串。空;
当我更改为新版本时,我首先成功地用文档填写了 DocumentList。GetListofTitle2 方法:
internal static void GetListOfTitle2()
{
TitleList = (from s in DocumentList where s.System == $"{SystemFilter}" select s.Title).ToList();
}
和:
public static ObservableCollection<DocumentModel> DocumentList { get; set; } = new ObservableCollection<DocumentModel>();
//--------------------------------------------------------------------------------------------//
public static string SystemFilter { get; set; } = String.Empty;
//--------------------------------------------------------------------------------------------//
public static List<string> TitleList { get; set; } = new List<string>();
在这个新版本中,TitleList 再次正确更新,但在界面上没有更新:/ 有什么问题?我想解决它,因为此解决方案似乎比每次打开连接并加载 .mdb 文件时更干净
感谢您提前回答
更新:如果我修改第二个版本仍然使用 observableCollections 并修改 GetListofTitle2 如下:
public static void GetListOfTitle2()
{
TitleList =new ObservableCollection<string>((from s in DocumentList where s.System == $"{SystemFilter}" select s.Title).ToList());
}
即使 TitleList 包含正确的项目,它仍然不会更新组合框。
解决方案
- 如果您更改模型中的实例
TitleList
,模型应该实现INotifyPropertyChanged
接口,并且您必须按照此处PropertyChanged
的说明触发一个事件(此外,在此之后,请查看此处)。 - 如果引用
TitleList
保持不变但发生变异(添加或删除元素),则它必须实现INotifyCollectionChanged
,而这正是ObservableCollection
做什么。
这段代码:
TitleList = new ObservableCollection<string>(...);
属于第 1类:您更改TitleList
实例。
但是您使用不触发PropertyChanged
事件的自动属性,因此不会刷新绑定:
// this is an auto-property
public List<string> TitleList { get; set; }
// it's equivalent to:
private List<string> _titleList;
public List<string> TitleList
{
get => _titleList;
set => _titleList = value;
}
您必须在块中触发一个PropertyChanged
事件:set
private List<string> _titleList;
public List<string> TitleList
{
get => _titleList;
set
{
// if the new value is the same as the old, just do nothing
if (Equal(_titleList, value))
return;
_titleList = value;
// This call will raise the event
NotifyPropertyChanged();
}
}
推荐阅读
- python - 绘制水平条形图,给出意想不到的结果
- r - 将 blogdown 与 github 操作一起使用 - 替代 serve_site
- graphql - GraphQL 允许使用可为空条目定义数组的技术原因是什么?
- for-loop - 使用具有 2 个参数的机器人框架进行循环
- laravel - Laravel 与 Laratrust - Mix 清单不存在?
- javascript - MongoDB查询从数组中检索所有内容?
- c++ - 掩蔽结构名称
- vaadin - import com.gitlab.mvysny.jdbiorm.Dao 对我来说失败了
- python - 使用 pd.read 的 Python File Not Found 错误
- node.js - 即使存在依赖项,npm 也无法安装 quick.db