【问题标题】:Code starts only when Application.Run() is invoked WPF application代码仅在调用 Application.Run() 时启动 WPF 应用程序
【发布时间】:2014-01-13 15:55:16
【问题描述】:

我有一个在class A 中调用的方法,它在class B 中定义:

class B{
      [STAThread]
        public static void ScanForAxisCameras() {
                DNSSDService service = new DNSSDService();
                DNSSDEventManager eventManager = new DNSSDEventManager();
                eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(eventManager_ServiceFound);
                DNSSDService browse = service.Browse(0, 0, "_axis-video._tcp", null, eventManager);
                Application.Run();//if not invoked everything above does not start
            }
}

class A{ ...before invoking..... B.ScanForAxisCameras(); ....after invoking....}

class B 中的代码“开始”/仅在我调用 Application.Run() 时才有效。 但这会导致class A ....after invoking.... 方法中的所有代码都不起作用。如何处理它,使其不会冻结应用程序?

编辑:class Aclass MainWindow.xaml.cs。它是 WPF 应用程序。

public partial class MainWindow : Window {

        public MainWindow() {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e) {
            createGUI();
        }

        private void createGUI() {

            LocalNetworkScanner.ScanForAxisCameras();//when there is no Application.Run()  ScanForAxisCameras() does not work.
}
}

【问题讨论】:

  • 这是一个 winform 应用程序,一个 Web 应用程序,还是什么?此时您是否已经启动了消息循环?您稍后会开始消息循环吗?
  • 如果你不打电话给Run,那么消息循环就不会开始,所以是的,在你打电话之前你不会收到任何通知是有道理的。
  • @BartoszKP “没有事件循环,事件就无法工作。”这根本不是真的。大多数事件永远不会使用消息循环。只有当代码试图编组到 UI 线程(甚至不需要来自事件)时,这才是一个问题。
  • @Servy 是的,你是对的。很抱歉造成混乱。
  • 您绝对不应该在 WPF 应用程序中调用 Application.Run。您正在使用的第 3 方组件中存在错误,它被设计为仅用于 WinForms,而不是 WPF,或者您没有以某种方式正确使用它。

标签: c# wpf multithreading


【解决方案1】:

调用ScanForAxisCameras() 的 WPF UI 线程已经有一个消息循环。我认为您的代码的问题在于您在ScanForAxisCameras 中创建的所有对象 具有本地范围

public static void ScanForAxisCameras() {
        DNSSDService service = new DNSSDService();
        DNSSDEventManager eventManager = new DNSSDEventManager();
        eventManager.ServiceFound += new _IDNSSDEvents_ServiceFoundEventHandler(eventManager_ServiceFound);
        DNSSDService browse = service.Browse(0, 0, "_axis-video._tcp", null, eventManager);
        Application.Run();//if not invoked everything above does not start
}

没有Application.Run(),您的对象(serviceeventManagerbrowse)可能会在ScanForAxisCameras 完成后立即被销毁并最终确定。因此,您正在寻找的事件(例如 ServiceFound)可能甚至没有机会被解雇。

如果您调用Application.Run(),则ScanForAxisCameras 不会退出(至少直到Application.Run() 本身退出)。这使您的对象保持活力和功能。

尝试重构代码以将这些对象的引用保留在类的成员字段中(或静态变量,FWIW)。我相信这应该可以解决问题。

[EDITED] 附带说明,[STAThread] 属性在该上下文中没有意义(除非您使用 ScanForAxisCameras 作为新线程的入口点 - 显然,这是这里不是这样)。

【讨论】:

  • 原来如此!有没有地方可以让我更多地了解这种行为?在论文中解释它?
  • @Yoda,很高兴它有帮助。只需在网上搜索“C# 对象生命周期”之类的内容。例如:msdn.microsoft.com/en-us/magazine/cc163316.aspx
【解决方案2】:

您可以在App.xaml.cs 文件中的App 中引入新的Run() 方法。 在这里,您可以在应用程序本身初始化之前执行自定义操作。 更多信息here

public partial class App : Application
{
    public new void Run()
    {
        // Do your stuff here
        B.DoStuff();

        // Call the base method
        base.Run();
    }
}

【讨论】:

    【解决方案3】:

    Application.Run 为该特定线程启动消息循环,如果没有消息循环,则不会通知您的对象知道他们必须做某事。

    只有当我调用 Application.Run() 时,B 类中的代码才会“启动”/工作。 但这会导致类A中的所有代码......在调用......方法后不起作用

    Run 是一个阻塞调用,因此该调用之后的任何代码都无法访问,直到应用程序关闭,即当您退出消息循环时。

    如何处理它才不会冻结应用程序?

    简而言之,你不能。 Run 将始终阻塞,因此您需要在应用程序启动过程中运行的任何代码都必须在调用之前发生。


    在您编辑后提到这是一个 WPF 应用程序,那么 Application.Run 作为 static 方法不是正确的方法。如果您需要在应用程序启动时运行初始化,那么您可以执行已经建议的操作并覆盖 Application 类的 Run 方法,或者(可能更合适)您可以挂钩到 OnStartup 事件,例如

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            // code before startup
            base.OnStartup(e);
            // code after startup
        }
    }
    

    【讨论】:

    • 请看编辑。
    【解决方案4】:

    在这种情况下,您似乎需要将 Application.Run() 添加到不同的类中。 Run() 什么都不接受,ApplicationContext,Form。这控制了应用程序的生命周期,并且应该在类 A 之前调用,除非类 A 是入口点。

    详情请见http://msdn.microsoft.com/en-us/library/ms157900.aspx

    【讨论】:

    • 请看编辑。
    【解决方案5】:

    Windows 窗体应用程序在调用 Main 方法时启动。您可以在 Main 函数上实现初始化过程。但是,要完全初始化 Windows 窗体应用程序 并启动它路由 Windows 窗体事件,您需要调用 Application.Run。

    您可以阅读有关应用程序here

    【讨论】:

    • 请看编辑。我应该说它是 WPF 应用程序。
    • 我认为没有区别:)
    • @PouyaSamie 嗯,它产生了巨大的不同。 Application.Run 是 Winform 构造,而不是 WPF 构造,不应在 WPF 应用程序中使用。
    • @servy 这是一堆废话,WPF 有它自己的Application.Run
    • @James 这不是静态方法;这是一个实例方法。 OP 从静态上下文中调用它,所以他显然在调用 Winform 组件。而且通过他的代码也很清楚,他在调用App.Run时已经有一个消息循环,因为他已经显示了一个窗口。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多