2017-09-19 2 views
2

In meiner UWP-Anwendung habe ich eine ListView mit inkrementellen Laden. Jetzt muss ich auch ein Bild in die ListViewItem aufnehmen. Ich habe versucht, es direkt die URI zu geben.Anzeigen von Bildern aus dem Internet asynchron

wo ThumbnailImage ist nur eine Zeichenfolge in meinem View-Modell. Das Problem dabei ist, dass die App durch inkrementelles Laden, wenn ich ein wenig nach unten scrolle, während die vorherigen Bilder noch geladen werden, einfach hängen bleibt. Während, wenn ich alle Bilder erscheinen lasse und dann nach unten scrolle, funktioniert es gut.

Ich habe auch versucht, die ImageEx Kontrolle aus dem Toolkit und es hat das gleiche Problem.

Ich habe einige Suche das einzige, was ich fand, war doing IsAsync = True in XAML. Aber es scheint, dass IsAsync nicht in UWP verfügbar ist.

Meine Viewmodel:

public class MyViewModel 
{ 
    ... 
    public string ThumbnailImage { get; set; } 
    ... 
} 

Meine XAML ListView die inkrementell

<ListView Grid.Row="0"    
     SelectionMode="Single" 
     IsItemClickEnabled="True" 
     ItemClick="SearchResultListView_ItemClick" > 

    <ListView.ItemContainerStyle> 
     <Style TargetType="ListViewItem"> 
      <Setter Property="HorizontalContentAlignment" Value="Stretch"/> 
      <Setter Property="BorderBrush" Value="Gray"/> 
      <Setter Property="BorderThickness" Value="0, 0, 0, 1"/> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="ListViewItem"> 
         <ListViewItemPresenter 
          ContentTransitions="{TemplateBinding ContentTransitions}" 
          SelectionCheckMarkVisualEnabled="True" 
          CheckBrush="{ThemeResource SystemControlForegroundBaseMediumHighBrush}" 
          CheckBoxBrush="{ThemeResource SystemControlForegroundBaseMediumHighBrush}" 
          DragBackground="{ThemeResource ListViewItemDragBackgroundThemeBrush}" 
          DragForeground="{ThemeResource ListViewItemDragForegroundThemeBrush}" 
          FocusBorderBrush="{ThemeResource SystemControlForegroundAltHighBrush}" 
          FocusSecondaryBorderBrush="{ThemeResource SystemControlForegroundBaseHighBrush}" 
          PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" 
          PointerOverBackground="{ThemeResource SystemControlDisabledTransparentBrush}" 
          SelectedBackground="{ThemeResource SystemControlDisabledTransparentBrush}" 
          SelectedForeground="{ThemeResource SystemControlDisabledTransparentBrush}" 
          SelectedPointerOverBackground="{ThemeResource SystemControlDisabledTransparentBrush}" 
          PressedBackground="{ThemeResource SystemControlDisabledTransparentBrush}" 
          SelectedPressedBackground="{ThemeResource SystemControlDisabledTransparentBrush}" 
          DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}" 
          DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}" 
          ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}" 
          HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
          VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" 
          ContentMargin="{TemplateBinding Padding}" 
          CheckMode="Inline"/> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </ListView.ItemContainerStyle> 

    <ListView.ItemTemplate> 
     <DataTemplate x:DataType="viewModel:MyViewModel"> 
      <UserControl > 
       <Grid Style="{StaticResource SomeStyle}"> 
        <VisualStateManager.VisualStateGroups> 
         <VisualStateGroup x:Name="VisualStateGroup"> 
          <VisualState x:Name="VisualStatePhone"> 
           <VisualState.StateTriggers> 
            <AdaptiveTrigger MinWindowWidth="0"/> 
           </VisualState.StateTriggers> 
           <VisualState.Setters> 
            <Setter Target="ThumbnailImage.Width" Value="50"/> 
            <Setter Target="ThumbnailImage.Height" Value="50"/>           
           </VisualState.Setters> 
          </VisualState> 

          <VisualState x:Name="VisualStateTablet"> 
           <VisualState.StateTriggers> 
            <AdaptiveTrigger MinWindowWidth="600" /> 
           </VisualState.StateTriggers> 
           <VisualState.Setters> 
            <Setter Target="ThumbnailImage.Width" Value="70"/> 
            <Setter Target="ThumbnailImage.Height" Value="70"/> 
           </VisualState.Setters> 
          </VisualState> 

          <VisualState x:Name="VisualStateDesktop"> 
           <VisualState.StateTriggers> 
            <AdaptiveTrigger MinWindowWidth="1200" /> 
           </VisualState.StateTriggers> 
           <VisualState.Setters> 
            <Setter Target="ThumbnailImage.Width" Value="90"/> 
            <Setter Target="ThumbnailImage.Height" Value="90"/> 
           </VisualState.Setters> 
          </VisualState> 
         </VisualStateGroup> 
        </VisualStateManager.VisualStateGroups> 

        <Grid.RowDefinitions> 
         <RowDefinition MaxHeight="30"></RowDefinition> 
         <RowDefinition MaxHeight="30"></RowDefinition> 
         <RowDefinition MaxHeight="30"></RowDefinition> 
         <RowDefinition MaxHeight="30"></RowDefinition> 
         <RowDefinition MaxHeight="30"></RowDefinition> 
         <RowDefinition MaxHeight="10"></RowDefinition> 
        </Grid.RowDefinitions> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="Auto"/> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 

        <Image Source="{x:Bind ThumbnailImage}"            
          Visibility="{x:Bind ThumbnailImage, Converter={StaticResource BoolToVisibilityImage}}" 
          Name="ThumbnailImage"/> 

        <TextBlock Text="{x:Bind Name}" .../>        

        <Grid Grid.Row="1" 
          Grid.Column="1" 
          Visibility="{x:Bind Source, Converter={StaticResource ConverterNameHere}}"> 

         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="Auto"/> 
          <ColumnDefinition Width="*"/> 
         </Grid.ColumnDefinitions> 

         <TextBlock Text="{x:Bind lblSource, Mode=OneWay}" .../> 

         <TextBlock Text="{x:Bind Source}" .../> 
        </Grid> 

        <Grid Grid.Row="2" 
          Grid.Column="1" 
          Visibility="{x:Bind Author, Converter={StaticResource ConverterNameHere}}"> 

         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="Auto"/> 
          <ColumnDefinition Width="*"/> 
         </Grid.ColumnDefinitions> 

         <TextBlock Text="{x:Bind lblAuthor, Mode=OneWay}" .../> 
         <TextBlock Text="{x:Bind Author}" .../> 
        </Grid> 

        <TextBlock Text="{x:Bind EducationalLevel}" .../> 

        <StackPanel Orientation="Horizontal" 
           Grid.Row="4" 
           Grid.Column="1"> 

         <ItemsControl ItemsSource="{x:Bind AccessRights}"> 
          <ItemsControl.ItemsPanel> 
           <ItemsPanelTemplate> 
            <StackPanel Orientation="Horizontal"/> 
           </ItemsPanelTemplate> 
          </ItemsControl.ItemsPanel> 
          <ItemsControl.ItemTemplate> 
           <DataTemplate> 
            <Image Source="{Binding}"/> 
           </DataTemplate> 
          </ItemsControl.ItemTemplate> 
         </ItemsControl> 

         <ItemsControl ItemsSource="{x:Bind Languages}"> 
          <ItemsControl.ItemsPanel> 
           <ItemsPanelTemplate> 
            <StackPanel Orientation="Horizontal"/> 
           </ItemsPanelTemplate> 
          </ItemsControl.ItemsPanel> 
         </ItemsControl> 

         <ItemsControl ItemsSource="{x:Bind TypeImages}"> 
          <ItemsControl.ItemsPanel> 
           <ItemsPanelTemplate> 
            <StackPanel Orientation="Horizontal"/> 
           </ItemsPanelTemplate> 
          </ItemsControl.ItemsPanel> 
          <ItemsControl.ItemTemplate> 
           <DataTemplate> 
            <Image Source="{Binding}"/> 
           </DataTemplate> 
          </ItemsControl.ItemTemplate> 
         </ItemsControl>        

        </StackPanel> 

       </Grid> 
      </UserControl> 
     </DataTemplate> 
    </ListView.ItemTemplate> 
