简体   繁体   English

C#WPF从工作线程更新UI

[英]C# WPF Updating UI from Worker Thread

using System;
using System.Linq;
using Microsoft.Practices.Prism.MefExtensions.Modularity;
using Samba.Domain.Models.Customers;
using Samba.Localization.Properties;
using Samba.Persistance.Data;
using Samba.Presentation.Common;
using Samba.Presentation.Common.Services;
using System.Threading;


namespace Samba.Modules.TapiMonitor
{
    [ModuleExport(typeof(TapiMonitor))]
    public class TapiMonitor : ModuleBase
    {

        public TapiMonitor()
        {
            Thread thread = new Thread(() => OnCallerID());
            thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
            thread.Start();
        }

        public void CallerID()
        {
            InteractionService.UserIntraction.DisplayPopup("CID", "CID Test 2", "", "");
        }

        public void OnCallerID()
        {
            this.CallerID();
        }
    }
}

I'm trying to add something to a opensource software package made in C# but I'm having problems with it. 我正在尝试添加一些用C#开发的开源软件包,但我遇到了问题。 The problem with the above (simplified) example is that once InteractionService.UserIntraction.DisplayPopup is called I get an exception "The calling thread cannot access this object because a different thread owns it". 上面(简化)示例的问题是,一旦调用了InteractionService.UserIntraction.DisplayPopup,我就会得到一个异常“调用线程无法访问此对象,因为另一个线程拥有它”。

I am not a C# coder but I have tried many things to solve this like Delegates, BackgroundWorkers, etc. etc. and none have worked for me so far. 我不是C#编码员,但是我已经尝试了很多东西来解决这个问题,比如Delegates,BackgroundWorkers等等。到目前为止,没有人能为我工作。

Can anybody help me with this? 任何人都可以帮我吗?

Consider calling the method on the UI thread through the Dispatcher. 考虑通过Dispatcher在UI线程上调用该方法。 In your case I believe you should pass in the UI dispatcher as a parameter to the constructor of the type you've described and save it in a field. 在您的情况下,我相信您应该将UI调度程序作为参数传递给您所描述类型的构造函数,并将其保存在字段中。 Then, when calling you can do the following: 然后,在呼叫时您可以执行以下操作:

if(this.Dispatcher.CheckAccess())
{
    InteractionService.UserInteration.DisplayPopup(...);
}
else
{
    this.Dispatcher.Invoke(()=>this.CallerID());
}

You can write your own DispatcherHelper to acces the Dispatcher from ViewModels. 您可以编写自己的DispatcherHelper来从ViewModels访问Dispatcher。 I think it is MVVM friendly. 我认为这是MVVM友好的。 We used an implementation in our app like this: 我们在我们的应用程序中使用了这样的实现:

public class DispatcherHelper
    {
        private static Dispatcher dispatcher;

        public static void BeginInvoke(Action action)
        {
            if (dispatcher != null)
            {
                dispatcher.BeginInvoke(action);
                return;
            }
            throw new InvalidOperationException("Dispatcher must be initialized first");
        }

        //App.xaml.cs
        public static void RegisterDispatcher(Dispatcher dispatcher)
        {
            DispatcherHelper.dispatcher = dispatcher;
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM