如何在 WPF 应用程序上执行异步启动?

2024-06-18

我在异步等待方面相当落后,所以这可能是一个“duh”问题。

我正在开发一个非常小的 UI 应用程序,它使用以下命令从系统托盘运行WPF 通知图标 http://www.codeproject.com/Articles/36468/WPF-NotifyIcon#context_menus图书馆。

应用程序应该以以下方式非常简单地运行(对于用户而言):

  • 节目开始
  • 如有必要,会有一个启动屏幕告诉用户程序正在运行并提示他们登录(如果他们在之前的迭代中尚未登录)。
  • WPF NotifyIcon 将出现在系统托盘中。
  • 异步执行开始

我遇到的问题是“异步执行开始”部分。在此之前发生的所有事情都工作正常,但是当程序开始尝试“运行”时,UI 会锁定(我的意思是,用户可以像疯子一样单击托盘图标,并且上下文菜单拒绝出现)。

这种锁定发生的时间长得令人无法接受。

这是启动代码:

private async void AppStartup( object sender, StartupEventArgs e ) {
    this.TRSIcon = this.FindResource( "TRSIcon" ) as TaskbarIcon;
    if ( Settings.Default.DoUpgrade ) { //Upgrade if necessary.
        Settings.Default.Upgrade( );
        Settings.Default.DoUpgrade = false;
        Settings.Default.Save( );
    }

    if ( string.IsNullOrEmpty( Settings.Default.Username ) || string.IsNullOrEmpty( Settings.Default.Password ) ) {
        new Help( ).ShowDialog( );
        Tuple<string, string> UP;
        if ( ( UP = Login.Instance.GetUserPassword( ) ) != null ) {
            Settings.Default.Username = UP.Item1;
            Settings.Default.Password = UP.Item2;
            Settings.Default.Save( );
        } else
            return;
    }
    await this.Start( ); //<-----This is where the meat of the program runs and it hangs the UI until it finishes.
    return; //<-----This is just so that I have a break point to see that await this.Start is blocking (I have to do it like that right? or do I?)
}

这是Resources.xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Tools="clr-namespace:WPFTools.TaskbarNotification;assembly=WPFTools"
    xmlns:TR="clr-namespace:TriviaRetriever">
    <ContextMenu x:Key="TSRInterfaceMenu" x:Shared="false">
        <MenuItem Header="Login" Command="{Binding cmdLogin}"/>
        <MenuItem Header="Get My Trivia" Command="{Binding cmdDownload}"/>
        <MenuItem Header="Register" Command="{Binding cmdRegister}"/>
        <MenuItem Header="Lost Password" Command="{Binding cmdLostPassword}"/>
        <MenuItem Header="About" Command="{Binding cmdAbout}"/>
        <MenuItem Header="Log Out" Command="{Binding cmdLogout}"/>
        <MenuItem Header="Exit" Command="{Binding cmdExit}"/>
    </ContextMenu>

    <Tools:TaskbarIcon
        x:Key="TRSIcon"
        MenuActivation="LeftOrDoubleClick"
        IconSource="/TRIcon.ico"
        DoubleClickCommand="{Binding cmdAbout}"
        ContextMenu="{StaticResource TSRInterfaceMenu}">
        <Tools:TaskbarIcon.DataContext>
            <TR:TRSIViewModel/>
        </Tools:TaskbarIcon.DataContext>
    </Tools:TaskbarIcon>
</ResourceDictionary>

这是上下文菜单命令的 MVVM:

public class TRSIViewModel {
    public ICommand cmdLogin {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => ( Application.Current as App ).Core == null,
                actCommand = async ( ) => {
                    Tuple<string, string> LoginPassword = Login.Instance.GetUserPassword( );
                    if ( LoginPassword != null ) {
                        Settings.Default.Username = LoginPassword.Item1;
                        Settings.Default.Password = LoginPassword.Item2;
                        Settings.Default.Save( );
                        await ( Application.Current as App ).Start( );
                    }
                }
            };
        }
    }

    public ICommand cmdLogout {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => ( Application.Current as App ).Core != null,
                actCommand = ( ) => {
                    ( Application.Current as App ).Core.Terminate( );
                    ( Application.Current as App ).Core = null;
                }
            };
        }
    }

    public ICommand cmdRegister {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => true,
                actCommand = ( ) => Process.Start( @"https://www.digigames.com/weekly_subscriptions/index.php" )
            };
        }
    }

    public ICommand cmdLostPassword {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => true,
                actCommand = ( ) => Process.Start( @"https://www.digigames.com/weekly_subscriptions/lost_password.php" )
            };
        }
    }

    public ICommand cmdAbout {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => true,
                actCommand = ( ) => ( Application.Current as App ).TRSIcon.ShowCustomBalloon( new About( ), PopupAnimation.Slide, 5000 )
            };
        }
    }

    public ICommand cmdExit {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => true,
                actCommand = ( ) => {
                    if ( ( Application.Current as App ).Core != null )
                        ( Application.Current as App ).Core.Terminate( );
                    Application.Current.Shutdown( 0 );
                }
            };
        }
    }

    public ICommand cmdDownload {
        get {
            return new DelegateCommand {
                fncCanExecute = ( ) => ( Application.Current as App ).Core != null,
                actCommand = async ( ) => await ( Application.Current as App ).Core.DownloadTrivia( true )
            };
        }
    }

    public class DelegateCommand : ICommand {

        public Action actCommand { get; set; }
        public Func<bool> fncCanExecute { get; set; }

        public bool CanExecute( object parameter ) {
            return this.fncCanExecute != null && this.fncCanExecute( );
        }

        public event EventHandler CanExecuteChanged {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute( object parameter ) { this.actCommand( ); }
    }
}

