2016-06-21 13 views
0

XAML、UWP、MVVM、Win2Dの新機能です。Win2DからVirtualBitmapControlを使用し、すぐにイメージをロード

ページビューに非常に大きな画像を表示する必要があります。私はWin2D、特にVirtualBitmapControlとVirtualBitmapExampleを見ています。

これは私がやりたいことに近いですが、私のイメージを選ぶ必要はありません。私はページに移動すると既にその情報を持っています。

コントロールを複製してファイルピッカーを削除しようとしましたが、ページに表示するファイルパスから画像をロードする場所がわかりません。

デバッガをステップ実行すると、ファイルパスのバインディングが設定される前にVirtualBitmapControlが初期化されます。さらに別のレイヤーを追加するには、MVVMも使用しています。そのため、すべてをUserControlとしてカプセル化し、Imageコントロールを使用するのと同じ方法で使用できるようにしました。ここで

は私のXAMLコードです:

public sealed partial class VirtualBitmapControl : UserControl, INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public VirtualBitmapControl() 
    { 
     this.InitializeComponent(); 

     if (!DesignMode.DesignModeEnabled) 
     { 
      DataContext = this; 
     } 

     virtualBitmapOptions = CanvasVirtualBitmapOptions.None; 
     //virtualBitmapOptions = CanvasVirtualBitmapOptions.CacheOnDemand; 
     //virtualBitmapOptions = CanvasVirtualBitmapOptions.ReleaseSource; 
    } 

    public string LoadedImageInfo { get; private set; } 

    public bool IsImageLoaded { get { return virtualBitmap != null; } } 


    //StorageFile PhotoAsStorageFile; 
    IRandomAccessStream imageStream; 

    CanvasVirtualBitmap virtualBitmap; 
    CanvasVirtualBitmapOptions virtualBitmapOptions; 

    // This is the file we are displaying 
    public string FilePath 
    { 
     get { return (string)GetValue(FilePathProperty); } 
     set { SetValue(FilePathProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for FilePath. 
    // This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty FilePathProperty = 
     DependencyProperty.Register("FilePath", typeof(string), typeof(VirtualBitmapControl), 
            new PropertyMetadata(null, new PropertyChangedCallback(OnPropertyChanged))); 
            //null); 

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     var instance = d as VirtualBitmapControl; 
     if (d == null) 
      return; 

     if (instance.virtualBitmap != null) 
     { 
      //instance.virtualBitmap.Invalidate(); 
      //instance.virtualBitmap.InvalidateMeasure(); 
     }    
    } 

    private void Control_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 

     // TODO: What do I need to do here? 
     ImageScrollViewer.MaxWidth = double.MaxValue; 
     ImageScrollViewer.MaxHeight = double.MaxValue; 

     /* WIN2d sample code 
     if (smallView) 
     { 
      ImageScrollViewer.MaxWidth = ActualWidth/4; 
      ImageScrollViewer.MaxHeight = ActualHeight/4; 
     } 
     else 
     { 
      ImageScrollViewer.MaxWidth = double.MaxValue; 
      ImageScrollViewer.MaxHeight = double.MaxValue; 
     }*/ 
    } 

    private void Control_Loading(FrameworkElement sender, object args) 
    { 
     System.Diagnostics.Debug.WriteLine("VirtualBitmapControl::Control_Loading"); 

    } 


    private void Control_Loaded(object sender, RoutedEventArgs e) 
    { 
     System.Diagnostics.Debug.WriteLine("VirtualBitmapControl::Control_Loaded"); 
    } 

    private void Control_Unloaded(object sender, RoutedEventArgs e) 
    { 
     System.Diagnostics.Debug.WriteLine("VirtualBitmapControl::Control_Unloaded"); 

     if (ImageVirtualControl != null) 
     { 
      ImageVirtualControl.RemoveFromVisualTree(); 
      ImageVirtualControl = null; 
     } 
    } 

    private void ImageVirtualControl_CreateResources(Microsoft.Graphics.Canvas.UI.Xaml.CanvasVirtualControl sender, Microsoft.Graphics.Canvas.UI.CanvasCreateResourcesEventArgs args) 
    { 
     System.Diagnostics.Debug.WriteLine("VirtualBitmapControl::ImageVirtualControl_CreateResources"); 
     if (imageStream != null) 
     { 
      args.TrackAsyncAction(LoadVirtualBitmap().AsAsyncAction()); 
     } 
    } 

    private void ImageVirtualControl_RegionsInvalidated(Microsoft.Graphics.Canvas.UI.Xaml.CanvasVirtualControl sender, Microsoft.Graphics.Canvas.UI.Xaml.CanvasRegionsInvalidatedEventArgs args) 
    { 
     foreach (var region in args.InvalidatedRegions) 
     { 
      using (var ds = ImageVirtualControl.CreateDrawingSession(region)) 
      { 
       if (virtualBitmap != null) 
        ds.DrawImage(virtualBitmap, region, region); 
      } 
     } 
    } 


    private async Task LoadVirtualBitmap() 
    { 
     if (virtualBitmap != null) 
     { 
      virtualBitmap.Dispose(); 
      virtualBitmap = null; 
     } 

     LoadedImageInfo = ""; 

     if (imageStream != null) 
     { 
      imageStream.Dispose(); 
      imageStream = null; 
     } 
     NotifyPropertyChanged(); 


     if (imageStream == null) 
     { 
      imageStream = await GetBitmapStreamFromFilePathAsync(this.FilePath); 
     } 
     NotifyPropertyChanged(); 


     virtualBitmap = await CanvasVirtualBitmap.LoadAsync(ImageVirtualControl.Device, imageStream, virtualBitmapOptions); 

     if (ImageVirtualControl == null) 
     { 
      // This can happen if the page is unloaded while LoadAsync is running 
      return; 
     } 

     var size = virtualBitmap.Size; 
     ImageVirtualControl.Width = size.Width; 
     ImageVirtualControl.Height = size.Height; 
     ImageVirtualControl.Invalidate(); 

     LoadedImageInfo = string.Format("{0}x{1} image, is {2}CachedOnDemand", 
      size.Width, size.Height, virtualBitmap.IsCachedOnDemand ? "" : "not "); 

     NotifyPropertyChanged(); 
    } 

    private void NotifyPropertyChanged() 
    { 
     if (PropertyChanged == null) 
      return; 

     foreach (var property in new string[] { "LoadedImageInfo", "IsImageLoaded", "FilePath"}) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(property)); 
     } 
    } 

    internal async static Task<IRandomAccessStream> GetBitmapStreamFromFilePathAsync(String filePath) 
    { 
     IRandomAccessStream imageStream = null; 
     <trimmed for space> 

     return imageStream; 
    } 

} 

