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:
Create a new WPF project using .NET 4.0.
Cut and Paste the code below.
To get the freezing behavior, you must drop the combobox to see the items, then click the button so the items source changes, an开发者_如何学Pythond 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?
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.
精彩评论