我看到很多关于这个主题的问题,而在我有限的 C# 和 WPF 经验中,答案过于复杂。我不敢相信微软让(对我来说)实现绑定到在运行时更改的列表框的集合变得如此困难。
这是交易:我有一个包含项目的列表框(实际上是电子邮件列表)。发生的情况是,当新电子邮件到达或从源文件夹中删除时,我需要刷新列表框。听起来很容易,但无论如何操作 Observable Collection 都会导致可怕的“这种类型的 CollectionView 不支持从与 Dispatcher 线程不同的线程对其 SourceCollection 的更改。”
所以暂时不要介意通过编写调度程序来规避这个问题。是否有一些“正常”的方式来操作不是来自另一个线程的集合?——这就是我困惑的地方。我还能在哪里修改集合?如果这是预期的,我很乐意将我的代码放在那里。
我当前的实现——很可能很糟糕——是将Folder.Items 事件处理程序放在集合类本身中,然后从集合(即它本身)中添加/删除电子邮件。这不起作用,我真的不明白如何做到这一点。
好的,我整理了这个代码示例。这不是我的应用程序,但它几乎代表了我(错误地)处理事情的方式......这将引发“无法更新源收集线程错误”。该示例分为 3 个部分,首先是 XAML 标记,然后是 Main 类和方法以及 ObservableCollection 类。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Class="WpfApplication1.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot" >
<Border BorderBrush="#FF404020" BorderThickness="5" Margin="0" Background="#FFFFFFC0" CornerRadius="25">
<ListBox x:Name="lbList" Margin="50" FontSize="21.333" DisplayMemberPath="Subject"/>
</Border>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Outlook;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MailList ml = new MailList();
public MainWindow()
{
this.InitializeComponent();
Microsoft.Office.Interop.Outlook.Application olApp = Marshal.GetActiveObject("Outlook.Application") as Microsoft.Office.Interop.Outlook.Application;
Folder f = (Folder)olApp.Session.PickFolder(); // User picks MAPI Folder
f.Items.ItemAdd += new ItemsEvents_ItemAddEventHandler(this.UpdateListBox); //Folder.Item add event, calls UpdateListBox
foreach (object o in f.Items)
{
if (o is MailItem)
{
ml.Add((MailItem)o); //Add Mailitems to ml collection
}
}
Binding b = new Binding(); //create binding for ListBox
b.Mode = BindingMode.OneWay;
lbList.DataContext = ml;
lbList.SetBinding(ListBox.ItemsSourceProperty, b);
}
public void UpdateListBox(object o) //Add new MailItem to ml collection
{
if (o is MailItem)
{
ml.Add((MailItem)o);
}
}
}
}
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using Microsoft.Office.Interop.Outlook;
namespace WpfApplication1
{
public class MailList : ObservableCollection<MailItem>
{
public MailList()
: base()
{
}
}
}