Как использовать интерфейс ISynchronizeInvoke в WPF? - PullRequest
0 голосов
/ 03 мая 2018

У меня есть такой компонент, и я не могу его изменить:

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 Form. Не нужно беспокоиться об интерфейсе 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 голосов
/ 04 мая 2018

WPF не обеспечивает реализацию ISynchronizeInvoke, как класс System.Windows.Forms.Form. Так что вам нужно его создать.

К счастью, класс Dispatcher в WPF предоставляет все необходимые средства для этой реализации. Вам просто нужно создать оболочки / адаптеры для Dispatcher и для DispatcherOperation.

Я могу дать вам представление, как это сделать. Обратите внимание, что этот код не следует использовать в производственной среде «как есть», поскольку он упрощен и не обрабатывается исключение.

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));
...