使用Observable Collection实现WPF Listbox的最简单方法

时间:2012-08-21 22:27:36

标签: wpf listbox observablecollection

我看到很多关于这个主题的问题,而且在我有限的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()
        {
        }
    }
}

1 个答案:

答案 0 :(得分:1)

将调度集合更改分配给UI线程应该是什么问题?据我所知,这是通常的方式。