2017-12-04 2 views
0

Ich versuche zu lernen ObservableCollection<T> und ListBox VirtualizingStackPanel.WPF ListBox, ruft gebunden Eigenschaft zweimal

Es gibt ein Bild innerhalb MyTestData Klasse, gebunden an Image (Thumbnail-Eigenschaft) innerhalb der ListBox.ItemTemplate. Das Problem ist, die Thumbnail Eigenschaft wird zweimal aufgerufen, wenn ich scrollte. Ist das ein Problem oder wie funktioniert WPF?

Fenster:

<Window x:ClassModifier="internal" x:Class="Virtual.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    Title="MainWindow" SizeToContent="Height" Width="525" WindowStartupLocation="CenterScreen"> 
<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"></ColumnDefinition> 
     <ColumnDefinition Width="*"></ColumnDefinition> 
    </Grid.ColumnDefinitions> 

    <StackPanel Orientation="Vertical"> 
     <Button x:Name="btnAdd1" Content="Add 1" Click="btnAdd_Click"></Button> 
     <Button x:Name="btnAdd10" Content="Add 10" Click="btnAdd_Click"></Button> 
     <Button x:Name="btnAdd100" Content="Add 100" Click="btnAdd_Click"></Button> 
     <Button x:Name="btnAdd1000" Content="Add 1000" Click="btnAdd_Click"></Button> 
     <Button x:Name="btnAdd1000000" Content="Add 1.000.000" Click="btnAdd_Click"></Button> 
     <TextBox x:Name="tbDebug" Margin="0,10,0,25" Height="250" AcceptsReturn="True"> 

     </TextBox> 

    </StackPanel> 
    <Button x:Name="btnAdd" Content="Add" VerticalAlignment="Bottom" Click="btnAdd_Click"></Button> 

    <ListBox x:Name="lbList2" Margin="10,0,0,25" Height="350" 
     Grid.Column="1" 
     ScrollViewer.CanContentScroll="True" 
     ScrollViewer.IsDeferredScrollingEnabled="False" 
     VirtualizingStackPanel.IsVirtualizing="True" 
     VirtualizingStackPanel.VirtualizationMode="Recycling"> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <VirtualizingStackPanel></VirtualizingStackPanel> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <StackPanel Orientation="Horizontal"> 
        <Border Margin="3,0,0,0" BorderBrush="Black" BorderThickness="1"> 
         <Image VerticalAlignment="Top" HorizontalAlignment="Left" MaxWidth="30" MaxHeight="30" SnapsToDevicePixels="True" Source="{Binding Thumbnail, UpdateSourceTrigger=PropertyChanged}" /> 
        </Border> 
        <Label Content="{Binding Name}"></Label> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 

    <Button x:Name="btnAdd2" Margin="10,0,0,0" Grid.Column="1" Content="Add" VerticalAlignment="Bottom" Click="btnAdd_Click"></Button> 
</Grid> 
</Window> 

Code:

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
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 Virtual 
{ 
    internal class MyTestData 
    { 
     public string Name { get; set; } 

     private BitmapSource _thumbnail = null; 
     public BitmapSource Thumbnail 
     { 
      get 
      { 
       if (_thumbnail == null) 
        _thumbnail = new BitmapImage(new Uri("c:\\300.jpg")); 

       Console.Text += "\n" + Name + " --> THUMBNAIL"; 
       Console.ScrollToEnd(); 

       return _thumbnail; 
      } 
     } 

     public MyTestData(string oName) 
     { 
      Name = oName; 
     } 

     internal TextBox Console; 
    } 

    internal partial class MainWindow : Window 
    { 
     public List<string> OItems1 { get; set; } 
     public ObservableCollection<MyTestData> OItems2 { get; set; } 

     public MainWindow() 
     { 
      InitializeComponent(); 

      OItems1 = new List<string>(); 
      OItems2 = new ObservableCollection<MyTestData>(); 

      lbList2.ItemsSource = OItems2; 
     } 

     private void OAdd(int c) 
     { 
      for (int i = 0; i < c; i++) 
      { 
       OItems2.Add(new MyTestData("oDATA = " + (OItems2.Count + 1).ToString()) 
       { 
        Console = tbDebug 
       }); 
      } 
     } 

     private void btnAdd_Click(object sender, RoutedEventArgs e) 
     { 
      if (sender == btnAdd1) 
       OAdd(1); 
      else if (sender == btnAdd10) 
       OAdd(10); 
      else if (sender == btnAdd100) 
       OAdd(100); 
      else if (sender == btnAdd1000) 
       OAdd(1000); 
      else if (sender == btnAdd1000000) 
       OAdd(1000000); 
     } 
    } 
} 
+0

Als Hinweis, Einstellung 'UpdateSourceTrigger = PropertyChanged' auf der Thumbnail Binding ist sinnlos. Es wirkt sich nur auf TwoWay- oder OneWayToSource-Bindungen aus. Außerdem ist das explizite Deklarieren eines VirtualizingStackPanel ebenfalls überflüssig. ListBox verwendet standardmäßig eine. – Clemens

Antwort

1

Ist das ein Problem oder wie WPF funktioniert?

Letzteres. Bitte beachten Sie die folgende Antwort von Microsoft unter Connect:

Das Framework (oder jemand anderes) ist berechtigt, den Property-Getter so oft wie er will, aus irgendeinem Grund. Es gibt keine Garantie, dass es nur einmal aufgerufen wird.

unerwartetes Verhalten: Bindungs ​​Motor bekommen Image zweimal:https://connect.microsoft.com/VisualStudio/feedback/details/770169/unexpected-behaviour-binding-engine-getting-imagesource-twice

Also dieses Verhalten erwartet wird.

+0

Weird :) Also, danke! – cKNet