2017-04-05 2 views
1

MediaImageクラス(モデル)非同期ロードされたイメージのUI内のすべてのショーを同時に

public class MediaImage : INotifyPropertyChanged 
{ 
    public MediaImage(FileSystemInfo file) 
    { 
     this.Uri = new Uri(file.FullName); 
     this.Label = file.Name; 

     var getThumbnail = this.LoadThumbnail(this.Uri); 

     getThumbnail.ContinueWith(task => 
     { 
      this.Thumbnail = task.Result; 
     }); 
    } 

    public Uri Uri { get; } 

    public string Label { get; private set; } 

    private BitmapImage thumbnail; 

    public BitmapImage Thumbnail 
    { 
     get { return this.thumbnail; } 
     private set 
     { 
      this.thumbnail = value; 
      this.OnPropertyChanged(); 
     } 
    } 
    private async Task<BitmapImage> LoadThumbnail(Uri uri) 
    { 
     return await Task.Run(() => this.GenerateThumbnail(uri)); 
    } 

    private BitmapImage GenerateThumbnail(Uri uri) 
    { 
     var sourceBitmap = new BitmapImage(); 

     sourceBitmap.BeginInit(); 
     sourceBitmap.CacheOption = BitmapCacheOption.OnLoad; 
     sourceBitmap.DecodePixelWidth = 100; 
     sourceBitmap.UriSource = uri; 
     sourceBitmap.EndInit(); 
     sourceBitmap.Freeze(); 

     return sourceBitmap; 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

メインウィンドウのC#

public partial class MainWindow 
{ 
    public MainWindow() 
    { 
     this.InitializeComponent(); 
    } 

    private void OnLoadImagesClick(object sender, RoutedEventArgs e) 
    { 
     var dialog = new FolderBrowserDialog(); 
     if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) 
     { 
      this.MediaImageView.LoadImages(dialog.SelectedPath); 
     } 
    } 
} 

ImageViewのXAML(インタフェース)

<Grid> 
    <ListBox Style="{DynamicResource ImageViewListBoxStyle}" 
      ItemsSource="{Binding Images}" 
      ItemContainerStyle="{DynamicResource ImageViewListBoxItemStyle}"> 
     <ListBox.ItemsPanel> 
      <ItemsPanelTemplate> 
       <WrapPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </ListBox.ItemsPanel> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Grid> 
        <Grid.RowDefinitions> 
          <RowDefinition Height="*" /> 
          <RowDefinition Height="Auto" /> 
        </Grid.RowDefinitions> 
        <TextBlock Panel.ZIndex="1000" Grid.Row="1" Text="{Binding Label}" Foreground="White" Width="100" Height="20" TextTrimming="CharacterEllipsis" VerticalAlignment="Center"> 
         <TextBlock.Background> 
          <SolidColorBrush Opacity="0.50" Color="Black"/> 
         </TextBlock.Background> 
        </TextBlock> 
        <Image Grid.Row="0" Grid.RowSpan="2" Source="{Binding Thumbnail, UpdateSourceTrigger=PropertyChanged}" Width="100" Height="100"/> 
       </Grid> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 

ImageViewのC#の(インターフェイスコード)

public partial class ImageView 
{ 
    public ImageView() 
    { 
     this.InitializeComponent(); 
     this.Images = new ObservableCollection<MediaImage>(); 
     this.DataContext = this; 
    } 

    public ObservableCollection<MediaImage> Images { get; } 

    public void LoadImages(string path) 
    { 
     this.Images.Clear(); 

     var option = SearchOption.TopDirectoryOnly; 

     var files = new DirectoryInfo(path).EnumerateFiles("*", option); 

     foreach (var file in files) 
     { 
      // Skip images already in our image collection 
      if (this.Images.Any(x => x.Uri.AbsolutePath == file.FullName)) 
      { 
       continue; 
      } 

      this.Images.Add(new MediaImage(file)); 
     } 
    } 
} 

問題行動のGIFの

enter image description here

ノート

調査し、で設定することを私の理解した学習によってUpdateSourceTrigger〜私のXAMLで、非同期タスクが完了し、ThumbnailプロパティがPropertyChangedイベントをトリガすると、各イメージはバインドを更新する必要があります。

ListBoxの各画像は、非同期タスクが完了したときに(他の画像やタスクに関係なく)元の画像に更新する必要がありますが、それは起こっていないようです。私の現在のビルドでは、最後のタスクが完了したときにすべての画像が更新されるようです。

質問

は私のモデル(MediaImage)は非同期で特定のプロパティを更新し、それのタスクが完了すると、リストボックスは、(好ましくはPropertyChangedイベントを経由して)各項目を更新するように私のコードを変更する簡単な方法はありますか?一言で言えば

+2

'UpdateSourceTrigger'はOneWayバインディングに影響しません。 TwoWayまたはOneWayToSourceがBindingのSourceプロパティをいつ更新するかを制御します。 'PropertyChanged'に設定することは、INotifyPropertyChangedインターフェースの' PropertyChanged'イベントとは何の関係もありません。 – Clemens

+1

ランダムな遅延を 'GenerateThumbnail'(' Thread.Sleep'を介して)に加えて、各サムネイル生成に異なる時間がかかるようにして、何が起こるのかを見てみましょう。 – Evk

+2

イメージを非同期にロードして表示する方法の例については、[この回答](http://stackoverflow.com/a/43124089/1136211)をご覧ください。 – Clemens

答えて

0

私のソリューション:

まず、あなたはそれがfalseに可視性だ設定する必要があります。 すべての画像が読み込まれるまで待つ必要があります。 FrameworkElement.Loadedイベント(https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.loaded(v=vs.110).aspx)を使用できます。 最後に、すべてのImageが正常に読み込まれた場合は、可視性をtrueに設定します。

+0

あなたの答えはありがとうございました。私はそれがロードされている間、イメージを非表示にするつもりはない、むしろ私は、非同期に画像をロードし、ロードされたときに画像を表示するインターフェイスをしたい。 – Bluecakes

関連する問題