0

我有一个数据网格(称为 dat1),它的项目源绑定到自定义类型的可观察集合,称为 TypeA。TypeA 的属性之一是另一个自定义类型的可观察集合,称为 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。当 items 源更改为 junk2 时延迟更长,大概是因为它更大。

它延迟得足够多,我认为它可能是由绑定异常引起的,因为异常需要时间。有没有办法查看是否抛出了绑定异常?

4

1 回答 1

0

我也观察到这种现象。我在 Windows 7 x64 上使用 Visual Studio 2010(带有 ReSharper 6.0)。

如上例所示,只有四个项目并不明显,但如果我将其设为例如 50 个或更多项目,则冻结变得非常明显。重新绑定后,它会挂起大约 15 秒,然后我才能再次与它交互。

另一个有趣的事情是,这只发生在 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 回答