簡體   English   中英

Task.Run(()=> Method()); 沒有運行該方法?

[英]Task.Run(() => Method()); doesn't run the method?

在我的WPF應用程序中:

using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using System.Diagnostics;

namespace CloudKey
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
    public Page1()
    {
        InitializeComponent();

        AuthText.Visibility = Visibility.Hidden;

    }
    private async void button_Click(object sender, RoutedEventArgs e)
    {

        AuthText.Visibility = Visibility.Visible;
        await Task.Run(() => Authenticate());
        Task.Factory.StartNew(() => Authenticate());
        Task.Run(() => Authenticate());
        Authenticate();
    }
    void Authenticate()
    {
        //Do Stuff
    }
  }
}

無論我嘗試以哪種方式調用“通過Tasks進行Authenticate ,它都不會運行。 我使用Task錯誤?

使用await(和async)會引發異常:

未處理System.InvalidOperationException消息:mscorlib.dll中發生了'System.InvalidOperationException'類型的未處理異常。其他信息:調用線程無法訪問此對象,因為其他線程擁有它。

僅使用Task.Run或Task.Factory.StartNew會導致完全不執行Authenticate方法。 如果我將斷點添加到Authenticate方法中,則無法實現。

只需使用Authenticate()調用該方法即可運行整個方法,而不會出現問題,但是它將凍結UI,使之成為“ AuthText.Visibility = Visibility.Visible;”。 無用。

老實說,我真的只希望UI更新消息“ Authenticating ...”,然后在單擊按鈕時運行方法中的所有內容。 也許有更簡單的方法做到這一點?

這是參考的工作代碼:

using System;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using System.Diagnostics;
using System.Threading.Tasks;

namespace CloudKey
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
    public Page1()
    {
        InitializeComponent();

        //private void PasswordBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { button_Click } }
        AuthText.Visibility = Visibility.Hidden;

    }
    private void button_Click(object sender, RoutedEventArgs e) //ON CONTINUE BUTTON CLICK
    {
        AuthText.Visibility = Visibility.Visible;
        Task.Run(() => Authenticate());
    }
    void Authenticate()
    {
        Dispatcher.Invoke(
        () =>
        {
          //ALL MY CODE HERE;
        });
      }
    }
  }

問題是您不等待異步任務完成,因此看起來好像“什么都沒有發生”-實際上確實發生了。 當您調用Task.RunTask.Factory.StartNew ,除非您正確處理Task ,否則實際上就是在執行即Task.RunTask.Factory.StartNew

private async void button_Click(object sender, RoutedEventArgs e)
{
    await Task.Run(() => Authenticate()); // Stuff happens
}

void Authenticate()
{
    // DO STUFF
}

在上面的示例中,將關鍵字async添加到事件處理程序允許該方法利用await關鍵字。 await關鍵字是所有魔術真正發生的地方……但是它將按您期望的那樣工作,即; “事情發生了”。

當我擊敗斯蒂芬·克雷蒂(Stephen Cleary)時,通常會向人們指向他的博客, 這一博客尤其應為您澄清這一點。

注意

強烈建議不要編寫async void 唯一的例外是在示例中將其應用於事件處理程序。 最后,當使用TaskTask<T>以及async / await關鍵字時,請在整個堆棧中使用。 我會更改您的Authenticate方法以返回一個Task ,例如,可以等待它。 嘗試調用Task.Run盡可能最低的級別。

private async void button_Click(object sender, RoutedEventArgs e)
{
    await Authenticate(); // Stuff happens
}

Task Authenticate()
{
    return _authModule.Authenticate();
}

更新資料

根據您的評論,執行以下操作:

private void button_Click(object sender, RoutedEventArgs e)
{
    bool authenticated = false;
    try
    {
        AuthText = "Authenticating...";
        authenticated = Authenticate(); // Stuff happens
    }
    finally
    {
        AuthText = authenticated ? "Authenticated" : "Oops!";
    }
}

bool Authenticate()
{
    // Return if auth was successful
}

在新線程中修改UI內容時,您需要使用Dispatcher.Invoke ,也可以使用InvokeAsync

    private void Button_Click( object sender, RoutedEventArgs e ) { Task.Run( () => Authenticate() ); }

    public void Authenticate()
    {
        Dispatcher.Invoke(
            () =>
            {
                ClickButton.Content = "Text Changed";
            } );
    }

通過使用Dispatcher您正在告訴WPF在有權更新您的GUI控件的主線程上運行此代碼塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM