我看到很多关于这个主题的问题,而且在我有限的C#和WPF经验中,答案过于复杂。我无法相信微软已经让我(实际上)难以实现绑定到在运行时更改的Listbox的集合。
这是交易:我有一个包含项目的列表框(实际上是电子邮件列表)。发生的情况是,当新电子邮件到达或从源文件夹中删除时,我需要刷新列表框。听起来很容易,但无论如何操纵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()
{
}
}
}
答案 0 :(得分:1)
将调度集合更改分配给UI线程应该是什么问题?据我所知,这是通常的方式。