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の
ノート
調査し、で設定することを私の理解した学習によってUpdateSourceTrigger
〜私のXAMLで、非同期タスクが完了し、Thumbnail
プロパティがPropertyChanged
イベントをトリガすると、各イメージはバインドを更新する必要があります。
ListBox
の各画像は、非同期タスクが完了したときに(他の画像やタスクに関係なく)元の画像に更新する必要がありますが、それは起こっていないようです。私の現在のビルドでは、最後のタスクが完了したときにすべての画像が更新されるようです。
質問
は私のモデル(MediaImage)は非同期で特定のプロパティを更新し、それのタスクが完了すると、リストボックスは、(好ましくはPropertyChanged
イベントを経由して)各項目を更新するように私のコードを変更する簡単な方法はありますか?一言で言えば
'UpdateSourceTrigger'はOneWayバインディングに影響しません。 TwoWayまたはOneWayToSourceがBindingのSourceプロパティをいつ更新するかを制御します。 'PropertyChanged'に設定することは、INotifyPropertyChangedインターフェースの' PropertyChanged'イベントとは何の関係もありません。 – Clemens
ランダムな遅延を 'GenerateThumbnail'(' Thread.Sleep'を介して)に加えて、各サムネイル生成に異なる時間がかかるようにして、何が起こるのかを見てみましょう。 – Evk
イメージを非同期にロードして表示する方法の例については、[この回答](http://stackoverflow.com/a/43124089/1136211)をご覧ください。 – Clemens