如何在WPF中使用ISynchronizeInvoke接口?

时间:2018-05-03 18:30:56

标签: c# wpf winforms thread-synchronization

我有这样的组件,无法改变它:

public sealed class UFScannerManager
{
    public UFScannerManager(ISynchronizeInvoke synInvoke);
    public ScannerList Scanners { get; }
    public event UFS_SCANNER_PROC ScannerEvent;

    public UFS_STATUS Init();
    public UFS_STATUS Uninit();
    public UFS_STATUS Update();

    [DefaultMember("Item")]
    public sealed class ScannerList
    {
        public ScannerList(UFScannerManager Owner);

        public UFScanner this[int Index] { get; }
        public UFScanner this[string ScannerID] { get; }
        public UFScanner this[IntPtr ScannerHandle] { get; }

        public int Count { get; }
    }
}

我想创建一个像这样的组件实例:UFScannerManager(this),但在WPF中我不能将pass this作为参数调用。这里this表示当前窗口表单对象,构造函数需要ISynchronizeInvoke sysInvoke参数。因此,在传递this时,可以在Windows窗体应用程序中正确初始化扫描程序。无需担心ISynchronizeInvoke界面。

UFS_STATUS ufs_res;
UFScannerManager ScannerManager;
int nScannerNumber;
ScannerManager = new UFScannerManager(this);
ufs_res = ScannerManager.Init();
nScannerNumber = ScannerManager.Scanners.Count;

但是,此代码在WPF中不起作用。问题是这一行。它不喜欢的是this

ScannerManager = new UFScannerManager(this);

当我尝试构建时,出现错误:

  

参数1:无法从'win_myapp'转换为'System.ComponentModel.ISynchronizeInvoke'

1 个答案:

答案 0 :(得分:1)

WPF不像ISynchronizeInvoke类那样提供System.Windows.Forms.Form实现。所以你需要创建一个。

幸运的是,WPF的Dispatcher类为该实现提供了所有必需的方法。您只需为DispatcherDispatcherOperation创建包装器/适配器。

我可以告诉你如何做到这一点。请注意,此代码不应“按原样”在生产环境中使用,因为它已经简化并且没有异常处理。

class DispatcherSynchronizeInvoke : ISynchronizeInvoke
{
    private readonly Dispatcher dispatcher;

    public DispatcherSynchronizeInvoke(Dispatcher dispatcher)
    {
        this.dispatcher = dispatcher;
    }

    public IAsyncResult BeginInvoke(Delegate method, object[] args)
    {
        // Obtaining a DispatcherOperation instance
        // and wrapping it with our proxy class
        return new DispatcherAsyncResult(
            this.dispatcher.BeginInvoke(method, DispatcherPriority.Normal, args));
    }

    public object EndInvoke(IAsyncResult result)
    {
        DispatcherAsyncResult dispatcherResult = result as DispatcherAsyncResult;
        dispatcherResult.Operation.Wait();
        return dispatcherResult.Operation.Result;
    }

    public object Invoke(Delegate method, object[] args)
    {
        return dispatcher.Invoke(method, DispatcherPriority.Normal, args);
    }

    public bool InvokeRequired => !this.dispatcher.CheckAccess();

    // We also could use the DispatcherOperation.Task directly
    private class DispatcherAsyncResult : IAsyncResult
    {      
        private readonly IAsyncResult result;

        public DispatcherAsyncResult(DispatcherOperation operation)
        {
            this.Operation = operation;
            this.result = operation.Task;
        }

        public DispatcherOperation Operation { get; }

        public bool IsCompleted => this.result.IsCompleted;
        public WaitHandle AsyncWaitHandle => this.result.AsyncWaitHandle;
        public object AsyncState => this.result.AsyncState;
        public bool CompletedSynchronously => this.result.CompletedSynchronously;
    }
}

使用此自定义ISynchronizeInvoke实现,您可以实例化您的类:

// Assuming you're calling this inside of a DispatcherObject, e.g. a Window
new UFScannerManager(new DispatcherSynchronizeInvoke(this.Dispatcher));