我在这里做错了什么?


我认为你的问题完全是关于你的Start method.

但首先要说的是。您的断点没有执行您期望的操作。一旦它打破Start方法实际上已完成,并且执行剩余的函数,而不是在 UI 线程再次释放后执行。您必须了解,一旦执行离开 UI 同步,UI 线程就可以再次自由运行。Start功能。

要了解该方法实际释放执行需要多长时间,一个好方法是等待它返回Task object.

var pendingTask = this.Start();
Debugger.Break();
await pendingTask;

The Task对象返回一次Start方法命中内部异步执行的函数。这await一旦返回pendingTask实际上完成了。

就你而言,我认为时间会相似,因为Start方法没有向后台发送足够的工作。

有几种方法可以解决这个问题。如果你的Start方法不与 UI 交互,你没问题。您只需将整个方法发送到后台即可完成。这工作起来很简单:

await Task.Run(() => this.Start());

这会将任务发送到 ThreadPool 的线程中,并立即再次释放 UI。这Task.Run方法有一个重载,会自动解开内部Task返回的Start method.

如果您的方法与 UI 交互,则必须在内部更改该方法。查找方法内需要很长时间并且不与 UI 交互的部分,并将它们包装到Task.Run方法如上图。

Every await将建立SynchronizationContext之前又出现过。所以每await在能够更改 UI 的线程中将确保延续也在同一个线程中执行。

所以像这样的事情工作没有问题:

someLabel.Label = "Working…";
await Task.Run(() => DoManyThings());
someLabel.Label = "Done! :D"

我希望这有帮助。如果不知道你的情况,我无法给你更多提示Start方法确实如此。但我希望这个答案能让你走上正轨。

