【问题标题】:SynchronizationContext.Post to UI MethodSynchronizationContext.Post 到 UI 方法
【发布时间】:2012-08-19 18:10:02
【问题描述】:

我正在使用 Web 服务,因此我有必要延长会话长度/重新连接并恢复大型数据集等。有时这可能很长,所以我希望它在一个单独的线程中异步更新 UI。

我似乎无法理解如何使用同步上下文来调用我的 UI 线程上的方法。我有它,我已经将我的 UIThread 上下文传递给我的线程,现在我想更新 UI 线程上的一些标签等。我已经阅读了大量的帖子,但似乎都没有解释如何简单地将一些参数传递回一个方法,或者他们可能这样做了,但我太累/太愚蠢了,没有看到它。

//在主 UI 线程上

public void updateConnStatus(string conn_name, bool connected)
{
        switch (conn_name)
        {
            case "Conn" : if (connected == true){ //do something} break;

//在单独的线程上

uiContext.Post( //something to do with delegates in here that eludes me );

如果有人可以简单地解释我如何将 sendOrPostCallBack 链接到原始方法,我将不胜感激。

谢谢

编辑:

我设法让代码运行并尝试触发事件,它可以填充我的自定义 eventArgs,但要么它说 updateUIConnStatus 尚未实例化,需要更多调查:o

public void updateUIThread(string conn, bool connected)
    {
       uiContext.Post(new SendOrPostCallback((o) => { updateConnStatus(this, new MyEventArgs<String, Boolean>(conn, connected)); }), null);
    }

public class MyEventArgs<T, U> : EventArgs
    {
        private T _val1; private U _val2;
        public  MyEventArgs(T value1, U value2) { _val1 = value1; _val2 = value2; }
        public T val1 { get { return _val1;} }
        public U val2 { get {return _val2;} }
    }

public event EventHandler<MyEventArgs<String, Boolean>> updateConnStatus = Delegate {};

//在 UI 线程上

 public void updateConnStatus(object sender, MyEventArgs<String,Boolean> e)
    {
        switch (e.val1)
        {
            case "Conn1" :
                if (e.val2 == true)
                {

【问题讨论】:

    标签: c# .net multithreading


    【解决方案1】:

    您需要一个 SendOrPostCallback 类型的委托。这很尴尬,它只需要一个 object 类型的参数。您绝对应该查看 .NET 4 中可用的 Task 类,以使这更容易。或者使用 lambda,如下所示:

            string conn_name = "foo";
            uiContext.Post(new SendOrPostCallback((o) => {
                updateConnStatus(conn_name, true);
            }), null);
    

    { 大括号 } 之间的代码在 UI 线程上执行。

    【讨论】:

    • 嗨,汉斯,我最初尝试过类似的操作,但我收到“当前上下文中不存在名称 'updateConnStatus'”,因为代码位于线程包装器类中。我刚刚尝试在那里粘贴一个事件处理程序,它似乎已经消除了错误,所以我会对其进行测试并返回! :)
    • 好吧,如果此方法存在于另一个类中,请使用正确的对象引用。或者当然,一个事件。
    • 不,我没正确使用它方法,但我似乎无法正确生成事件处理程序或引用主 UI 方法:/
    • 好吧,迈出一小步。 使用“线程包装器”,只需将其放在与您的 updateConnStatus 方法相同的类中即可。学习 OOP 和忘记 vb.net 需要一段时间。
    • 我设法通过使用泛型创建自定义 EventArgs 类来运行代码。看来只是事件有问题。
    【解决方案2】:

    通常您在 UI 线程上创建类型的实例(例如 ViewModels),因此您可以将 SynchronizationContext 或 TaskScheduler(最好是恕我直言)保存到私有字段,然后在需要时进行比较...

    private readonly SynchronizationContext _syncContext = SynchronizationContext.Current;
    private readonly TaskScheduler _scheduler = TaskScheduler.Current;
    
    void OnSomeEvent(object sender, EventArgs e)
    {
        if (_syncContext != SynchronizationContext.Current)
        {
            // Use Send if you need to get something done as soon as possible.
            // We'll be polite by using Post to wait our turn in the queue.
            _syncContext.Post(o => DoSomething(), null);
            return;
        }
        // Call directly if we are already on the UI thread
        DoSomething();
    }
    
    void OnSomeOtherEvent(object sender, MyEventArgs e)
    {
        var arg1 = e.Arg1; // "Hello "
        var arg2 = e.Arg2; // {"World", "!"};
    
        // Process args in the background, and then show the result to the user...
        // NOTE: We don't even need to check the context because we are passing
        // the appropriate scheduler to the continuation that shows a MessageBox.
    
        Task<string>.Factory.StartNew(() => ReturnSomething(arg1, arg2))
            .ContinueWith(t => MessageBox.Show(t.Result), _scheduler);
    }
    
    void DoSomething() { MessageBox.Show("Hello World!"); }
    
    string ReturnSomething(string s, IEnumerable<string> list)
    {
        return s + list.Aggregate((c, n) => c + n);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-03
      相关资源
      最近更新 更多