0

私は困惑しており、あなたの助けが必要です。

ASYNC と AWAIT を使用して WEBAPI を呼び出す WPF アプリケーションがあり、UI に遅延が発生しています。

これが私が使用しているコードです...

HttpResponseMessage response = await WEBAPI.GetHttpClient().GetAsync("api/COStateType/GetStateTypesByCountryID/" + Constants.COUNTRY_ID_USA);  
response.EnsureSuccessStatusCode(); 
App.stateTypes = await response.Content.ReadAsAsync<List<coStateType>>(); 

GetHttpClient コード...

 public static HttpClient GetHttpClient()
    {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(ConfigurationManager.AppSettings["ABS2.WEBAPI.Uri"]);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        return client;
    }

ここからが本題…

起動時に歯車が動くスプラッシュ スクリーンを表示します (アニメーション)。アニメーションがスムーズでなくなる WEBAPI への呼び出しを実装した後。HttpClient を使用した ASYNC 呼び出しが UI のブロックを引き起こし、それが私のアニメーションに起こっていることを示していることを読みました。

これが質問です...

とにかくこの問題の周りにありますか? この呼び出しを BackgroundWorker や Task 内にラップしようとしましたが、どちらも問題を解決しませんでした。この UI のブロックを引き起こさない WEBAPI と通信する別の方法はありますか? 私は何か間違ったことをしていますか?

ありとあらゆる助けに感謝します!!!

4

4 に答える 4

2

@Stef7 & @Panagiotis - UI スレッドがブロックされたというのは正しいです。ただし、非同期呼び出しが UI スレッドをブロックする理由がよくわかりません。私はもっ​​と研究をしなければならないでしょう。

既にバックグラウンド スレッドを試していましたが、タスクに ContinueWith を実装するまで問題は解決しませんでした。

ご協力ありがとうございました。

これが最終的なコードです。

public partial class Splash : Window
{
    private TypeBO boType = new TypeBO();
    private Stopwatch swTotal = new Stopwatch();
    private Stopwatch swData= new Stopwatch();

    public Splash()
    {
        InitializeComponent();
        swTotal.Start();
    }

    private void GetData()
    {
        Assembly assembly = Assembly.GetExecutingAssembly();
        lblMessage.Content = "Please Wait...";
        lblVersion.Content = "Version: " + assembly.GetName().Version.Major + "." + assembly.GetName().Version.Minor + "." + assembly.GetName().Version.Revision;

        swData.Start();

        var backgroundWorker = new BackgroundWorker();
        backgroundWorker.DoWork += this.OnBackgroundWorkerDoWork;
        backgroundWorker.RunWorkerCompleted += OnBackgroundWorkerRunWorkerCompleted;
        backgroundWorker.RunWorkerAsync();
    }

    private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
    {
        WEBAPI.GetHttpClient().GetAsync("api/COStateType/GetStateTypesByCountryID/"
            + Constants.COUNTRY_ID_USA).ContinueWith(r =>
            {
                r.Result.EnsureSuccessStatusCode();
                e.Result = r.Result.Content.ReadAsAsync<List<coStateType>>().Result;
            }).Wait();

        swData.Stop();
        System.Diagnostics.Debug.Write("Splash - DATA - Total Elapsed Time - " + swData.Elapsed + Environment.NewLine);
    }

    private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        var backgroundWorker = sender as BackgroundWorker;
        backgroundWorker.DoWork -= this.OnBackgroundWorkerDoWork;
        backgroundWorker.RunWorkerCompleted -= OnBackgroundWorkerRunWorkerCompleted;

        App.stateTypes = e.Result as List<coStateType>;

        coStateType pleaseSelectStateType = new coStateType() { State_ID = 0, State_Nm = "Select One", Country_ID = 1 };
        App.stateTypes.Insert(0, pleaseSelectStateType);

        sbHideState.Completed += (snd, eva) =>
        {
            //Pre-Load User Controls
            Assembly assembly = this.GetType().Assembly;
            UserControl ucBHSearch = (UserControl)assembly.CreateInstance(string.Format("{0}.BHSearch", "ABS2.WPF.ADMIN.UserControls.BusinessHierarchy"));
            UserControl ucBHDetails = (UserControl)assembly.CreateInstance(string.Format("{0}.BHDetails", "ABS2.WPF.ADMIN.UserControls.BusinessHierarchy"));
            App.userControls.Add("BHD", ucBHDetails);
            App.userControls.Add("BHS", ucBHSearch);

            Login winLogin = new Login();
            winLogin.Show();

            swTotal.Stop();
            System.Diagnostics.Debug.Write("Splash - UI - Total Elapsed Time - " + swTotal.Elapsed + Environment.NewLine + Environment.NewLine);
            swTotal.Reset();
            this.Close();
        };
        sbHideState.Begin(gridSplash);
    }

    private void Window_Loaded_1(object sender, RoutedEventArgs e)
    {
        lblMessage.Content = "";
        lblVersion.Content = "";
        sbDefaultState.Begin(gridSplash);
        sbRotateState.Begin(gridSplash);           
    }

    private void window_ContentRendered(object sender, EventArgs e)
    {
        sbShowState.Completed += (snd, eva) =>
        {
            GetData();
        };
        sbShowState.Begin(gridSplash);
    }
}
于 2012-12-19T13:31:44.630 に答える
1

投稿されたコードはすべてUIスレッドで実行されます。非同期機能を使用すると、(Webリクエスト中に)何も​​することがないときにUIスレッドをブロックしないようにできますが、コードが多すぎてUIスレッドをビジー状態にすると、アニメーションで常に問題が発生します。

Web関連のすべてのコードをバックグラウンドワーカーに移動し、UIスレッドに短いUI更新のみを投稿してみます。すでにバックグラウンドワーカーを試したと書いたので、UIの更新に時間がかかりすぎると思います。

パフォーマンスプロファイラーを使用している場合は、UIスレッドのビジー時間を分析して、より良い画像を取得します。

于 2012-12-18T15:57:11.860 に答える
1

awaitが待機を終了すると、元のコンテキスト (スレッド) で実行が続行されます。これは、この場合は UI スレッドです。

これにより、コードはディスパッチャを使用せずに UI コントロールにアクセスできます。これは、最後のawaitの後の高価なコードが実際に UI スレッドで実行されることを意味します。

コードを別のスレッドで引き続き実行したい場合は、await の呼び出しの後に .ConfigureAwait(false) を追加する必要があります。

await response.Content.ReadAsAsync<List<coStateType>>().ConfigureAwait(false);

この場合、Dispatcher または SynchronizationContext メソッドのPost / Sendを使用して UI コントロールにアクセスするように注意する必要があります。

SynchronizationContext.Current.Post(_=>progressBar.Value+=5,null);
于 2012-12-18T08:27:37.287 に答える