当项目源更改时,是什么导致我的 WPF 组合框项目需要很长时间才能刷新?

发布于 2024-10-06 19:01:17 字数 2263 浏览 0 评论 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 答案。

附言。当项目源更改为 junk2 时,延迟会更长,大概是因为它更大。

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

I have a datagrid (call it dat1) that has an items source bound to an observable collection of a custom type, call it TypeA. One of the properties on TypeA is an observable collection of another custom type, call it TypeB. I then have a combobox with an items source bound to dat1's SelectedItem.TypeB.

So when the user selects a TypeA in dat1, the combobox shows the items in the TypeB observable collection from the selected TypeA. Make sense?

The binding DOES work and it DOES update. The problem is that when the items presenter in the combobox has already displayed items and the user selects a different TypeA in dat1 and tries to view the new items in the combobox, there is a long pause while the items presenter generates the new items.

To test the problem, I can simplify the scenario.

Steps to reproduce:

  1. Create a new WPF project using .NET 4.0.

  2. Cut and Paste the code below.

  3. To get the freezing behavior, you must drop the combobox to see the items, then click the button so the items source changes, and then drop the combobox again. The combobox drops after a few seconds, but why so slow?

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>

Code

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; }
}

NOTE: This is a WPF problem. I've heard Silverlight doesn't have the same issue. I don't need to know if Silverlight works. I need a WPF answer.

PS. The delay is longer when the items source is changed to junk2, presumably because it is larger.

It delays enough that I think it may be caused by binding exceptions, since exceptions take time. Is there a way to see if there are binding exceptions being thrown?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

无风消散 2024-10-13 19:01:17

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

如上例所示,只有 4 个项目时,这种情况并不明显,但如果我将其设置为 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; }
    }
}

如果我找到解决方案或解决方法,我将再次在此发布。

I observe this phenomenon too.
I'm using Visual Studio 2010 (with ReSharper 6.0) on Windows 7 x64.

It's not noticeable with only four items as in the example above, but if I make it e.g. 50 or more items the freeze gets very noticeable.
After the rebinding it will then hang for about 15 seconds before I'm allowed to interact with it again.

Another interesting thing is that this only happens while debugging in VS. If I run the exe standalone it is really snappy and fast.

Here is the code from my simple project:

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>

Code

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; }
    }
}

I will post here again if I find a solution or workaround to this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文