そして、どのように私は私のページのXAMLからのコントロールを使用しています:

<Grid x:Name="rootPhotoGrid" RelativePanel.Below="pageHeader" 
      RelativePanel.AlignLeftWithPanel="True" 
    RelativePanel.AlignRightWithPanel="True" Background="AntiqueWhite"> 
    <local:VirtualBitmapControl FilePath="{x:Bind ViewModel.LoadedImagePath}"/> </Grid> 

<UserControl 
    x:Class="PEERNET.UWPImageViewer.Views.VirtualBitmapControl" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="using:PEERNET.UWPImageViewer.Views" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:Win2Dcanvas="using:Microsoft.Graphics.Canvas.UI.Xaml" 
    mc:Ignorable="d" 
    d:DesignHeight="300" 
    d:DesignWidth="400" 
    d:DataContext="{d:DesignInstance Type=local:VirtualBitmapControl, IsDesignTimeCreatable=true}" 
    SizeChanged="Control_SizeChanged" 
    Unloaded="Control_Unloaded" 
    Loading="Control_Loading" 
    Loaded="Control_Loaded"> 

    <Grid> 
     <VisualStateManager.VisualStateGroups> 
      <VisualStateGroup x:Name="AdaptiveVisualStateGroup"> 
       <VisualState x:Name="VisualStateNarrow"> 
        <VisualState.StateTriggers> 
         <AdaptiveTrigger MinWindowWidth="{StaticResource NarrowMinWidth}" /> 
        </VisualState.StateTriggers> 
        <VisualState.Setters> 
         <!-- TODO: change properties for narrow view --> 
        </VisualState.Setters> 
       </VisualState> 
       <VisualState x:Name="VisualStateNormal"> 
        <VisualState.StateTriggers> 
         <AdaptiveTrigger MinWindowWidth="{StaticResource NormalMinWidth}" /> 
        </VisualState.StateTriggers> 
        <VisualState.Setters> 
         <!-- TODO: change properties for normal view --> 
        </VisualState.Setters> 
       </VisualState> 
       <VisualState x:Name="VisualStateWide"> 
        <VisualState.StateTriggers> 
         <AdaptiveTrigger MinWindowWidth="{StaticResource WideMinWidth}" /> 
        </VisualState.StateTriggers> 
        <VisualState.Setters> 
         <!-- TODO: change properties for wide view --> 
        </VisualState.Setters> 
       </VisualState> 
      </VisualStateGroup> 
     </VisualStateManager.VisualStateGroups> 

     <ScrollViewer HorizontalScrollMode="Enabled" 
         VerticalScrollMode="Enabled" 
         ZoomMode="Disabled" 
         HorizontalScrollBarVisibility="Auto" 
         VerticalScrollBarVisibility="Auto" 
         x:Name="ImageScrollViewer"> 
      <Grid> 
       <Win2Dcanvas:CanvasVirtualControl 
        x:Name="ImageVirtualControl" 
        CreateResources="ImageVirtualControl_CreateResources" 
        RegionsInvalidated="ImageVirtualControl_RegionsInvalidated"/> 
      </Grid> 
     </ScrollViewer> 

    </Grid> 
