【问题标题】:How to call async method from MainWindow?如何从 MainWindow 调用异步方法?
【发布时间】:2015-05-14 21:53:48
【问题描述】:

所以我写了一个快速的async 方法来将一些数据从Oracle 数据库中获取到DataTable。我应该如何在不阻塞 UI 线程的情况下从 MainWindow() 调用它? async/wait 模型在那里没有多大意义。

    async Task<DataTable> AccessOracleAsync()
    {
        DataTable dt;
        using(OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["connStr"].ConnectionString))
        using (OracleCommand cmd = new OracleCommand(@"SELECT * FROM myTbl", conn))
        {
            await conn.OpenAsync();
            using (var reader = await cmd.ExecuteReaderAsync())
            {
                dt = new DataTable();
                dt.Load(reader);                        
            }

        }
        return dt;
    }

【问题讨论】:

    标签: c# wpf xaml async-await


    【解决方案1】:

    尝试为Laoded 事件创建一个处理程序,将其标记为async 并从那里调用您的AccessOracleAsync 方法。

    【讨论】:

      【解决方案2】:

      没有看到你的构造函数,很难说那里可能“有意义”。但是您至少有几个选择。

      选项#1:将调用放入构造函数中。

      在这种情况下,您不能创建方法async,并且您肯定不希望您的延续执行任何需要在构造函数返回之前完成的事情。但是您仍然可以有效地完成 C# 在 async 方法中为您完成的工作:

      public MainWindow()
      {
          InitializeComponent();
      
          AccessOracleAsync().ContinueWith(task => { /* do some other stuff */ },
              TaskScheduler.FromCurrentSynchronizationContext());
      }
      

      这将在 UI 线程上执行延续,就好像你写了await AccessOracleAsync(); /* do some other stuff */。根据需要在 continuation 方法中添加异常处理(即检查 task 对象并适当处理)。

      选项 #2: 将呼叫放在其他地方。

      建议使用Loaded 事件,您可以这样做。这可能看起来像这样:

      private async void Window_Loaded(object sender, RoutedEventArgs e)
      {
          await AccessOracleAsync();
      
          // do some other stuff
      }
      

      请注意,如果后者看起来合适,恕我直言,这是更可取的。它让 C# 编译器为您完成繁重的工作,包括处理异常(您可以将调用包装在 try/catch 中,一切都“正常工作”)。

      【讨论】:

        【解决方案3】:

        我刚刚完成了这个,男孩,这是一场斗争!您不能只按照其他答案中的建议调用您的方法,因为调用方法或构造函数将结束并且任务将丢失。

        我做了两件事

        1:绑定窗口加载事件,而不是在构造函数中做

        2:如果您想在后台进程中运行,则必须调用 Task.Run,​​无论您的方法是否是异步的

        例如

            public async void Window_Loaded(object sender, RoutedEventArgs e)
            {
                Task.Run(()=>this.AccessOracleAsync().ContinueWith(function to deal with results));
            }
        

        此外,如果您需要返回前台线程以使用结果更新 UI,您将需要启用您的集合以确保线程安全

            public MainVM()
            {
                this.results= new ObservableCollection<resultType>();
                BindingOperations.EnableCollectionSynchronization(results, _itemsLock);
            }
            private static object _itemsLock = new object();
            public ObservableCollection<resultType> results{ get; set; }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-03-06
          • 2016-07-20
          • 1970-01-01
          • 2020-03-10
          • 2019-07-09
          • 1970-01-01
          相关资源
          最近更新 更多