等待新添加的控制事件 - C#

2024-03-21

我在面板中有一个按钮,它将调用另一个方法,该方法将创建一个用户控件来覆盖整个面板。这是面板按钮单击事件的代码:

    private void btnTarget_Click(object sender, EventArgs e)
    {
        UtilLoader.ShowLoader(this);

        lblStatus.Text = "Done";
    }

ShowLoader的代码是这样的:

internal class UtilLoader
{
    public static void ShowLoader(Control parent)
    {
        var ct = new UcLoaderBox(parent)
        {
            Dock = DockStyle.Fill,
            Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
            Bounds = parent.ClientRectangle
        };
        parent.Controls.Add(ct);
        ct.BringToFront();

        ct.SubmitMessage += (sender, args) => { /* Here I can detect if user control is closed */ };
    }
}

用户控件有一个名为的事件SubmitMessage如果用户单击用户控件内的按钮,则会触发该事件。这btnTarget_Click将打开用户控件,然后立即执行lblStatus.Text = "Done;

我需要等待SubmitMessage在用户控件内触发。 我尝试使用做这样的事情ManualResetEvent,但没有成功,它不会停止等待:

internal class UtilLoader
{
    public static async void ShowLoader(Control parent)
    {
        var waiter = new ManualResetEvent(false);
        var ct = new UcLoaderBox(parent)
        {
            Dock = DockStyle.Fill,
            Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right,
            Bounds = parent.ClientRectangle
        };
        parent.Controls.Add(ct);
        ct.BringToFront();

        ct.SubmitMessage += (sender, args) => { waiter.Reset(); };

        await Task.Run(()=> waiter.WaitOne());
    }
}

我还使用了下面的代码并替换await ct.WhenClicked代替await Task.Run(()=> waiter.WaitOne());在上面的代码中,但仍然没有等待!

public static class Utils
{
        public static Task WhenClicked(this Control target)
        {
            var tcs = new TaskCompletionSource<object>();
            EventHandler onClick = null;
            onClick = (sender, e) =>
            {
                ((UcLoaderBox) target).SubmitMessage -= onClick;
                tcs.TrySetResult(null);
            };
            ((UcLoaderBox)target).SubmitMessage += onClick;
            return tcs.Task;
        }
}

我应该做什么来实现我的目标?

Updated:

有了安迪的答案,现在就可以正常工作了。但还有另一个问题。

该用户控件充当模态框,它会在需要时出现。我正在添加它并用旧的消息框系统替换它。该按钮可以调用插入数据库的方法或登录文本文件的另一个方法。在这些方法中,用户控件可以在其父控件上显示为模式。

我可以将父参数添加到这些方法中,并将父控件传递给它们,这样每当它们想要显示模式时,它们就可以,如果没有,则什么也没有。

但是将所有这些方法转换为 async-await 并将所有按钮事件转换为 async-await 非常困难。


这似乎有效:

public class SomeLoader
{
    // no reason to use async void here. Use Task.
    public static async Task LoadSomethingAsync(Control parent)
    {
        using(var ev = new ManualResetEvent(false))
        {
            var c = new TestModalUserCtrl();
            parent.Controls.Add(c);

            c.SomeMessage += (s, e) =>
            {
                ev.Set(); // use Set
            };

            await Task.Run(() => ev.WaitOne());

            parent.Controls.Remove(c);
        }
    }
}

诀窍是做到这一点async,然后等待调用者:

