Низкая производительность WPF - много DataItem = предупреждения о нулевой привязке

У меня есть элемент управления дерева, который показывает очень низкую производительность, и я пытаюсь отследить источник проблемы.

Я пытаюсь понять, важны ли такие предупреждения, как следующее:

System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=ContextMenu.IsOpen; DataItem=null; target element is 'MultipleSelectionTreeViewItem' (Name=''); target property is 'NoTarget' (type 'Object')

Производительность обновления содержимого дерева, даже когда все эти диагнозы выключены, действительно ужасна (более секунды, чтобы заново заполнить ~ 300 элементов), и именно это заставило меня посмотреть на вывод трассировки.

Эти предупреждения издаются дюжиной для каждого клика в моем дереве, и когда я переключаю дерево, чтобы отобразить различное содержимое, возникает несколько сотен таких предупреждений. Однако содержимое дерева всегда отображается правильно, поэтому контекст данных должен быть установлен на ноль только временно.

Я поставил явную привязку дляDataContext с конвертером значений, чтобы попытаться увидеть, что происходит.

<HierarchicalDataTemplate x:Key="HierarchyItemTemplate"
                          DataType="{x:Type local:HierarchyItem}"
                          ItemsSource="{Binding Children}">
    <StackPanel DataContext="{Binding Converter={StaticResource DbgConverter}}" Orientation="Horizontal">
       ...
    </StackPanel>
</HierarchicalDataTemplate>

... но значение никогда не кажется равным нулю, поступающему туда.

Я мог бы установить запасное значение для всех привязок, чтобы избавиться от этих предупреждений, но это создает много ненужного беспорядка в xaml и кажется, что он скрывает проблему, а не решает ее (предполагая, что это даже проблема!).

Итак, мой вопрос:

Эти диагнозы могут вызвать проблемы с производительностью?Если да, то будет ли предоставление запасных значений иметь какое-то значение для производительности при отключении диагоналей?Если так, то есть ли лучший способ сделать это, чем заполнить xaml crud?

редактировать

Использование резервных значений, похоже, не является решением, так как не удается найти ресурсы:

System.Windows.ResourceDictionary Warning: 9 : Resource not found; ResourceKey='Img_Folder_Closed_Ex'

Это как если бы вы забыли все в словаре ресурсов, сгенерировали все эти ложные ошибки, а затем снова запомнили все это и отобразили ok.

редактировать

Хорошо, я сузил это немного дальше, закомментировав все привязки и положив их обратно один за другим и решая проблемы по пути, так что теперь он загружается, и я могу нажимать по элементам, и никакие диагнозы не производятся до тех пор, пока ... Когда я нажимаю кнопку, которая меняет элементы дерева, она сходит с ума и выдает сотни ошибок. Вот небольшое подмножество ошибок:

System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Wi,ndows.Data Information: 41 : BindingExpression path error: 'IsFolder' property not found for 'object' because data item is null.  This could happen because the data provider has not produced any data yet. BindingExpression:Path=IsFolder; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 20 :System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=IsFolder; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=IsFolder; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.ResourceDictionary Warning: 9 : Resource not found; ResourceKey='Img_QA'
System.Windows.Data Information: 41 : BindingExpression path error: 'IsIncluded' property not found for 'object' because data item is null.  This could happen because the data provider has not produced any data yet. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
 BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=IsFolder; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=IsFolder; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=IsFolder; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 41 : BindingExpression path error: 'IsIncluded' property not found for 'object' because data item is null.  This could happen because the data provider has noSystem.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
t produced any data yet. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=IsIncluded; DataItem=null; target element is 'TreeViewItemIcon' (Name=''); target property is 'NoTarSystem.Windows.ResourceDictionary Warning: 9 : Resource not found; ResourceKey='Img_QA'
System.Windows.Data Information: 41 : BindingExpression path error: 'Name' property not found for 'object' because data item is null.  This could happen because the data provider has not produced any data yet. BindingExpression:Path=Name; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=Name; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 21 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=Name; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Name; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
get' (type 'Object')

Если я изменю обработчик кнопки, чтобы просто установить ItemsSource в пустой список, он генерирует тот же огромный набор ошибок. Похоже, что когда источник отключен, WPF переоценивает все привязки и, как и следовало ожидать, все они терпят неудачу.

редактировать

Проще говоря ...

ItemsSource привязан к ObservableCollection.Я вызываю Clear () для ObservableCollection.Все привязки переоцениваются и больше не могут найти свои данные (потому что они были удалены)В конечном итоге все предметы удалены

Почему эти привязки переоцениваются? Есть ли способ заставить его убирать предметы без всякой дополнительной работы?

редактировать

Я создал проект, который демонстрирует часть проблемы. Он генерирует ошибки, сообщающие, что ресурсы не могут быть найдены при вызове Clear (), но он не создает сообщения dataItem = null. Я буду продолжать пытаться воспроизвести их на простом примере. К сожалению, я заблокирован от pastebin и тому подобного брандмауэром, так что вот код, который отличается от стандартного приложения WPF ...

