0

カスタムタイプの監視可能なコレクションにバインドされた項目ソースを持つデータグリッド (dat1 と呼びます) があり、それを TypeA と呼びます。TypeA のプロパティの 1 つは、TypeB と呼ばれる別のカスタム型の監視可能なコレクションです。次に、アイテム ソースが dat1 の SelectedItem.TypeB にバインドされたコンボ ボックスを作成します。

そのため、ユーザーが dat1 で TypeA を選択すると、コンボボックスには、選択した TypeA の TypeB オブザーバブル コレクションのアイテムが表示されます。わかる?

バインディングは機能し、更新されます。問題は、コンボボックスのアイテム プレゼンターが既にアイテムを表示しているときに、ユーザーが dat1 で別の TypeA を選択し、コンボボックスで新しいアイテムを表示しようとすると、アイテム プレゼンターが新しいアイテムを生成する間、長い一時停止が発生することです。

問題をテストするために、シナリオを単純化できます。

再現する手順:

  1. .NET 4.0 を使用して新しい WPF プロジェクトを作成します。

  2. 以下のコードをカット&ペーストしてください。

  3. フリーズ動作を取得するには、コンボボックスをドロップしてアイテムを表示し、ボタンをクリックしてアイテムのソースを変更し、コンボボックスを再度ドロップする必要があります。コンボボックスは数秒後にドロップしますが、なぜそんなに遅いのでしょうか?

XAML

<Window x:Class="ComboBoxTest.MainWindow"
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <ComboBox x:Name="cbo" DisplayMemberPath="Junk1"></ComboBox>
            <Button Content="Click Me!" Click="btn_Click"></Button>
        </StackPanel>
    </Grid>
</Window>

コード

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.cbo.ItemsSource = junk1;
    }

    ObservableCollection<Junk> junk1 = new ObservableCollection<Junk>() {
        new Junk() { Junk1 = "junk1 - 1" },
        new Junk() { Junk1 = "junk1 - 2" } };

    ObservableCollection<Junk> junk2 = new ObservableCollection<Junk>() {
        new Junk() { Junk1 = "junk2 - 1" },
        new Junk() { Junk1 = "junk2 - 2" },
        new Junk() { Junk1 = "junk2 - 3" },
        new Junk() { Junk1 = "junk2 - 4" } };

    private void btn_Click(object sender, RoutedEventArgs e)
    {
        if (this.cbo.ItemsSource == junk1)
            this.cbo.ItemsSource = junk2;
        else
            this.cbo.ItemsSource = junk1;
    }
}

public class Junk
{
    public string Junk1 { get; set; }
}

注: これは WPF の問題です。Silverlight には同じ問題がないと聞いたことがあります。Silverlight が機能するかどうかを知る必要はありません。WPFの回答が必要です。

PS。アイテムのソースが jump2 に変更されると、遅延が長くなります。これは、おそらくサイズが大きいためです。

例外には時間がかかるため、バインド例外が原因であると思われるほど十分に遅延します。バインディング例外がスローされているかどうかを確認する方法はありますか?

4

1 に答える 1

0

私もこの現象を観察しています。Windows 7 x64 で Visual Studio 2010 (ReSharper 6.0 を使用) を使用しています。

上記の例のように 4 個のアイテムだけでは目立ちませんが、たとえば 50 個以上のアイテムにすると、フリーズが非常に目立ちます。再バインド後、約 15 秒間ハングしてから、再度操作できるようになります。

もう 1 つの興味深い点は、これが VS でのデバッグ中にのみ発生することです。exe をスタンドアロンで実行すると、非常に高速で高速です。

私の単純なプロジェクトのコードは次のとおりです。

XAML

<Window x:Class="ComboBoxFreeze.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
  <StackPanel>
    <ComboBox x:Name="cbo" DisplayMemberPath="Junk1"></ComboBox>
    <Button Content="Click Me!" Click="btn_Click"></Button>
  </StackPanel>
</Window>

コード

using System.Collections.ObjectModel;
using System.Windows;

namespace ComboBoxFreeze
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;

            _junk1 = new ObservableCollection<Junk>();
            for (int i = 0; i < 50; i++)
            {
                _junk1.Add(new Junk { Junk1 = "Prop1a-" + i, Junk2 = "Prop1b-" + i });
            }


            _junk2 = new ObservableCollection<Junk>();
            for (int i = 0; i < 50; i++)
            {
                _junk2.Add(new Junk { Junk1 = "Prop2a-" + i, Junk2 = "Prop2b-" + i });
            }
        }

        private readonly ObservableCollection<Junk> _junk1;

        private readonly ObservableCollection<Junk> _junk2;

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            cbo.ItemsSource = _junk1;
        }

        private void btn_Click(object sender, RoutedEventArgs e)
        {
            if (cbo.ItemsSource == _junk1)
            {
                cbo.ItemsSource = _junk2;
            }
            else
            {
                cbo.ItemsSource = _junk1;
            }
        }
    }

    public class Junk
    {
        public string Junk1 { get; set; }
        public string Junk2 { get; set; }
    }
}

これに対する解決策または回避策が見つかったら、ここに再度投稿します。

于 2011-09-22T11:06:05.607 に答える