将项添加到ObservableCollection时窗口冻结

时间:2013-06-14 18:09:59

标签: wpf data-binding mvvm datagrid observablecollection

我有一个绑定到ObservableCollection ProductsFound的DataGrid 它在我的ViewModel中作为属性公开。 通过在TextBox中键入文本,模型中包含的包含TextBox中插入的文本的Code属性的产品将添加到ProductsFound。

我发现如果DataGrid包含在任何控件(如StackPanel或TabItem)中,当我尝试在TextBox中键入文本时,Window(程序)会停止响应;如果DataGrid未包含在任何控件中,则一切都正常运行。

这是窗口的代码:

public class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        // This method just fill the dataset I pass to the model's contructor in the next line.
        Init();
        ProductsModel model = new ProductsModel(dataSet);
        searchViewModel = new ProductsSearchViewModel(model);

        DataContext = searchViewModel;           
    }

    private ProductsSearchViewModel searchViewModel;

   // This handler supports the binding between the TextBox and the MatchText property of the View Model.
    private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        var binding = ((TextBox)sender).GetBindingExpression(TextBox.TextProperty);
        binding.UpdateSource();
    }

}

这是我的ViewModel:

public class ProductsSearchViewModel : Notifier, IProductsSearchViewModel
{
    public ProductsSearchViewModel(IProductsModel inModel)
    {
        model = inModel;
        productsFound = new ObservableCollection<ProductViewModel>();       
    }

    private string matchText;
    private IProductsModel model;
    private ObservableCollection<ProductViewModel> productsFound;

    // This is a helper method that search for the products in the model and adds them to ProductsFound.
    private void Search(string text)
    {
        Results.Clear();

        foreach (Product product in model.Products)
        {                
            if (product.Code.ToLower().Contains(text.ToLower()))
                Results.Add(new ProductViewModel(product));
        }
    }

    public string MatchText
    {
        get { return matchText; }

        // This setter is meant to be executed every time the Text property of the TextBox is changed.
        set
        {
            if ((value != matchText) && (value != ""))
            {
                matchText = value;

                // This raises INotifyPropertyChanged.PropertyChaged.
                NotifyPropertyChanged("MatchText");
                Search(value);                  
            }
        }
    }

    public ObservableCollection<ProductViewModel> ProductsFound
    {
        get
        {
            return productsFound;
        }
        set
        {
            productsFound = value;
            NotifyPropertyChanged("Results");
        }
    }
}

这是XAML:

<Window x:Class="MyNameSpace.UI.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">
<Grid>
    <StackPanel>
        <TextBox Text="{Binding MatchText, Mode=TwoWay}" TextChanged="TextBox_TextChanged"  />
        <DataGrid x:Name="grid1" ItemsSource="{Binding Results}" >
    </StackPanel>
</Grid>

使用该StackPanel,当我尝试在文本框中键入文本并且没有任何项添加到DataGrid时程序停止响应;但如果我删除它一切都运行正常。 问题是什么?我是否遗漏了WPF绑定系统的工作原理? 我的视图模型编码错了吗?

提前致谢。

1 个答案:

答案 0 :(得分:2)

StackPanel放在那里会阻止DataGrid获取特定的Height,因此它会向下扩展到无穷大,从而打破了UI虚拟化。

从那里移除StackPanel并使用非无限容器,例如GridDockPanel