App.xaml:

<Application x:Class="ObservableCollectionTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <Style x:Key="{x:Type TreeViewItem}" TargetType="{x:Type TreeViewItem}">
            <Setter Property="HorizontalContentAlignment" Value="Left" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
        </Style>
    </Application.Resources>
</Application>

MainWindow.xaml:

<Window x:Class="ObservableCollectionTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:l="clr-namespace:ObservableCollectionTest"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>

        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/ObservableCollectionTest;component/Theme.xaml" />
            </ResourceDictionary.MergedDictionaries>

            <l:Model x:Key="TheModel" />

        </ResourceDictionary>

    </Window.Resources>

    <Grid>
        <Grid.Resources>
            <ObjectDataProvider x:Key="TheModelProvider" ObjectInstance="{StaticResource TheModel}" />

            <HierarchicalDataTemplate
                x:Key="TheModelTemplate"
                DataType="{x:Type l:TestItem}"
                ItemsSource="{Binding Items}">
                <StackPanel Orientation="Horizontal">
                    <Image Style="{DynamicResource ImageStyle}" />
                    <Label>
                        <TextBlock Style="{DynamicResource TextBlockStyle}" Text="{Binding Name}" />
                    </Label>
                </StackPanel>
            </HierarchicalDataTemplate>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <TreeView
            ItemsSource="{Binding Source={StaticResource TheModelProvider}, Path=Items}"
            ItemTemplate="{StaticResource TheModelTemplate}"/>

        <Button
            Grid.Row="1"
            Height="30"
            Content="Empty the list"
            Click="EmptyTheList_Click" />
    </Grid>
</Window>

MainWindow.cs:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ObservableCollectionTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            PresentationTraceSources.DataBindingSource.Listeners.Add(
                    new ConsoleTraceListener());

            PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.All;

            InitializeComponent();
        }

        private void EmptyTheList_Click(object sender, RoutedEventArgs e)
        {
            (Resources["TheModel"] as Model).Items.Clear();
        }
    }
}

Model.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace ObservableCollectionTest
{
    class Model
    {
        public ObservableCollection<TestItem> Items { get; set; }

        public Model()
        {
            Items = new ObservableCollection<TestItem>()
            {
                new TestItem()
                {
                    Name = "TopLevel",
                    Items = new List<TestItem>()
                    {
                        new TestItem() { Name = "Item1", Items = new List<TestItem>() },
                        new TestItem()
                        {
                            Name = "Item2",
                            Items = new List<TestItem>()
                            {
                                new TestItem() { Name = "SubItem1", Items = new List<TestItem>() },
                                new TestItem() { Name = "SubItem2", Items = new List<TestItem>() },
                                new TestItem() { Name = "SubItem3", Items = new List<TestItem>() }
                            }
                        },
                        new TestItem() { Name = "Item3", Items = new List<TestItem>() },
                        new TestItem() { Name = "Item4", Items = new List<TestItem>() }
                    }
                }
            };
        }
    }

    class TestItem
    {
        public string Name { get; set; }

        public bool IsRoot { get { return Name == "TopLevel"; } }

        public List<TestItem> Items { get; set; }
    }
}

Theme.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="/ObservableCollectionTest;component/Common.xaml" />
    </ResourceDictionary.MergedDictionaries>

    <BitmapImage x:Key="Img_Folder_Open_In" UriSource="/ObservableCollectionTest;component/VS11_Light_Folder_Open_In.png" />
    <BitmapImage x:Key="Img_Folder_Closed_In" UriSource="/ObservableCollectionTest;component/VS11_Light_Folder_Closed_In.png" />

</ResourceDictionary>

Common.xaml:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Style x:Key="TextBlockStyle" TargetType="TextBlock">
        <Setter Property="Foreground" Value="Blue" />
        <Setter Property="Background" Value="Yellow" />

        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Name}" Value="TopLevel" />
                    <Condition Binding="{Binding IsExpanded, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}}, FallbackValue=False}" Value="True" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Background" Value="Red" />
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

    <Style x:Key="ImageStyle" TargetType="{x:Type Image}">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding IsRoot}" Value="False" />
                    <Condition Binding="{Binding IsExpanded, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}}, FallbackValue=False}" Value="True" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Source" Value="{DynamicResource Img_Folder_Open_In}" />
            </MultiDataTrigger>

            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding IsRoot}" Value="False" />
                    <Condition Binding="{Binding IsExpanded, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TreeViewItem}}, FallbackValue=False}" Value="False" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Source" Value="{DynamicResource Img_Folder_Closed_In}" />
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>

</ResourceDictionary>

FWIW, я также использую .NET 3.5 (я, к сожалению, должен), но эта проблема появилась и в .NET 4.0.

У меня также есть два изображения в проекте:

редактировать

Пытался поменятьObjectDataProvider&nbsp;использовать DynamicResource:

<ObjectDataProvider x:Key="TheModelProvider" ObjectInstance="{DynamicResource TheModel}" />

Но это породило это исключение: