2013-07-05 17 views
11

Tôi có một điều khiển cây thể hiện hiệu suất rất kém và tôi đang cố gắng theo dõi nguồn gốc của sự cố.Hiệu suất chậm WPF - nhiều DataItem = cảnh báo ràng buộc null

Tôi cố gắng để làm việc hiểu xem những cảnh báo như sau đây là quan trọng:

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

Việc thực hiện cập nhật nội dung cây ngay cả với tất cả những diags tắt là thực sự khủng khiếp (hơn một giây để repopulate ~ 300 bài), đó là những gì bắt đầu tôi nhìn vào đầu ra dấu vết.

Các cảnh báo này được giải phóng bởi hàng tá cho mỗi nhấp chuột trong chế độ xem dạng cây của tôi và khi tôi chuyển đổi cây để hiển thị các nội dung khác nhau, hàng trăm cảnh báo này xuất hiện. Tuy nhiên, nội dung của cây luôn xuất hiện một cách chính xác được hiển thị để bối cảnh dữ liệu phải được đặt thành null chỉ một cách thoáng qua.

Tôi đặt một ràng buộc rõ ràng cho DataContext bằng trình chuyển đổi giá trị để thử và xem điều gì đang diễn ra.

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

... nhưng giá trị không bao giờ có vẻ bằng null vào đó.

Tôi có thể đặt giá trị dự phòng cho tất cả các ràng buộc để loại bỏ các cảnh báo này nhưng điều đó đặt nhiều mớ hỗn độn không cần thiết vào xaml và dường như nó ẩn vấn đề hơn là giải quyết nó (giả sử nó thậm chí còn là vấn đề!).

Vì vậy, câu hỏi của tôi là:

  1. Là những diags có khả năng gây ra vấn đề hiệu suất?
  2. Nếu có, việc cung cấp các giá trị dự phòng có tạo ra bất kỳ sự khác biệt nào về hiệu suất khi các biểu đồ bị tắt không?
  3. Nếu có, có cách nào tốt hơn để thực hiện việc này hơn là đổ xaml bằng crud không?

Sửa

Sử dụng các giá trị dự phòng có vẻ như nó không phải là một giải pháp mà thôi vì nó cũng thất bại trong việc tìm kiếm các nguồn:

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

Nó giống như nó được quên tất cả mọi thứ có trong từ điển tài nguyên , tạo ra tất cả các lỗi giả mạo này và sau đó ghi nhớ tất cả lại và hiển thị ok.

Sửa

Ok, tôi đã thu hẹp này xuống một chút nữa bằng cách bình luận ra tất cả các cam kết ràng buộc và đưa chúng trở lại trong từng người một và giải quyết các vấn đề trên đường đi vì vậy bây giờ nó tải và tôi có thể nhấp thông qua các vật phẩm và không có miếng lót được sản xuất cho đến khi ... Khi tôi nhấp vào nút thay đổi các mục cây, nó phát điên và phát hiện ra hàng trăm lỗi. Đây là một tập con nhỏ của các lỗi:

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

Nếu tôi thay đổi nút xử lý để chỉ đặt ItemsSource vào danh sách trống thì nó sẽ tạo cùng một tập hợp lỗi. Có vẻ như khi nguồn bị ngắt kết nối, WPF sẽ đánh giá lại tất cả các ràng buộc và như mong đợi tất cả chúng đều thất bại.

Sửa

Nói một cách đơn giản hơn ...

  • ItemsSource là ràng buộc để một ObservableCollection.
  • Tôi gọi Clear() trên ObservableCollection.
  • Tất cả các ràng buộc được đánh giá lại và không thể tìm thấy dữ liệu của họ nữa (vì nó được loại bỏ)
  • Cuối cùng tất cả các mục được loại bỏ

Tại sao những cam kết ràng buộc được đánh giá lại? Có cách nào để có được nó để loại bỏ các mục mà không có tất cả những công việc phụ?

Sửa

Tôi đã tạo ra một dự án mà thể hiện một phần của vấn đề. Nó tạo ra các lỗi phàn nàn rằng các tài nguyên không thể được tìm thấy khi gọi Clear() nhưng nó không tạo ra các thông điệp dataItem = null. Tôi sẽ tiếp tục cố gắng tái sản xuất chúng với ví dụ đơn giản. Đáng tiếc là tôi đang bị chặn từ pastebin và như vậy bởi các bức tường lửa vì vậy đây là mã mà được thay đổi từ các ứng dụng WPF chuẩn ...

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, tôi cũng đang sử dụng .NET 3.5 (tôi phải không may) nhưng vấn đề này đã xuất hiện với .NET 4.0 cũng vậy.

Tôi cũng có hai hình ảnh trong dự án:

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

Sửa

Cố gắng thay đổi ObjectDataProvider sử dụng DynamicResource:

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

Nhưng điều đó tạo ra ngoại lệ này:

Exception generated using DynamicResource for model

+0

bạn đã làm điều gì đó với 'ContextMenu.IsOpen'? và hiện 'Img_Folder_Closed_Ex' tồn tại ở đâu đó? – WiiMaxx

+0

Tất cả các tài nguyên đều tồn tại và tất cả chúng đều được tìm thấy (cuối cùng). Vấn đề là khi các mục đang thay đổi và WPF vô nghĩa đánh giá lại các ràng buộc mà dữ liệu đã biến mất. –

+0

nếu bạn gọi rõ ràng bảng dữ liệu của bạn sẽ chỉ biến mất và không phát điên vì 'no Hierarchi == no HierarchicalDataTemplate'. Có vẻ như bạn cần cung cấp thêm mã hoặc bạn cũng có thể xây dựng một phiên bản đơn giản để xem liệu hành vi có giống nhau hay không hoặc đăng hoặc liên kết mã đầy đủ của ví dụ đơn giản – WiiMaxx

Trả lời

8

tôi đã được quản lý để thoát khỏi của tất cả các lỗi ràng buộc!

Tôi không chắc tại sao nhưng thêm tài nguyên vào Application.Resources thay vì sử dụng UserControl.Resources đã giải quyết lỗi Resource not found. Điều này là xa một giải pháp lý tưởng (nó sẽ là đẹp hơn nhiều để quản lý tài nguyên người dùng phạm vi để kiểm soát người dùng) nhưng nó hoạt động.

Tất cả các lỗi loại khác dataItem=null được phân giải bằng cách cung cấp giá trị dự phòng trong các kết buộc khác nhau.

Điều này đã giải quyết vấn đề hiệu suất đã bắt đầu câu hỏi này để câu trả lời cho câu hỏi ban đầu của tôi là sửa lỗi ràng buộc tạo sự khác biệt lớn cho hiệu suất. Bây giờ tôi đã cố định các ràng buộc, cập nhật cây của tôi gần như ngay lập tức thay vì tham gia một giây :)

Rất cám ơn sự giúp đỡ!

Jeremy

Các vấn đề liên quan