Dispatcher.CheckAccess()无法在我的控制台应用程序中运行,是否有更好的方法

时间:2010-04-21 14:09:12

标签: .net wpf multithreading serial-port console-application

我在WPF / VB中编写了一个应用程序,并将业务逻辑和UI分成不同的项目。

业务层使用在不同线程上运行的串行端口。既然我正在尝试为同一业务层编写命令行接口,那么在调用.Invoke()时它似乎失败了。 (没有错误,只是不起作用)

我很确定我必须在checkaccess和.invoke中添加的原因是因为我在处理串口数据期间会更改集合并希望通过WPF数据绑定处理NotifyCollectionChanged。 (我不是百分之百确定的原因是因为它是几个月前我写的那部分,它在GUI中运行得很好,现在添加控制台应用程序让我重新考虑其中一些)

我希望我的业务层在创建它们的线程上运行这些进程,我需要从我的GUI版本和命令行版本开始工作。

我是否在业务层中滥用Dispatcher?有没有更好的方法从串口处理事件,然后返回主线程来处理数据?

更新

Private Delegate Sub NewDataRecieved(ByVal byteBuffer() As Byte)
Private Sub DataReceived(ByVal byteBuffer() As Byte) Handles _serial.DataRecieved
    If _dispatcher.CheckAccess() Then
        ProcessTheData
    Else
        Dim dataReceivedDelegate As NewDataRecieved
        dataReceivedDelegate = New NewDataRecieved(AddressOf DataReceived)
        _dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, dataReceivedDelegate, byteBuffer)
    End If
End Sub

3 个答案:

答案 0 :(得分:2)

Invoke不执行任何操作,因为您没有运行调度程序,要从调度程序获取任何服务,您必须调用Dispatcher.Run(http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.run.aspx

现在,您的问题是调用Dispatcher.Run将使WPF控制该线程 - 这可能不是您想要在控制台应用程序中执行的操作。

我认为在您的情况下,最好的选择是从业务层删除线程同步代码(与调度程序通信的任何内容),并将其移除到包装器对象中。

WPF应用程序可以像以前一样使用包装器对象继续工作,控制台应用程序可以直接使用“原始”业务层。

更新:下面是一个包装器的示例,您必须为执行线程工作并调用原始对象的原始类的每个公共成员创建一个方法/属性。

public class BOWrapper : INotifyPropertyChanged
{
    private BO _bo;
    private Dispather _dispather;

    public BOWrapper(BO bo, Dispatcher dispather)
    {
        _bo = bo;
        _dispather = dispather;
        _bo.PropertyChanged += BOPropertyChanged;
    }

    public string SomeValue
    {
        get { return _bo.SomeValue; }
    }

    private void BOPropertyChanged(object sender, PropertyChangedEventArgs ea)
    {
        _dispatcher.Invoke(
            new Action<PropertyChangedEventArgs>(
                e=>
                {
                    var handler = PropertyChanged;
                    if(handler!=null) handler(this,e);
                }),ea);
    }
}

包装器类是100%样板代码,您可能可以使用一些代码生成器来创建它,甚至可以使用类似DynamicProxy(http://www.castleproject.org/dynamicproxy/index.html)的东西在运行时自动生成它。

答案 1 :(得分:0)

控制台应用程序中的WPF?在控制台应用程序中,对特定线程中的运行功能没有限制。您可以在调用者线程上下文中处理任何事件,并在必要时提供同步。

答案 2 :(得分:0)

替代方法:在您需要Dispatcher的线程中,使用Dispatcher.CurrentDispatcher静态属性。如果尚未为该线程创建调度程序,则会自动创建该调度程序(如果可能)。您可以将此值存储在某处以允许其他线程使用调度程序。

在代码中:

public class BusinessLayerThread
{
    public BusinessLayerThread()
    {
        Dispatcher = Dispatcher.CurrentDispatcher;
    }

    public static Dispatcher Dispatcher { get; private set; }
}