如何使用C#的方法 Dispatcher.Invoke =>

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用C#的方法 Dispatcher.Invoke =>相关的知识,希望对你有一定的参考价值。

参考技术A

Dispatcher.Invok是WPF中特有的。使用方法如下

1)创建一个“WPF 引用程序”

2)在Window1.xaml中添加一个Label

3)在后台代码Window1.xaml.cs中

using System;
using System.Windows;
using System.Threading;

namespace WpfApplication3

    /// <summary>
    /// Window1.xaml 的交互逻辑
    /// </summary>
    public partial class Window1 : Window
    
        public Window1()
        
            InitializeComponent();
            
            // 启动一个后台线程
            Thread t = new Thread(WorkThread);
            t.IsBackground = true;
            t.Start();
        
        
        // 后台线程
        void WorkThread()
        
            while (true)
            
                // 利用Dispacther.Invoke调用更新labelClock显示的内容
                // 按WPF规定:labelClock是由主线程创建的。要想在后台线程
                // 中刷新主线程创建的控件,必须通过Dispatcher.Invoke(...)
                // 来实现!
                this.Dispatcher.Invoke(
                    new Action(() => labelClock.Content 
                        = DateTime.Now.ToString("HH:mm:ss")), 
                    System.Windows.Threading.DispatcherPriority.Render);
                
                // 后台线程停顿1秒    
                Thread.Sleep(1000);
            
        
    

4)运行结果

本回答被提问者和网友采纳

如何使用 SWIG 从 C 调用 C# 方法?

【中文标题】如何使用 SWIG 从 C 调用 C# 方法?【英文标题】:How to call a C# method from C using SWIG? 【发布时间】:2021-12-25 09:46:32 【问题描述】:

我一直在寻找一些解释/代码 sn-ps 来说明如何使用 SWIG 从 C 调用 C# 方法。我能找到的最好的是:Callback from C++ to C# using SWIG。唉,这是针对 C++ 而不是 C。除了 C,我们如何实现相同的功能?

【问题讨论】:

【参考方案1】:

您仍然可以使用 SWIG 来提供帮助(一点),但从根本上说,如果您使用的是 C 编译器,则无法启用 SWIG 导向器,您链接到的示例依赖于该导向器:

test.i:1: Error: Directors are not supported for C code and require the -c++ option

因此,您必须在 C 中重建该功能的某些部分才能做到这一点。我构建了一个启用 C++ 的 director/callbacks 设置示例,并以此为基础来构建我对 C# 机制的理解。让我们从我们要运行的测试开始,从后面开始:

public class TestImpl : CallbackInterface 
    public override void callback() 
        System.Console.WriteLine("handling event...");
    

    public static void Main() 
        CallbackInterface cb = new TestImpl();
        test.test_runner(cb);   
    

我们想要定义一个抽象类CallbackInterface,我们可以传递实例并让我们的 C 代码调用 C# callback 实现。

这是我的 .i SWIG 接口文件:

%module test
%
#include <assert.h>
%

%typemap(csclassmodifiers) struct CallbackInterface "public abstract class";
%typemap(cscode) struct CallbackInterface %
  public delegate void callback0(); // [2]

  public CallbackInterface() : this(null)  // [3]
    connect();
  

  private void connect() 
    setCallback(new callback0(callback));
  

  public abstract void callback();
%

// [4]
%typemap(cstype) cb0 "CallbackInterface.callback0";
%typemap(imtype) cb0 "CallbackInterface.callback0";
%typemap(csin) cb0 "$csinput";
%ignore CallbackInterface::cb;

%extend struct CallbackInterface 
  CallbackInterface(cb0 cb)  // [3]
    struct CallbackInterface *ret = malloc(sizeof *ret);
    ret->cb = cb;
    return ret;
  

  void setCallback(cb0 cb) 
    $self->cb = cb;
  


%inline %
  typedef void (*cb0)();

  struct CallbackInterface 
    cb0 cb; // [1]
  ;

  static void test_runner(struct CallbackInterface *interface) 
    assert(interface->cb);
    fprintf(stderr, "Doing test, pointer=%p, cb=%p\n", interface, interface->cb);
    interface->cb();
  
%

通过调查 C# 中的正常导向器实现,似乎 C++ 层正在通过 pinvoke 接口处理函数指针。所以我们在接口 1 处定义了一个结构体,它有一个成员,一个函数指针。

为了从我们的 C# 代码中实际获取函数指针,我们需要使用委托,我们在 2 处为此进行了设置,这是将成为 CallbackInterface 类的一部分的 C# 代码。

在 SWIG 中,我们已经“扩展”了(但仍然只是使用 C)我们的结构来提供一个构造函数,该构造函数在 3 处接受一个委托作为参数。这有点奇怪,因为我们只传递了 null在这里,但是稍后它可以作为我们默认构造函数的方便重载,并确保我们在创建实例时也至少初始化结构的 cb 成员,并在 3 处调用委托构造函数。(旁白:我最初试图在这里创建委托,但这是一个静态上下文,所以你现在不能这样做)。然后在默认构造函数的主体中,我们调用私有 connect 方法,该方法设置一个委托并使用我们的 %extend setCallback 方法实际修改结构。

如果您愿意,您也可以提供 setCallback 的重载,以便可以将 C 函数指针设置为处理程序,但这是一个额外的额外内容,特别是考虑到 C 限制意味着您不能在全部。在 4 处添加了一些额外的类型映射,以确保将委托作为函数指针传递给 C,因此下面的 Makefile 可以为我们运行和测试:

.PHONY: run

all: run

test_wrap.c: test.i
    swig -csharp -Wall -debug-tmsearch test.i

test.cs: test_wrap.c
CallbackInterface.cs: test_wrap.c
testPINVOKE.cs: test_wrap.c

test.exe: test.cs runme.cs CallbackInterface.cs testPINVOKE.cs
    mcs $^

libtest.so: test_wrap.c
    gcc -shared -Wall -Wextra $^ -o $@ -fPIC

run: test.exe libtest.so
    LD_LIBRARY_PATH=. ./test.exe

在 Ubuntu 上使用 Mono 至少可以按预期工作。

【讨论】:

以上是关于如何使用C#的方法 Dispatcher.Invoke =>的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SWIG 从 C 调用 C# 方法?

如何使用 javascript 调用 ASP.NET c# 方法

如何在 C# 中创建异步方法?

如何在 C# 中将 lambda 与方法一起使用?

如何使用 c# 扩展方法扩展类? [复制]

如何在 C# 中使用反射调用具有不同类型参数的方法