WPF中如何使用ISynchronizeInvoke接口?
How to use the ISynchronizeInvoke interface in WPF?
我有这样的组件,无法更改它:
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
表示当前window表单对象,构造函数需要一个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);
当我尝试构建时,出现错误:
Argument 1: cannot convert from 'win_myapp' to 'System.ComponentModel.ISynchronizeInvoke'
WPF 不像 System.Windows.Forms.Form
class 那样提供 ISynchronizeInvoke
实现。所以你需要创建一个。
幸运的是,WPF 的 Dispatcher
class 提供了该实现所需的所有方法。您只需为 Dispatcher
和 DispatcherOperation
.
创建 wrappers/adapters
我可以告诉你如何做到这一点。请注意,此代码不应在生产环境中使用 'as is',因为它已简化且缺少异常处理。
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
实现,您可以实例化您的 classes:
// Assuming you're calling this inside of a DispatcherObject, e.g. a Window
new UFScannerManager(new DispatcherSynchronizeInvoke(this.Dispatcher));
以@dymanoid 的示例为基础。最好把它做成扩展方法。
public static class WPFExtensions
{
public static System.ComponentModel.ISynchronizeInvoke ISynchronizeInvoke
(this System.Windows.Threading.DispatcherObject dispatcher)
{
return new DispatcherSynchronizeInvoke(dispatcher.Dispatcher);
}
}
class DispatcherSynchronizeInvoke : System.ComponentModel.ISynchronizeInvoke
{
// see dymanoid's answer, you do need one additional line in the internal
// private class DispatcherAsyncResult : IAsyncResult
// this >>
// WaitHandle IAsyncResult.AsyncWaitHandle => this.result.AsyncWaitHandle;
}
这与计时器 class 配合使用效果很好,这样您就不必编组 elasped 事件。从 window 你可以做:
var timer = new Timer(TimeSpan.FromSeconds(10).TotalMilliseconds)
{
SynchronizingObject = this.ISynchronizeInvoke()
};
timer.Elapsed += timer_Elapsed;
然后计时器的已用事件在 window 的线程上。
我有这样的组件,无法更改它:
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
表示当前window表单对象,构造函数需要一个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);
当我尝试构建时,出现错误:
Argument 1: cannot convert from 'win_myapp' to 'System.ComponentModel.ISynchronizeInvoke'
WPF 不像 System.Windows.Forms.Form
class 那样提供 ISynchronizeInvoke
实现。所以你需要创建一个。
幸运的是,WPF 的 Dispatcher
class 提供了该实现所需的所有方法。您只需为 Dispatcher
和 DispatcherOperation
.
我可以告诉你如何做到这一点。请注意,此代码不应在生产环境中使用 'as is',因为它已简化且缺少异常处理。
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
实现,您可以实例化您的 classes:
// Assuming you're calling this inside of a DispatcherObject, e.g. a Window
new UFScannerManager(new DispatcherSynchronizeInvoke(this.Dispatcher));
以@dymanoid 的示例为基础。最好把它做成扩展方法。
public static class WPFExtensions
{
public static System.ComponentModel.ISynchronizeInvoke ISynchronizeInvoke
(this System.Windows.Threading.DispatcherObject dispatcher)
{
return new DispatcherSynchronizeInvoke(dispatcher.Dispatcher);
}
}
class DispatcherSynchronizeInvoke : System.ComponentModel.ISynchronizeInvoke
{
// see dymanoid's answer, you do need one additional line in the internal
// private class DispatcherAsyncResult : IAsyncResult
// this >>
// WaitHandle IAsyncResult.AsyncWaitHandle => this.result.AsyncWaitHandle;
}
这与计时器 class 配合使用效果很好,这样您就不必编组 elasped 事件。从 window 你可以做:
var timer = new Timer(TimeSpan.FromSeconds(10).TotalMilliseconds)
{
SynchronizingObject = this.ISynchronizeInvoke()
};
timer.Elapsed += timer_Elapsed;
然后计时器的已用事件在 window 的线程上。