</ListView> 

Hier ist meine inkrementelle Laden Klasse gefüllt wird:

public class ItemsToShow : ObservableCollection<MyViewModel>, ISupportIncrementalLoading 
{ 
    private SearchResponse ResponseObject { get; set; } = new SearchResponse(); 
    MyViewModel viewModel = null; 


    public bool HasMoreItems 
    { 
     get 
     { 
      if ((string.IsNullOrEmpty(SearchResultDataStore.NextPageToken) && !SearchResultDataStore.IsFirstRequest) || SearchResultDataStore.StopIncrementalLoading) 
       return false; 

      if(SearchResultDataStore.IsFirstRequest) 
      { 
       using (var db = new DbContext()) 
       { 
        var json = db.UpdateResponse.First(r => r.LanguageId == DataStore.Language).JsonResponse; 
        Metadata = Newtonsoft.Json.JsonConvert.DeserializeObject<UpdateApiResponse>(json).response.metadata.reply; 
       } 

       var returnObject = SearchResultDataStore.SearchResponse; 
       ResponseObject = returnObject.response; 

       //This will show a grid with some message for 3 seconds on a xaml page named SearchResultPage. 
       Toast.ShowToast(ResponseObject.message, SearchResultPage.Current.ToastGrid); 
      } 
      else 
      { 
       SearchApiResponse returnObject = null; 
       try 
       { 
        returnObject = new SearchApiCall().CallSearchApiAsync(param1, param2, param3).Result; 
       } 
       catch 
       { 
        return false; 
       } 
       ResponseObject = returnObject.response; 
      } 

      try 
      { 
       return ResponseObject.documents.Count > 0;           
      } 
      catch { return false; } 
     } 
    } 

