2

そのため、ディスクから 400 ~ 600 個の画像 (それぞれのサイズは約 200Kb) をロード (および表示) する必要がある WPF コントロールを構築しています。次は、コントロールの分離コードです。

private List<BitmapImage> pages = new List<BitmapImage>();

        private BackgroundWorker worker;

        public PagesListBox()
        {
            InitializeComponent();
            worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = false;
            worker.WorkerReportsProgress = false;
            worker.DoWork += worker_DoWork;
            worker.RunWorkerCompleted += worker_RunWorkerCompleted;
        }

        void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            List<BitmapImage> pagesList = new List<BitmapImage>();
            var files = DirectoryServices.GetFiles(Properties.Settings.Default.PagesScanDirectory, new string[] { "*.tiff", "*.jpg", "*.png", "*.bmp" });
            foreach (var file in files)
            {
                Uri uri = new Uri(file);
                pagesList.Add(new BitmapImage(uri));
            }
            e.Result = pagesList;
        }

        void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            Pages.ItemsSource = (List<BitmapImage>)e.Result;
        }

        internal void LoadPages()
        {
            worker.RunWorkerAsync();
        }

        internal List<BitmapImage> AttachPages()
        {
            List<BitmapImage> attachedPages = new List<BitmapImage>();

            foreach (BitmapImage eachItem in Pages.SelectedItems)
            {
                attachedPages.Add(eachItem);
                pages.Remove(eachItem);
            }
            Pages.ItemsSource = null;
            Pages.ItemsSource = pages;

            return attachedPages;
        }

ページ リストをビューに割り当てようとしましたが (バックグラウンド ワーカーは使用できません)、失敗します。

画像を非同期にロードする他の方法はありますか (おそらく UI を更新します)、または私が試みているバックグラウンド ワーカーのこのアプローチは問題ありません。そして、問題がなければ、どうすれば例外を解決できますか (完了イベント内):

Must create DependencySource on same Thread as the DependencyObject.

ありがとう

4

1 に答える 1

2

コードを簡素化するには、List<> ではなく ObservableCollection<> を使用し、ItemsSource プロパティを 1 回だけ割り当てます。

スレッド エラーは、ビットマップを作成し、それをメイン UI スレッドではなくバックグラウンド ワーカー スレッドのリストに追加しているためです。これを回避するには、DispatcherHelper (Laurent Bugnion の MVVMLight Framwwork から取得) を使用します。

まったく異なる考え方ですが、「Winforms の方法」で物事を行うのではなく、多くの WPF 開発を行う場合は、MVVM をアプリケーション設計方法論として検討することをお勧めします。

...
DispatcherHelper.Initialise()
...


private ObservableCollection<BitmapImage> _Pages = new ObservableCollection<BitmapImage>();

public PagesListBox()
{
    InitializeComponent();
    BackgroundWorker worker = new BackgroundWorker();
    worker.WorkerSupportsCancellation = false;
    worker.WorkerReportsProgress = false;
    worker.DoWork += worker_DoWork;
    this.ItemSource = _Pages;
}

void worker_DoWork(object sender, DoWorkEventArgs e)
{
     var files = DirectoryServices.GetFiles(Properties.Settings.Default.PagesScanDirectory, new string[] { "*.tiff", "*.jpg", "*.png", "*.bmp" });
    foreach (var file in files)
    {
        DispatcherHelper.CheckBeginInvokeOnUI(()=>
        {
            Uri uri = new Uri(file);
            _Pages.Add(new BitmapImage(uri));
        });
    }
}


public static class DispatcherHelper
{
    public static Dispatcher UIDispatcher { get; private set; }

    public static void CheckBeginInvokeOnUI(Action action)
    {
        if (UIDispatcher.CheckAccess())
            action();
        else
            UIDispatcher.BeginInvoke(action);
    }

    public static void Initialize()
    {
        if (UIDispatcher != null)
            return;

        UIDispatcher = Dispatcher.CurrentDispatcher;
    }
}
于 2012-04-13T09:26:46.873 に答える