滚动时ListBox引发ItemControl Text Visualizer错误

时间:2019-02-10 20:00:11

标签: wpf data-binding wpf-controls

我有一个列表框,下面的代码是我要填充的900个项目。当我快速向下滚动列表时,出现“ ItemsControl与它的项目来源不一致”的异常。关于导致问题的原因有什么想法?

                <ListBox x:Name="FileList" ItemsSource="{Binding Files}" ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" 
                     MaxHeight="520" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <CheckBox x:Name="FileChecked" IsChecked="{Binding Checked}" Grid.Column="0" BorderThickness="1"/>
                            <Label Content="{Binding Name}" Grid.Column="1" />
                            <Label Content="{Binding Source}" Grid.Column="2" Style="{StaticResource FileProperties}" />
                            <Label Content="{Binding Destination}" Grid.Column="3" Style="{StaticResource FileProperties}"/>
                            <Label Content="{Binding ArchiveLocation}" Grid.Column="4" Style="{StaticResource FileProperties}"/>
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

enter image description here

以下是该问题的视频。 https://www.screencast.com/t/YUlp24zoXiG

1 个答案:

答案 0 :(得分:0)

我相信我已经找到了问题。我在下面粘贴了有问题的代码,以便其他访问者可以从此答案中受益。

// Your code from GitHub unchanged
private async void Preview_Click(object sender, System.Windows.RoutedEventArgs e)
{
    vm.Files = new List<InstrumentFile>();

    try
    {
        for (int i = 0; i < InstrumentList.Items.Count; i++)
        {
            ListBoxItem lbi = (InstrumentList.ItemContainerGenerator.ContainerFromIndex(i)) as ListBoxItem;
            ContentPresenter cp = GetFrameworkElementByName<ContentPresenter>(lbi);
            DataTemplate dt = InstrumentList.ItemTemplate;
            CheckBox cb = (dt.FindName("InstrumentChecked", cp)) as CheckBox;

            if (cb.IsChecked == true)
            {
                List<InstrumentFile> instrumentFiles = new List<InstrumentFile>();
                Instrument instrument = ((Instrument)(InstrumentList.Items[i]));

                string[] files = Directory.GetFiles(instrument.FileSource);
                foreach (string file in files)
                {
                    FileInfo fi = new FileInfo(file);
                    instrumentFiles.Add(new InstrumentFile()
                    {
                        Name = fi.Name,
                        Source = instrument.FileSource,
                        Destination = instrument.Destination,
                        ArchiveLocation = instrument.ArchiveLocation
                    });
                }
                if (string.IsNullOrEmpty(instrument.FileExt) == false)
                {
                    IEnumerable<InstrumentFile> filteredFiles = instrumentFiles.Where(f => f.Name.ToUpper().EndsWith(instrument.FileExt.ToUpper()));
                    if (filteredFiles.Count() > 0)
                        vm.Files.AddRange(filteredFiles);
                }
                else
                {
                    if (instrumentFiles.Count > 0)
                        vm.Files.AddRange(instrumentFiles);
                }

            }
        }
    }
    catch (Exception ex)
    {
        await metroWindow.ShowMessageAsync("Exception Encountered", ex.Message, MessageDialogStyle.Affirmative, Helpers.DialogSettings());
    }
    FileCount.Content = vm.Files.Count.ToString() + " files";
}

在这里,您正在初始化视图模型中的Files属性。这将导致数据绑定更新为空列表。到目前为止没有问题。但是,您随后将内容添加到Files,但是这些更改不会传播到数据绑定系统,因为视图模型中的列表不是ObservableCollection

您可以通过两种方法解决此问题。一种修复方法是在创建并填充列表后的 视图模型中设置Files属性。新代码看起来像这样(缩写):

private async void Preview_Click(object sender, System.Windows.RoutedEventArgs e)
{
    // Create new variable to store the list
    var files = new List<InstrumentFile>();

    // You do a bunch of things, but you now add items to files, not to vm.Files
    files.AddRange(filteredFiles);

    // Finally, change Files
    vm.Files = files
}

最后一行将在视图模型中引发PropertyChanged事件,以更新数据绑定,但会使用完整的项目列表进行此操作。

第二种解决方法是将视图模型中Files的类型更改为ObservableCollection<InstrumentFile>。每当您更改Files时,都会引发正确的事件以更新数据绑定。