Long List Selector Observable Collection and Visua

2019-01-15 22:29发布

问题:



I've made a short example to show where I've encoutered some problems. They concers LongsListSelector bound to ObservableCollection (no matter what type items are). I've set long list item template as (for example) a textblock, I've also made three buttons - to add one element to collection, to remove one last, and to search through visuall tree. The code is not so long so I'll post it here below (if you want whole example it's at: http://sdrv.ms/163TYEG ).

XAML (except headers):

    <phone:PhoneApplicationPage.Resources>
    <DataTemplate x:Key="ElementStyle">
        <TextBlock x:Name="elemBlck" Text="Element"/>
    </DataTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="30*"/>
        <RowDefinition Height="30*"/>
        <RowDefinition Height="30*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="70*"/>
        <ColumnDefinition Width="30*"/>
    </Grid.ColumnDefinitions>

    <Button x:Name="addBtn" Content="Add" Grid.Row="0" Grid.Column="1"/>
    <Button x:Name="delBtn" Content="Del" Grid.Row="1" Grid.Column="1"/>
    <Button x:Name="showBtn" Content="Show" Grid.Row="2" Grid.Column="1"/>       
    <phone:LongListSelector x:Name="phoneLLS" HorizontalAlignment="Left" Height="700" Margin="0" Grid.Row="0" 
                            VerticalAlignment="Top" Grid.RowSpan="3" Grid.Column="0" Width="300"
                            LayoutMode="Grid" GridCellSize="300,100" IsGroupingEnabled="False"
                            ItemTemplate="{StaticResource ElementStyle}" />
</Grid>

and C#:

 public partial class MainPage : PhoneApplicationPage
 {
  private ObservableCollection<string> collection = new ObservableCollection<string>();

  public MainPage()
  {
     InitializeComponent();
     phoneLLS.ItemsSource = collection;
     addBtn.Click += addBtn_Click;
     delBtn.Click += delBtn_Click;
     showBtn.Click += showBtn_Click;
  }

  private void addBtn_Click(object sender, RoutedEventArgs e)
  {
     collection.Add("element");
  }

  private void delBtn_Click(object sender, RoutedEventArgs e)
  {
     collection.RemoveAt(collection.Count - 1);
  }

  private void showBtn_Click(object sender, RoutedEventArgs e)
  {
     List<TextBlock> controlList = new List<TextBlock>();
     SearchForControls<TextBlock>(phoneLLS, ref controlList);
  }

  private static void SearchForControls<T>(DependencyObject parent, ref List<T> controlList) where T : DependencyObject
  {
     int numberOfChildreen = VisualTreeHelper.GetChildrenCount(parent);
     for (int i = 0; i < numberOfChildreen; i++)
     {
        var child = VisualTreeHelper.GetChild(parent, i);

        if (child is T)
           controlList.Add((T)child);
        else SearchForControls<T>(child, ref controlList);
     }
  }
}

Where are problems?

  1. When I push button 'add', the collection is enlarged by one element. Ok, I see it becouse element item is added in LLS. But try to push it more. After that within one button push few elements appear? What's wrong? Collection is enlarged by one element but LLS is populated much faster.

  2. The same with delete - it deletes one element but from LLS a group of items sometimes dissapear.

  3. And the main problem - toggle a breakpoint at second line of showBtn_Click. Add some elements, try to search visual tree (push show button). The debug stops and after the second line you see the exact numer of elements within the visual tree (which differs from collection.Count). And the second big surprise - when you delete en element, and search once again visual tree, then you'll see that: collection was decresed (which is right), some elements dissapeard from LLS (should one), and! - the number of Visual tree elements didn't changed (!). What's wrong?

    Are these some kind of a bug? Or maybe I don't understand something?

回答1:

Try to set data context to your List and use Bindings in ItemsSource property.

Xaml:

<phone:LongListSelector ItemsSource={Binding} x:Name="phoneLLS"  HorizontalAlignment="Left" Height="700" Margin="0" Grid.Row="0" 
                        VerticalAlignment="Top" Grid.RowSpan="3" Grid.Column="0" Width="300"
                        LayoutMode="Grid" GridCellSize="300,100" IsGroupingEnabled="False"
                        ItemTemplate="{StaticResource ElementStyle}" />

