1

私は 2 つのユーザー コントロールを持ち上げます。最初のものには 1 つが含まれItemsControlており、2 番目のユーザー コントロールで動的に入力する必要があります。ÌtemsControl2 番目のユーザー コントロールには、再帰的に別のユーザー コントロールが含まれている可能性があるため、初期化するのは非常に重いコントロールです。

これが私がしたことですSubControl

public sealed partial class SubControl : UserControl
{
    public SubControl(ModelA item)
    {
        this.InitializeComponent();
        this.DataContext = item;

        //if the current item has child items, add them to the ItemsControl:
        if(item.SubItems != null)
        {
            BuildUI(item.SubItems);
        }
    }

    private void BuildUI(List<AbstractModel> data)
    {
        foreach(var item in data)
        {
            var dataItem = item as ModelA;
            //we only want item of type ModelA in our ItemsControl:
            if(dataItem != null)
            {
                SubElements.Items.Add(new SubControl(dataItem));
            }
        }
    }
}

ここで、これらのセットを含む (と呼ばれる)MainControlItemsControl最初に書いたものを次に示します。ElementsSubControl

public sealed partial class MainControl : UserControl
{
    public MainControl(List<AbstractModel> data)
    {
        this.InitializeComponent();
        BuildUI(data);
    }

    private void BuildUI(List<AbstractModel> data)
    {
        foreach(var item in data)
        {
            var dataItem = item as ModelA;
            if(dataItem != null)
            {
                Elements.Items.Add(item);
            }
        }
    }
}

この「ツリー」の作成中に UI がわずかにフリーズすることに気付きましたが、現在は非常に強力なコンピューターで作業しています。Windows Surface RT などのより小さなデバイスでもアプリケーションをスムーズに実行したいと考えています。だから私はMainControlコードを変更しました:

public sealed partial class MainControl : UserControl
{
    public MainControl(List<AbstractModel> data)
    {
        this.InitializeComponent();
        BuildUI(data);
    }

    private async void BuildUI(List<AbstractModel> data)
    {
        var list = new List<SubControl>();
        await Task.Run(() =>
        {
            foreach(var item in data)
            {
                var dataItem = item as ModelA;
                if(dataItem != null)
                {
                    list.Add(new SubControl(dataItem));
                }
            }
        });
        foreach(var item in list)
        {
            Elements.Items.Add(item);
        }
    }
}

アイデアはSubControl、UI がブロックされないようにすべてを別のスレッドで構築することです。すべてのユーザー コントロールが初期化されたら、それらを の に追加しItemsControlますMainControl

SubControlただし、実際には UI に1 つも存在しない場合でも、データのマーシャリングが原因でこれは機能しません。SubControl実際の UI に影響を与えないため、ビルド中にクラッシュします。これは非常に奇妙です。それらは一時的に追加されるだけListです。

UI がフリーズしないように、バックグラウンド タスクでこれらのユーザー コントロールを構築するためのトリックは何でしょうか?

4

2 に答える 2

4

Windows UI は非常にシングルスレッドです。各 UI コントロール作成し、単一のスレッドからのみ使用する必要があります。これを回避する方法はありません。

そのため、解決策について少し違った方法で考える時が来ました。何十ものコントロールを作成しても問題ありません。UIはそれをうまく処理します。何百または何千もの項目をリスト コントロールに追加することについて話しているのですが、それは単に使用できない UI です。したがって、適切な解決策は、UI デザインを再考することです。おそらく、結果をカテゴリなどに分割できます。

UI のデザインを考えても、何百、何千ものアイテムをユーザーに表示したいという確信がある場合、その答えは仮想化を使用することです。これは単純なforeachループよりもコーディングが少し難しくなりますが、大量のデータを効率的に表示する唯一の方法です。

于 2013-11-04T03:23:49.440 に答える
-1

これを行うには多くの方法があります。

次のワークフローを使用できます。

  • 初期化の終了時に発生する EventHandler を実装します。
  • 「読み込み中」と言って空の MainControl を表示する
  • 別のスレッドですべての UI をビルドする
  • すべての UI をビルドしたら、finish イベントを発生させます
  • このイベントのリスナーは、SubControls を MainControl に追加します

[...] 実際の UI に影響を与えないためです。それらは一時的なリストに追加されるだけです

ところで、実際には非 GUI スレッドである非同期メソッドでコントロールを追加しているため、コードはクラッシュします。したがって、あなたの提案は間違っています。

于 2013-11-03T00:02:48.903 に答える