// make sure your event is async
private async void button1_Click(object sender, EventArgs e)
{
    // await for the job to finish
    await SomeLoader.LoadSomethingAsync(this);

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

等待新添加的控制事件 - C# 的相关文章

随机推荐

  • 分布式序列号生成?

    我一般都实现了序列号生成过去使用数据库序列 例如使用 Postgres SERIAL 类型http www neilconway org docs sequences http www neilconway org docs sequenc
  • 如何在渲染前使用 setState 更新状态

    我将在序言中声明我是 React js 的初学者 我创建了一个我正在开发的项目示例 在该项目中 我在 componentDidMount 中调用 API 并获取对象数组 并将其设置为状态 它看起来是这样的 class App extends
  • 如何将@request注入到服务中?

    当我尝试将 request 注入到我的任何服务中时 我收到此异常 ScopeWideningInjectionException 检测到范围扩大注入 定义 service navigation 引用服务 request 属于比较窄的范围 一
  • 如何在多个 Angular 组件之间共享 api 响应?

    我试图把我的头绕过去并使用BehaviourSubject在 Angular 中 到目前为止还没有太多运气 我的目标是在我的组件之间共享 api 请求响应 这是我的项目的 stackblitz 设置 https stackblitz com
  • 在 Tomcat 中打开新线程

    我只是问理论问题 我有一个需要一段时间的操作 该操作是在某些 Servlet doGet doPost 方法或 Spring MVC 控制器内部执行的 打开新的后台线程并在那里执行是个好主意吗 不会导致性能问题吗 如果我在这种情况下使用 j
  • 通过 VPN 的 Python 请求给出 502 Bad Gateway

    我正在尝试使用以下命令从公司网络内的服务器获取一些数据requests图书馆 我使用 VPN 进入公司网络 并且还设置了公司代理 我尝试访问的地址仅在该公司网络内可见 import requests url http some privat
  • 将 clojure 映射/数组写入文件并读回

    我需要将 clojure 映射保存到文件中并稍后读回以处理它们 这就是我能想到的 有没有更好的方法来完成同样的事情 user gt def my data for a Person1 Person2 b Address1 Address2
  • 对 Python 正在处理其输出的外部程序进行计时

    我想测量我的 Python 脚本使用其输出的外部程序的执行时间 Calling extprogram产生输出的程序 目前我做了类似的事情 import time import subprocess def process output li
  • 尝试将打字稿库与 webpack 捆绑时导出未定义

    我有一个正在用打字稿开发的库 我有通过 tsc 构建它以将其用作 npm 包的解决方案 但 tsc 单独翻译每个文件 我想使用 webpack 将所有内容创建在一个缩小的文件中 但它不起作用 我做了一些测试 使用 module export
  • 如何在页面重新加载时将值保留在 blazor Web 程序集中的单例状态容器中

    我练习和学习blazor web assembly 我正在学习组件之间通信的方法 一种这样的方法是使用状态容器 这按预期工作 但它不能维持页面刷新的价值 这是我的状态容器类 AppState public class AppState pu
  • 了解使用右值/左值的模板参数推导

    这是来自的后续函数模板无法识别左值 https stackoverflow com questions 22166767 template function does not recognize lvalue 22166879 221667
  • C# 中的私有方法单元测试

    Visual Studio 允许通过自动生成的访问器类对私有方法进行单元测试 我编写了一个私有方法的测试 该方法编译成功 但在运行时失败 代码和测试的相当最小的版本是 in project MyProj class TypeA privat
  • 如何将不透明度应用于 CSS 颜色变量?

    我正在使用 Electron 设计一个应用程序 因此我可以访问 CSS 变量 我已经定义了一个颜色变量vars css root color f0f0f0 我想用这个颜色main css 但应用了一些不透明度 element backgro
  • 在 WSO2 Integration Studio 中将双精度数转换为整数

    我正在 XPath 表达式中执行算术运算 在下面的代码中 qty1和qty2是双倍的 因此我得到的结果是双倍的 我想将结果转换为整数并将其保存在属性中 如何在 WSO2 Integration Studio 中实现它
  • CasperJS/PhantomJS 在加载页面时卡住

    我正在使用 phantomjs 运行以下脚本 var casper require casper create var url https itunesconnect apple com itc static login view 1 pa
  • 在 Visual Studio 2017 中使用 Windows 窗体应用程序?

    我正在关注 Udemy 系列 它要求的第一件事是创建一个 Windows 窗体应用程序 使用 C 我不认为这是我的选择之一 这是因为我使用的是免费版本吗 我已经安装了 Windows Template Studio 为了开发WPF Wind
  • 这些 jQuery 就绪函数有什么区别?

    有什么区别 function and document ready function 什么都没有 http api jquery com jQuery jQuery3 这个函数的行为就像 document ready 因为它应该 用于包装其
  • 如何更改Windows系统时区?

    我正在编写一个软件 允许更改 Windows 中使用的当前时区参数 到目前为止 我发现的设置系统范围时区的唯一参考是API 或其变体SetDynamicTimeZoneInformation 但我不太确定如何使用它来更改当前时区 例如 需要
  • 多处理池工作线程中的线程标识符

    我相信Thread ident作为线程的唯一标识符 但现在我看到不同的工作进程multiprocessing poo Pool报告相同的线程标识符threading current thread ident How 根据平台的不同 ID 可
  • 等待新添加的控制事件 - C#

    我在面板中有一个按钮 它将调用另一个方法 该方法将创建一个用户控件来覆盖整个面板 这是面板按钮单击事件的代码 private void btnTarget Click object sender EventArgs e UtilLoader