我通常的免责声明:我通常使用 VB.net,因此我的 C# 代码可能在语法方面存在缺陷。如果您发现任何错误,请随时编辑它或告诉我出了什么问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 WPF 应用程序上执行异步启动? 的相关文章

  • 插入多重集中:在该值第一次出现之前而不是最后一次出现之后

    正如标题所示 multiset 在所有相同值的范围末尾插入一个值 例如 在多重集中插入 21 2 2 3做到了1 2 2 new 2 3 如何在所有相同值的范围开头插入新值 例如 在多重集中插入 21 2 2 3应该使1 new 2 2 2
  • Cocoa 常量名称中的“k”代表什么[重复]

    这个问题在这里已经有答案了 可能的重复 Apple 的 API 中的 k 前缀表示什么 https stackoverflow com questions 675816 what does the k prefix indicate in
  • 如何获取网络服务的状态

    如何使用 C 获取 Web 服务的状态 无论是成功完成 失败还是待处理 private void button1 Click object sender EventArgs e var url servicsURL try var myRe
  • 具有自动返回类型推导的 Friend 函数模板无法访问私有成员

    抱歉这个问题的标题太复杂了 我试图描述我为这个问题构建的最小 SSCCE 我有以下代码 include
  • C++ 构造函数根据参数类型调用另一个构造函数

    我有这门课 class XXX public XXX struct yyy XXX std string private struct xxx data 第一个构造函数 使用结构 很容易实现 第二 我可以将一个字符串以特定的格式分开 解析
  • Motif 库的水平绘制的 RowColumn 类 (C)?

    我正在使用 Motif Library 来完成我的工作 如果有人不熟悉这个库 您可以在这里找到文件列表https packages ubuntu com xenial amd64 libmotif dev filelist https pa
  • C#:如何计算纵横比

    我对编程比较陌生 我需要根据给定尺寸 例如 axb 计算纵横比 16 9 或 4 3 我如何使用 C 来实现这一点 任何帮助将不胜感激 public string AspectRatio int x int y code am lookin
  • 除非我在开​​始时声明变量,否则为什么会收到“错误未声明的标识符”?

    当我有以下情况时 include stdafx h include
  • “双免”是什么意思?

    正如标题所暗示的那样 我是 C 语言的新手 并且很快就会有期中考试 我目前正在修改过去的论文 一个反复出现的主题是双重自由问题 我理解就是调用的过程free 在同一个内存位置两次 但我有几个问题我不能 100 确定如何回答 问题1 C中双重
  • llvm clang 编译器上的dynamic_cast失败

    我看到一个奇怪的失败dynamic cast正在返回NULL在 clang 编译器上 但相同的代码可以在 gcc 环境下运行 您能否指出根本原因是什么 之间可能有什么区别dynamic cast关于 llvm 和 gcc 我正在使用两个编译
  • 如何在运行时统一捕捉两个对象?

    这是 3D 模型 我想将另一个像这样的模型连接到顶部的银色连接器 并将另一个模型连接到右侧 所以请帮助我捕捉它 https i stack imgur com qoWwl png我想知道如何在运行时将两个 3D 对象对齐在一起 即 在 玩
  • boost::bind 会导致开销吗?

    我目前正在从事网络软件方面的工作 它有一个主要类 server这显然代表一个服务器实例 A server实例可以发送请求 并通过回调通知用户响应 代码如下 class server public typedef boost function
  • 访问控制器类中的 appsettings.json 值

    无法弄清楚如何读取startup cs之外的appsettings json值 例如 我想做的是在 Layout cshtml 中 从配置中添加站点名称 例如 ViewData SiteName Configuration GetValue
  • Pythonlibs3 CMake 和 macOS

    更新2 将以下两行添加到我的 CMake 文件中时 成功找到了 python 3 及其库 这只在终端中工作的原因是因为 CLion 使用其捆绑版本的 CMake 3 6 3 而我的终端使用的更新版本 3 7 2 正确找到了 python F
  • 如何打开 Outlook 已接收和阅读电子邮件

    我们有 5 个人 使用同一封电子邮件通过 Outlook 回复客户 我想设计一个程序来打开所有已发送的电子邮件 阅读它们 打开它们 找到第一个人的签名 并在他 她的计数器中添加一个数字 以便我可以得出一些统计数据 关于如何打开 Outloo
  • 如何在迭代时从地图中删除?

    迭代时如何从地图中删除 喜欢 std map
  • 实现多个接口的 Service Fabric Actor 接口

    我正在构建一个应用程序 其中有多个不同的参与者类型 这些参与者类型对于某些不同的数据对象具有相同类型的行为 CRUD 为了更轻松地创建处理此问题的代码 我尝试创建一个这些参与者可以实现的接口 这意味着我有一个看起来像这样的参与者界面 pub
  • SQlite 查询 - 如何检索多列数据?

    我很难在网上找到一个关于使用 xcode 和 cocos2dx 从 SQlite DB 获取多个值的工作示例 这是我的sql查询 char sql query 100 sprintf sql query SELECT FROM SQList
  • 类型与创建 CLR 存储过程不匹配

    我在程序集中有一个如下所示的方法 namespace MyNameSpace public class MyClass Microsoft SqlServer Server SqlProcedure public static void M
  • 系统.安全.加密与 PCLCrypto

    我们正在删除系统中的许多共享功能并将其移植到 PCL 库中 我在使用 PCLCrypto 时遇到问题 我正在获取数据库中的一些现有数据 并尝试使用相同的算法对其进行解密 我得到了值 但末尾有 16 个额外字节 这些字节都是垃圾 参见下面的代

