Calling ShowDialog in BackgroundWorker

后端 未结 4 891
佛祖请我去吃肉
佛祖请我去吃肉 2020-12-11 17:46

I have a WinForms application in which my background worker is doing a sync task, adding new files, removing old ones etc.

In my background worker code I want to sho

4条回答
  •  伪装坚强ぢ
    2020-12-11 18:23

    IMO answers stating that you should launch a thread to handle this are misguided. What you need is to jump the window back to the main dispatcher thread.

    In WPF

    public ShellViewModel(
        [NotNull] IWindowManager windows, 
        [NotNull] IWindsorContainer container)
    {
        if (windows == null) throw new ArgumentNullException("windows");
        if (container == null) throw new ArgumentNullException("container");
        _windows = windows;
        _container = container;
        UIDispatcher = Dispatcher.CurrentDispatcher; // not for WinForms
    }
    
    public Dispatcher UIDispatcher { get; private set; }
    

    and then, when some event occurs on another thread (thread pool thread in this case):

    public void Consume(ImageFound message)
    {
        var model = _container.Resolve();
        model.ForImage(message);
        UIDispatcher.BeginInvoke(new Action(() => _windows.ShowWindow(model)));
    }
    

    WinForms equivalent

    Don't set UIDispatcher to anything, then you can do have:

    public void Consume(ImageFound message)
    {
        var model = _container.Resolve();
        model.ForImage(message);
        this.Invoke( () => _windows.ShowWindow(model) );
    }
    

    DRYing it up for WPF:

    Man, so much code...

    public interface ThreadedViewModel
        : IConsumer
    {
        /// 
        /// Gets the UI-thread dispatcher
        /// 
        Dispatcher UIDispatcher { get; }
    }
    
    public static class ThreadedViewModelEx
    {
        public static void BeginInvoke([NotNull] this ThreadedViewModel viewModel, [NotNull] Action action)
        {
            if (viewModel == null) throw new ArgumentNullException("viewModel");
            if (action == null) throw new ArgumentNullException("action");
            if (viewModel.UIDispatcher.CheckAccess()) action();
            else viewModel.UIDispatcher.BeginInvoke(action);
        }
    }
    

    and in the view model:

        public void Consume(ImageFound message)
        {
            var model = _container.Resolve();
            model.ForImage(message);
            this.BeginInvoke(() => _windows.ShowWindow(model));
        }
    

    Hope it helps.

提交回复
热议问题