Code Behind:

public partial class MainPage : PhoneApplicationPage
{
   private ObservableCollection<string> collection = new ObservableCollection<string>();
   public MainPage()
   {
     InitializeComponent();
     phoneLLS.DataContext = collection;
     addBtn.Click += addBtn_Click;
     delBtn.Click += delBtn_Click;
     showBtn.Click += showBtn_Click;
   }
   ...
}

Let me know if this works.



回答2:

I've also made some further research - that if you reenter the page with LLS everything is updated correct - Visual tree has that many elements like collection. I've modified an example (http://sdrv.ms/169kRqI ):

Let's make Main_Page the second_page:

Xaml:

<phone:PhoneApplicationPage.Resources>
    <DataTemplate x:Key="ElementStyle">
        <TextBlock x:Name="elemBlck" Text="Element"/>
    </DataTemplate>
</phone:PhoneApplicationPage.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="30*"/>
        <RowDefinition Height="30*"/>
        <RowDefinition Height="30*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="70*"/>
        <ColumnDefinition Width="30*"/>
    </Grid.ColumnDefinitions>

    <Button x:Name="addBtn" Content="Add" Grid.Row="0" Grid.Column="1"/>
    <Button x:Name="delBtn" Content="Del" Grid.Row="1" Grid.Column="1"/>
    <Button x:Name="showBtn" Content="Show" Grid.Row="2" Grid.Column="1"/>
    <phone:LongListSelector x:Name="phoneLLS" HorizontalAlignment="Left" Height="700" Margin="0" Grid.Row="0" 
                            VerticalAlignment="Top" Grid.RowSpan="3" Grid.Column="0" Width="300"
                            LayoutMode="Grid" GridCellSize="300,100" IsGroupingEnabled="False"
                            ItemTemplate="{StaticResource ElementStyle}" ItemsSource="{Binding}"/>

</Grid>

code behind:

public partial class second_page : PhoneApplicationPage
{
  public second_page()
  {
     InitializeComponent();
     phoneLLS.DataContext = MainPage.collection;
     addBtn.Click += addBtn_Click;
     delBtn.Click += delBtn_Click;
     showBtn.Click += showBtn_Click;
  }

  private void addBtn_Click(object sender, RoutedEventArgs e)
  {
     MainPage.collection.Add("element");
  }

  private void delBtn_Click(object sender, RoutedEventArgs e)
  {
     MainPage.collection.RemoveAt(MainPage.collection.Count - 1);
  }

  private void showBtn_Click(object sender, RoutedEventArgs e)
  {
     List<TextBlock> controlList = new List<TextBlock>();
     SearchForControls<TextBlock>(phoneLLS, ref controlList);
  }

  private static void SearchForControls<T>(DependencyObject parent, ref List<T> controlList) where T : DependencyObject
  {
     int numberOfChildreen = VisualTreeHelper.GetChildrenCount(parent);
     for (int i = 0; i < numberOfChildreen; i++)
     {
        var child = VisualTreeHelper.GetChild(parent, i);

        if (child is T)
           controlList.Add((T)child);
        else SearchForControls<T>(child, ref controlList);
     }
  }
}

and Main_Page - only navigation:

Xaml:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <Button x:Name="goToPage" Content="SecondPage" Width="Auto" Height="Auto"
            HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>

Code behind:

public partial class MainPage : PhoneApplicationPage
{
  public static ObservableCollection<string> collection = new ObservableCollection<string>();

  public MainPage()
  {
     InitializeComponent();
     goToPage.Click+=goToPage_Click;
  }

  private void goToPage_Click(object sender, RoutedEventArgs e)
  {
     NavigationService.Navigate(new Uri("/second_page.xaml", UriKind.Relative));
  }
}

Just try to do the same with and without reentering the page:

  1. add for example 3 elements, with debugger toggle a breakpoint at second line of showBtn_Click and Click the buton - it will show 6 elements! Do not touch anything except go back.

  2. Reenter the second page - you will se the correct LLS - with 3 elements as you click showBtn with breakpoint you will see 3 elements in the Visual Tree.

    Anybody tried this?