随机推荐

  • PreviewKeyDown 不会在 ElementHost 中针对 Tab 和箭头键触发

    我在 Winforms ElementHost 中有一个 WPF 窗口 我的窗口上的 Tab 键和箭头键不会触发 KeyDown 和 PreviewKeyDown 事件 KeyUp 和 PreviewKeyUp 似乎工作正常 Preview
  • 将字符串拆分为数组,在 Swift 中保留定界符/分隔符

    寻找一种 优雅的 解决方案来分割字符串并将分隔符保留为数组中的项目 示例1 hello world hello world 示例2 hello world hello world thx 假设您要使用名为的分隔符分割字符串separator
  • 在 Bash 中替换垂直线

    我很难完成我的脚本 因为这一部分没有按照我想要的方式运行 我的脚本中有这一行 cat home tmp temp1 txt awk gsub RS gsub RS print gt home tmp temp txt 效果很好 是的 但是当
  • 如何枚举控件的所有依赖属性?

    我有一些 WPF 控件 例如 文本框 如何枚举该控件的所有依赖属性 如 XAML 编辑器所做的那样 不需要使用反射 恕我直言 这是一个坏主意 因为框架已经为此提供了实用程序类 但它们并不明显找到 以下是基于这篇文章的答案 枚举绑定 http
  • nodejs knox 放入 s3 结果是 403

    我尝试在 nodejs 项目中使用 knox 上传到 Amazon s3 存储桶 但无法解决 403 错误 我已确保密钥 秘密和存储桶已正确设置 我真的需要那些有更多经验的人的帮助 我的节点代码如下 var upload test func
  • 属性“tablename.title”未定义

    我是伊比 我想做的是上传图像 照片 以及具有更新功能的数据库中的路径条目 我已点击此链接 http www yiiframework com wiki 349 how to upload image photo and path entry
  • 插入后,数据库中仅插入“字符串”的一个字符

    Below is my table screenshot Data after insertion C 代码 SqlConnection con new SqlConnection connectionsession Con con Ope
  • 未调用 Ajax 回调。如何解决这个问题?

    我再次来这里寻求您的建议 我有一些 AJAX 调用 用于从我的编辑器 PHP 在线编辑器 运行代码 大家可以来看看my site http web guru99 com 我有一些 ajax 调用来发送编辑器的数据并接收输出 问题 for 循
  • Bash for Windows 10 gcc 不会编译粘贴到根目录中的 c 文件

    正如标题所示 如果我将在其他地方编写的c文件粘贴到Linux子系统的根目录中 则无法编译它 我做了一个测试 我制作了两个不同标题的 hello world 程序 一个在 vi 中 我可以从 bash 界面进入 另一个在其他地方 当我编译了
  • 尝试查找 BLE 设备时如何使用 LeDeviceListAdapter?

    我正在 Android 中开发一个应用程序 并且我遵循 Android 中的代码建议开发者页面 http developer android com guide topics connectivity bluetooth le html f
  • 如何区分结构化数据和非结构化数据?

    结构化数据和非结构化数据有什么区别 这种差异如何影响各自的数据挖掘方法 我熟悉的术语是结构化的 and 非结构化的数据 除了后缀之外 与 Q 中的内容相同 我在机器学习中使用这两种类型的数据 但我不知道任何正式的定义 然而 我怀疑几乎每个工
  • 如何将字典转换为字符串

    我正在尝试使用提供的解决方案here https stackoverflow com questions 5192753 how to get the number of occurrences of each character usin
  • Tensorflow 导入错误:没有名为“tensorflow”的模块

    我在 Windows Python 3 5 Anaconda 环境中安装了 TensorFlow 验证成功 有警告 tensorflow C gt python Python 3 5 3 英特尔公司 默认 2017 年 4 月 27 日 1
  • 如何减少 Android 布局中文本之间的行距?

    我想减少所附布局中文本之间的行距 User12 5 部电影 改进 2 5 下面是 xml 我尝试删除 singleLine true 语句并尝试将其设置为 false
  • Rstudio 中的 Sweave — pdf 中没有显示任何图

    这里是 Sweave Latex 新手 我在生成常规函数输出时没有问题 但绘图没有显示 这是一个基本示例 documentclass article begin document SweaveOpts concordance TRUE lt
  • 空 Activity 中的内存泄漏

    我最近决定使用泄漏金丝雀 https github com square leakcanary在我的项目中 所以我创建了一个空的项目Activity只是为了测试 当我运行应用程序时 在没有逻辑代码或视图的项目创建之后 我从这个库中获得了内存
  • 当参数为 0 与任何其他整数时,如何为返回不同类型的函数创建重载注释?

    是否可以为当参数为时返回不同类型的函数创建重载注释0与任何其他整数 def foo val int gt MyObjectA MyObjectB if val 0 return MyObjectA return MyObjectB 有没有办
  • Git:以新名称签出旧版本的目录

    如何以新名称查看目录的先前版本 我一直都有一个目录foo在我的仓库中 我想创建一个目录foo old在我当前的工作树中 其内容是HEAD 2 foo 我同时需要两个版本 以确保它们给出相同的结果 测试这需要相当多的代码 并且需要同时提供两个
  • 随机斜率 Cox 比例风险

    我一直在尝试使用coxme提取模型中每个协变量的随机斜率 library coxme Start lt runif 5000 1985 2015 Stop lt Start runif 5000 2 10 S lt data frame X
  • 如何在 WPF 应用程序上执行异步启动?

    我在异步等待方面相当落后 所以这可能是一个 duh 问题 我正在开发一个非常小的 UI 应用程序 它使用以下命令从系统托盘运行WPF 通知图标 http www codeproject com Articles 36468 WPF Noti