</UserControl> 

そしてここでは、コードビハインドであります

誰かが正しい方向に私を向けることができ、あるいは私が間違ってやっていることを教えてくれたり、私が逃していることを教えてもらえれば、 preciated。シェリ

答えて

0

は、あなたのコントロールにCreateResourcesイベントをフックし、これはCanvasVirtualBitmap.LoadAsyncコールの進行状況を監視できるようにTrackAsyncActionを使用しています。

http://microsoft.github.io/Win2D/html/T_Microsoft_Graphics_Canvas_CanvasBitmap.htm

深い背景情報のコード例をご覧ください:これは動作しますが、CreateResources https://blogs.msdn.microsoft.com/win2d/2014/12/05/async-resource-loading-in-win2d/

+0

だけ今まで私は、そのページに行き、非常に最初の時間後に呼び出されます。私は別のページ(MVVMとViewModel Locaterを使用して)からこのページを前後にナビゲートしています。新しいイメージ(別のページから選択し、ユーザーコントロールのFilePathプロパティとして設定)が必要です。ページ。私はまた、Control_UnloadedでImageVirtualControlのアンロードをコメントアウトするか、ページに戻ったときにnull参照を取得していました。 – SheriSteeves

+0

一般に、私は、ページを再訪したときにWin2Dコントロールを再利用するためにキャッシュすることを勧めません。各Win2Dコントロールは、ページが見えなくなったときに本当に解放したいGPUリソ​​ースをかなり消費します。 ページキャッシュを無効にするには、NavigationCacheModeをDisabledに設定します(詳細はhttp://mikaelkoskinen.net/post/winrt-navigation-cache-or-why-going-back-to-previous-page-creates-a-新しいインスタンスのインスタンス) 代替(より複雑な)アプローチ:https://blogs.msdn.microsoft.com/win2d/2015/01/29/loading-win2d-resources-from-outside-the -createresources-event / –

関連する問題