2013-07-05 9 views
11

Ho un controllo ad albero che mostra prestazioni molto scarse e sto cercando di rintracciare la fonte del problema.WPF prestazioni lente - molti DataItem = avvisi di associazione nulli

Sto cercando di capire se gli avvertimenti come la seguente sono importanti:

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') 

Le prestazioni di aggiornamento dei contenuti degli alberi anche con tutti questi diags spento è davvero terribile (oltre un secondo per ripopolare ~ 300 articoli), che è quello che mi ha iniziato a guardare l'output della traccia.

Questi avvisi vengono emessi ogni volta da una dozzina per ogni clic nella mia vista ad albero e quando si passa all'albero per visualizzare contenuti diversi, si verificano diverse centinaia di questi avvisi. Tuttavia, i contenuti dell'albero vengono sempre visualizzati correttamente, pertanto il contesto dei dati deve essere impostato su null solo transitoriamente.

Ho inserito un binding esplicito per DataContext con un convertitore di valori per provare a vedere cosa sta succedendo.

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

... ma il valore non sembra mai uguale a null che entra in là.

Potrei impostare un valore di fallback per tutti gli attacchi per sbarazzarsi di questi avvertimenti ma questo mette un sacco di disordine inutile in xaml e sembra che stia nascondendo il problema piuttosto che risolverlo (presumendo che sia anche un problema!).

Quindi la mia domanda è:

  1. sono questi diags che possono causare il problema di prestazioni?
  2. In tal caso, fornire valori di fallback può influire sulle prestazioni quando i diags sono disattivati?
  3. Se è così, c'è un modo migliore per farlo rispetto al riempimento di xaml con crud?

Modifica

Utilizzando valori di ripristino sembra che non è una soluzione in ogni caso perché è anche non riuscendo a trovare risorse:

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

E 'come se si sta dimenticando tutto nel dizionario risorse , generando tutti questi errori spuri e poi ricordando tutto di nuovo e mostrando ok.

Modifica

Ok, ho ristretto questo giù un po 'più da commentando tutte le associazioni e la loro messa di nuovo in uno per uno e risolvere i problemi lungo la strada quindi ora è carica e posso cliccare attraverso gli oggetti e senza diags sono prodotti fino a ... Quando clicco sul pulsante che cambia gli elementi dell'albero impazzisce e vomita centinaia di errori. Ecco un piccolo sottoinsieme degli errori:

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.Windows.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') 

Se cambio il gestore di pulsante per impostare solo ItemsSource ad una lista vuota allora genera la stessa serie enorme di errori. Sembra che quando la fonte viene disconnessa, WPF rivaluta tutti i binding e come ci si aspetterebbe che falliscano tutti.

Modifica

Per dirla più semplicemente ...

  • ItemsSource è associata a un ObservableCollection.
  • Io chiamo Clear() su ObservableCollection.
  • Tutte le associazioni sono rivalutati e non riescono a trovare i loro dati più (perché è stato rimosso)
  • In ultima analisi tutti gli elementi vengono rimossi

Perché quei binding essere rivalutati? C'è un modo per farlo rimuovere gli oggetti senza tutto quel lavoro extra?

Modifica

ho creato un progetto che presenta una parte del problema. Genera errori lamentando che non è possibile trovare risorse quando si chiama Clear() ma non produce i messaggi dataItem = null. Continuerò a provare a riprodurre quelli con il semplice esempio. Purtroppo sto bloccato e pastebin e simili dal firewall: ecco il codice che viene modificato dalla applicazione standard 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, sto anche usando .NET 3.5 (devo purtroppo) ma questo problema si è presentato con la Anche .NET 4.0.

Ho anche due immagini nel progetto:

VS11_Light_Folder_Closed_In.png (VS11_Light_Folder_Closed_In.png) VS11_Light_Folder_Open_In.png (VS11_Light_Folder_Open_In.png)

Modifica

provato a cambiare il ObjectDataProvider di utilizzare DynamicResource:

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

Ma che ha generato questa eccezione:

Exception generated using DynamicResource for model

+0

hai fatto qualcosa con il 'ContextMenu.IsOpen'? e 'Img_Folder_Closed_Ex' esiste da qualche parte? – WiiMaxx

+0

Le risorse esistono tutte e sono tutte trovate (eventualmente). Il problema è che gli elementi cambiano e WPF rivaluta inutilmente i collegamenti per i quali i dati sono andati. –

+0

se chiami clear i tuoi Datatemplates dovrebbero sparire e non impazzire perché 'no Hierarchi == no HierarchicalDataTemplate'. Sembra che tu debba fornire più codice o potresti anche creare una versione semplice e guardare se il comportamento è lo stesso e pubblicare o collegare il codice completo dell'esempio semplice – WiiMaxx

risposta

8

sono riuscito a sbarazzarsi di tutti gli errori vincolanti!

io non so perché, ma aggiungendo le risorse in Application.Resources invece di utilizzare UserControl.Resources ha risolto i Resource not found errori. Questo è lontano da una soluzione ideale (sarebbe molto più bello mettere le risorse del controllo dell'utente sul controllo utente) ma funziona.

Tutti gli altri errori di tipo dataItem=null erano risolvibili fornendo valori di fallback nei vari bind.

Questo ha risolto il problema di prestazioni che ha dato inizio a questa domanda in modo che la risposta alla mia domanda iniziale sia che che corregge gli errori di associazione faccia una grande differenza per le prestazioni. Ora ho risolto i binding, i miei aggiornamenti dell'albero sono quasi istantanei invece di occupare un secondo :)

Mille grazie per l'aiuto!

Jeremy

Problemi correlati