    public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count) 
    { 
     CoreDispatcher coreDispatcher = Window.Current.Dispatcher; 

     return Task.Run<LoadMoreItemsResult>(async() => 
     {   
      await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,() => 
      { 
       foreach (var item in ResponseObject.documents) 
       {    
        this.Add(PrepareViewModel(item)); 
       } 
      }); 

      await Task.Delay(350);     
      return new LoadMoreItemsResult() { Count = count }; 

     }).AsAsyncOperation<LoadMoreItemsResult>(); 
    } 

    public MyViewModel PrepareViewModel(Document document) 
    { 
     viewModel = new MyViewModel(); 

     viewModel.property1 = document.value1; 
     viewModel.property2 = document.value2; 

     ... 
     ... 

     if(SearchResultDataStore.ShowImage) 
     {    
      //thumbnailUrl is a string. 
      viewModel.ThumbnailImage = document.thumbnailUrl; 
     } 
     else 
     { 
      viewModel.ThumbnailImage = "somegarbage.png"; 
     } 

     ... 
     ... 

     return viewModel; 
    } 

} 
+0

Quelle sollte BitmapImage verwenden. – lindexi

+0

Ich habe das auch versucht, hilft nicht, gleiche Ergebnisse –

+0

UWP Community Toolkit hat 'ImageEx' Kontrolle. Sie sollten sich das ansehen – AVK

Antwort

0

standardmäßig, wenn Sie verwenden x:Bind für die Quelle wird die Bindung nicht automatisch aktualisiert. Um zu überprüfen, ob dies tatsächlich die Ursache Ihres Problems ist, können Sie einen Haltepunkt in Ihrem Wertkonverter festlegen und sehen, wie viele Zeit aufgerufen wird.

Ich würde vorschlagen, x:Bind ThumbnailImage, Mode=OneWay

Sie verwenden könnte INotifyPropertyChanged in Ihrem Code hinter umsetzen müssen.

0

Stellen wenigen Schritten:

  1. Add x:Phase Attribut Image Kontrolle. Größer als anderer Wert (z. B. alle sind "0", "1" usw.)

  2. Fügen Sie Mode=OneWay zu Image hinzu, da Sie wissen sollten, wenn die Eigenschaft geändert wird.

  3. Fügen Sie die Steuererweiterung zu Image Steuerelement mit Abhängigkeitseigenschaft ImagePath hinzu. Wenn die Eigenschaft geändert wird -> beginnt das Bild asynchron aus dem Netz zu laden (zB durch HttpClient). Wenn die Anfrage abgeschlossen sein wird -> holen Sie den Inhalt und setzen Sie es auf und setzen Sie es auf die Source Eigenschaft von Image.

Stellen Sie sicher, dass Größe des Originalbildes nicht viel mehr als Image Größe der Kontrolle, denn wenn es wahr ist -> UI hängen wird.