3

我目前正在构建一个 C# 应用程序,当用户连接到特定的无线网络时,它将自动针对某些网络资源对用户进行身份验证。

目前,我正在使用托管 Wifi API来发现用户何时连接/断开无线网络。我有一个事件处理程序,因此当发生任何这些活动时,会调用我的一个方法来检查无线连接的当前状态。

为了管理应用程序的状态,我有另一个称为“导体”的类,它执行更改应用程序状态所需的操作。例如,当无线网卡连接到正确的网络时,指挥需要将系统状态从“监控”更改为“验证”。如果身份验证成功,指挥者需要将状态更改为“已连接”。断开连接会再次导致“监控”状态,而身份验证错误会导致“错误”状态。这些状态更改(如果用户请求)可能会导致 TrayIcon 通知,因此用户知道他们正在通过身份验证。

我目前的想法涉及让用于检查无线当前状态的方法调用状态管理器中的“身份验证”或“断开连接”方法。但是,我不确定这是否是事件处理程序的适当使用——它是否应该设置一个标志或通过某种形式的 IPC 将消息发送到一个单独的线程,该线程将开始身份验证/断开连接过程?

除了能够请求连接/断开连接的事件处理程序之外,用户还可以通过托盘图标执行它。因此,我需要确保这些后台操作不会阻止托盘与用户的交互。

只有一个组件应该能够随时请求更改系统状态,所以我需要使用互斥锁来防止并发状态更改。然而,我应该如何同步这些组件的其余部分对我来说有点神秘。

我应该阅读的任何建议或文献都会受到欢迎。我没有接受过 C# 语言的正式培训,因此如果我有任何错误陈述,我深表歉意。

编辑:最重要的是,我想验证一个事件将作为一个单独的线程执行,因此它不能阻塞主 UI。另外,我想验证如果我有一个事件处理程序订阅了一个事件,它会串行处理事件,而不是并行处理(所以如果用户在处理第一个连接事件之前连接和断开连接,则不会发生两次状态更改同时发生)。

4

5 回答 5

1

作为一种选择,替代...

如果我是你,而且你还是要重新开始,我会认真考虑
Rx Reactive Extensions

它对事件和基于事件的编程提供了全新的视角,并且对您正在处理的事情有很大帮助(包括同步、处理线程、组合事件、停止、启动等)。

一开始学习可能有点“陡峭的曲线”,但同样,这可能是值得的。

希望这可以帮助,

于 2012-04-06T21:42:11.060 回答
1

我应该阅读的任何建议或文献都会受到欢迎。我没有接受过 C# 语言的正式培训,因此如果我有任何错误陈述,我深表歉意。

这解释了一些事情。:)
我会阅读线程、事件处理和系统托盘图标/界面的创建。

重要的是要注意以下几点:

  • 事件在调用它们的同一线程上处理。如果您希望事件处理不锁定 GUI,那么您需要让按钮将工作移动到不同的线程。
  • 当一个事件被触发时,它会将适当的参数传递给其列表中的所有方法。这与调用一个方法然后调用所有其他方法几乎相同(参见 EventFired 示例)。事件的目的不是调用我们已经可以做到的方法,而是调用编译代码时可能不知道的方法(当控件所在的库时,按钮控件上的单击事件将不知道)例如编译)。简而言之,如果您可以调用该方法而不是使用事件,则可以这样做。

    void EventFired(int arg1, object arg2)
    {
        subscribedMethod1(arg1, arg2);
        SubscribedMethod2(arg1, arg2);
        SubscribedMethod3(arg1, arg2);
        SubscribedMethod4(arg1, arg2);
        SubscribedMethod5(arg1, arg2);
        SubscribedMethod6(arg1, arg2);
        SubscribedMethod7(arg1, arg2);
    }
    
  • 如果您想阻止用户界面锁定,请在另一个线程上进行工作。但请记住,用户界面元素(表单、按钮、网格、标签等)只能从它们的主机线程访问。使用 control.Invoke 方法调用其线程上的方法。

  • 从界面中删除一个选项并不是防止赛道状况的好方法(用户在一个已经运行的情况下开始连接/断开连接),因为用户界面将在不同的线程上并且可能不同步(这需要时间单独的线程同步)。虽然有很多方法可以解决这个问题,但对于线程新手来说,最简单的方法是对值使用锁定。这样,.NET 将确保一次只有一个线程可以更改设置。您仍然需要更新用户界面,以便用户知道正在发生更新。

您的总体设计听起来不错。您可以使用 2-3 个线程(1 个用于用户界面(托盘图标),1 个用于检查新的网络连接,1 个(可以与连接检查合并)用于检查 Internet 连接。

希望这会有所帮助,如果您需要更多信息(或接受答案),请告诉我们。

于 2012-04-06T21:12:30.017 回答
0

对我来说,您似乎将过度设计该项目。您基本上需要Commander在主应用程序中实现一个事件并订阅它们。那是。

如果总是有一个组件可以进行更改并且您可以拥有多个组件,那么使用某种同步机制(如Mutex您所指出的)是完全有效的选择。

希望这可以帮助。

于 2012-04-06T20:45:05.193 回答
0

如果您希望在任何时候最多有一个状态更改挂起,最好让您正在侦听的外部事件的事件处理程序在执行期间保持锁定。这确保了一种简单的编程方式,因为您可以保证您的应用程序的状态不会在您下面改变。在这种特殊情况下,不需要单独的线程。

您需要区分应用程序的当前状态和目标状态。用户指示目标状态(“已连接”、“已断开”)。实际状态可能不同。示例:用户想要断开连接,但实际状态是正在验证。身份验证步骤完成后,状态机必须检查目标状态:

targetState == connected => set current state to connected
targetState == disconnected => begin to disconnect and set state to disconnecting

分离实际状态和目标状态允许用户随时改变主意,并且状态机可以引导至所需状态。

于 2012-04-06T20:45:32.537 回答
0

如果不查看应用程序的整个(建议的)结构,很难给出准确的答案。但总的来说,是的,对这类事情使用事件处理程序是可以的——尽管我可能会将实际实现移到单独的方法中,以便您可以更轻松地从其他位置触发它。

关于禁用“连接”按钮的评论对我来说听起来很正确,尽管可以想象你可能还需要其他形式的同步。但是,如果您的应用程序不需要多线程,我会避免仅仅为了它而引入多线程。如果您这样做,请查看已包含在Task Parallel Library中的新 Task API 。他们很好地抽象了很多东西。

关于不要过度思考这个问题的评论也很受欢迎。如果我站在你的立场上,只是从一门新语言开始,我会避免一开始就试图让架构恰到好处。深入研究并使用您已有的认知工具集进行开发。当你探索更多时,你会发现,“哦,废话,这是一个更好的方法。” 然后去那样做。重构是你的朋友。

于 2012-04-06T20:46:35.080 回答