2016-06-21 7 views
0

Neu bei XAML, UWP, MVVM und Win2D.Verwenden von VirtualBitmapControl von Win2D und laden Bild sofort

Ich muss ein sehr großes Bild in meiner Seitenansicht anzeigen. Ich schaue auf Win2D, speziell auf das VirtualBitmapControl und das VirtualBitmapExample.

Das ist nah an dem, was ich tun möchte, aber ich brauche nicht mein Bild auszuwählen, ich habe bereits diese Informationen, wenn ich auf die Seite navigieren.

Ich habe versucht, das Steuerelement zu duplizieren und die Dateiauswahl zu entfernen, aber ich kann nicht sehen, wo ich mein Bild aus dem Dateipfad laden würde, um auf der Seite anzuzeigen.

Beim Ausführen des Debuggers wird das VirtualBitmapControl initialisiert, bevor die Bindung für den Dateipfad festgelegt wird. Um eine weitere Ebene hinzuzufügen, verwende ich MVVM, also habe ich versucht, alles als UserControl zu kapseln und in der Lage zu sein, es wie ein Bild-Steuerelement zu verwenden.

Hier ist meine XAML-Code:

<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> 

Und hier ist der Code-behind:

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; 
    } 

} 

Und wie ich die Kontrolle von meiner Seite XAML bin mit:

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

Wenn mir jemand in die richtige Richtung zeigen könnte oder mir sagen würde, was ich falsch mache oder was ich vermisse, wäre das sehr ap genervt.

Sheri

Antwort

0

einhängen CreateResources Ereignis auf Ihrer Kontrolle, und verwenden Sie TrackAsyncAction dies den Fortschritt eines CanvasVirtualBitmap.LoadAsync Anruf überwachen zu lassen.

Schauen Sie sich den Code Beispiel bei http://microsoft.github.io/Win2D/html/T_Microsoft_Graphics_Canvas_CanvasBitmap.htm

Deeper Hintergrund Info: https://blogs.msdn.microsoft.com/win2d/2014/12/05/async-resource-loading-in-win2d/

+0

Das funktioniert aber CreateResources wird immer nur einmal das erste Mal, dass ich auf diese Seite gehen genannt. Ich navigiere auf dieser Seite von einer anderen Seite (mit MVVM und einem ViewModel Locater) und brauche das neue Bild (das auf der anderen Seite ausgewählt und als FilePath-Eigenschaft für das Benutzersteuerelement festgelegt wird), wenn ich in das Fenster gehe Seite. Ich musste auch das Entladen des ImageVirtualControl in Control_Unloaded auskommentieren oder ich erhielt Null-Referenzen, als ich zurück in die Seite ging. – SheriSteeves

+0

Im Allgemeinen rate ich davon ab, Win2D-Steuerelemente für die Wiederverwendung zwischenzuspeichern, wenn eine Seite erneut besucht wird. Jedes Win2D-Steuerelement verbraucht eine erhebliche Menge an GPU-Ressourcen, die Sie wirklich freigeben möchten, wenn die Seite nicht mehr sichtbar ist. Sie können das Seiten-Caching deaktivieren, indem Sie NavigationCacheMode auf Deaktiviert setzen (weitere Informationen finden Sie unter http://mikaelkoskinen.net/post/winrt-navigation-cache-or-why-going-back-to-previous-page-creates-a- new-instance-of-the-page) Alternative (komplexere) Vorgehensweise: https://blogs.msdn.microsoft.com/win2d/2015/01/29/loading-win2d-resources-from-outside-the -createresources-event / –