2013-01-24 3 views
5

私は写真閲覧アプリを作成していて、画像のズームを実装したいと思います。私はScrollViewerを作成し、そこにImageを配置しました。それはすべて箱から出てきます。私はズームジェスチャーを行うことができ、それは画像にズームする。次に、実装しようとしているのは、ズームジェスチャが開始され、ロードされたときにImageコントロールのビットマップを動的にスワップするときに、画像の高解像度バージョンをロードすることです。私はそれがシームレスに起こるように、ユーザーはジェスチャーを続けてズームを続け、より詳細な画像を見ることができます。 これを達成する最良の方法は何ですか? これは私が現在持っているコードです。私のコードの問題は、Image.Sourceが置き換えられたときにジェスチャが中断され、写真が元のサイズにリセットされることです。 ScrollViewerの変更イメージが置き換えられたときにリセットされるように見えるので、ZoomFactorは役に立ちません。 私は最初にnullを返しますが、低解像度モードで 'ファイル'から画像をロードし始め、読み込みが完了したらOnPropertyChanged( "Image")を呼び出すImageプロパティを持つDataModelを持っています。 LoadFullImage()を呼び出すと、フル解像度のバージョンがロードされ、終了したらOnPropertyChanged( "Image")を呼び出します。ここでズームジェスチャーを行っているときにScrollViewerの画像を置換する

はDataModel.csからの抽出物である:ここでは

public async Task LoadFullImage() 
    { 
     loadFullImageTask = UpdateImage(0); 
     await loadFullImageTask; 
    } 

    public ImageSource Image 
    { 
     get 
     { 
      if (fullImage != null) 
      { 
       return fullImage; 
      } 
      else if (image != null) 
      { 
       return image; 
      } 
      else 
      { 
       Task loadImageTask = UpdateImage(768); 

       return null; 
      } 
     } 
    } 

    public bool FullImageLoading 
    { 
     get { return (this.loadFullImageTask != null) && (!this.loadFullImageTask.IsCompleted); } 
    } 

    public bool FullImageLoaded 
    { 
     get { return this.fullImage != null; } 
    } 

は私のMainPage.xamlを次のとおりです。ここで

<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"> 
    <ScrollViewer x:Name="imageViewer" HorizontalAlignment="Stretch" HorizontalScrollBarVisibility="Visible" VerticalAlignment="Stretch" MinZoomFactor="1" ZoomMode="Enabled" ViewChanged="imageViewer_ViewChanged"> 
     <Image x:Name="image" Margin="0,0,0,0" Stretch="Uniform" Source="{Binding Image}" /> 
    </ScrollViewer> 
</Grid> 

は私のMainPage.xaml.csです:

protected override async void OnNavigatedTo(NavigationEventArgs e) 
    { 
     FileOpenPicker filePicker = new FileOpenPicker(); 
     filePicker.SuggestedStartLocation = PickerLocationId.ComputerFolder; 
     filePicker.FileTypeFilter.Add(".jpg"); 
     StorageFile file = await filePicker.PickSingleFileAsync(); 

     data = new DataModel(file); 
     imageViewer.DataContext = data; 
    } 

    private async void imageViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e) 
    { 
     ScrollViewer imageViewer = (ScrollViewer)sender; 

     if (imageViewer.ZoomFactor > 1) 
     { 
      if (!data.FullImageLoaded && (!data.FullImageLoading)) 
      { 
       int oldHeight = ((BitmapImage)data.Image).PixelHeight; 
       int oldWidth = ((BitmapImage)data.Image).PixelWidth; 
       double oldHOffset = imageViewer.HorizontalOffset; 
       double oldVOffset = imageViewer.VerticalOffset; 

       await data.LoadFullImage(); 

       int newHeight = ((BitmapImage)data.Image).PixelHeight; 
       int newWidth = ((BitmapImage)data.Image).PixelWidth; 

       float ratio = (float)oldHeight/(float)newHeight; 
       imageViewer.MaxZoomFactor = imageViewer.MaxZoomFactor * ratio; 
       imageViewer.MinZoomFactor = imageViewer.MinZoomFactor * ratio; 
       imageViewer.ZoomToFactor(imageViewer.ZoomFactor * ratio); 
       //imageViewer.ScrollToHorizontalOffset(oldHOffset/ratio); 
       //imageViewer.ScrollToVerticalOffset(oldVOffset/ratio); 
      } 
     } 
    } 

として、私がすでに述べたように、このコードの問題は、ジェスチャーが中断され、新しいイメージが正しいサイズにサイズ変更されない/スクロールされないことですユーザーエクスペリエンスはシームレスではありません。 これを解決するための提案をありがとう。

答えて

0

私はそれがあまりにも多くなりますので、あなたのためにこのコードを書くつもりが、ここでの手順はないのです。

  1. 画像はScaleTransformはそのRenderTransformプロパティに適用されている必要があります。これを使用して、ユーザーがピンチまたはストレッチしているときに「ズーム」させます。
  2. 操作イベントを使用してピンチジェスチャーを検出します。いくつかのコードを減らすことができれば、ピンチジェスチャーだけにフィルタリングすることもできます。これらの出来事が最も信頼できるでしょう。
  3. 操作イベントは、ピンチまたはストレッチがどれだけ発生しているかを返します。これは、1の画像ScaleTransformに適用するズームの程度に対応する必要があります。
  4. BitmapImageを作成すると、サーバーからイメージをロードします。読み込まれたら、ユーザーが挟んでいる画像のソースを置き換えることができます。これは、高解像度画像がマルチメガバイトでない限り、ユーザーにはほとんどシームレスになります。それをしないでください。

私の手順にはScrollViewerが含まれていないことに注意してください。 ScrollViewerは確かにイメージをラップすることができますが、作業自体はImage自体の一部として行われます。

私はまた、あなたは、このベストを尽くすためにからいくつかのロジックを盗むしたい場合がありますMultiScaleImage制御を指している可能性があります:http://msdn.microsoft.com/en-us/library/system.windows.controls.multiscaleimage%28v=vs.95%29.aspx

もう一つあります。これはDeepZoomで非常に簡単に行うことができます。 XAMLではまだ使用できないため、これを実現するためにWebViewを活用することはできません。これは、あなたにあらかじめ構築された、微妙にスケーラブルな(そして自由な)ソリューションを提供します。しかし、選択はあなたのものです。

+0

私は、ScrollViewerがズームジェスチャをサポートしていなかった場合、ScaleTransformによるアプローチが必要だと考えました。現在、1枚の画像で完璧に動作します。非常にスムーズにズームインできます。また、私のScrollViewerはFlipViewコントロールに含まれており、ScrollViewerコントロールとFlipViewコントロールの両方からジェスチャーがうまく機能します。必要に応じて画像を反転したりズームインしたりできます。 ScrollViewerで画像をシームレスに切り替えることは不可能だと言っていますか? – Vitaly

0

誰でもこのスレッドを覚えていますか? =)ok、
私はmy appの 'ズーム中に画像を置き換える'を実装しました。
上記の@Vitaryと同様に、 'content'のサイズが変更されると、スクロールビューアはズーム比とX/Yオフセットをリセットします。同じようビューボックスのサイズを維持することによって

<FlipView> 
    <DataTemplate> 
    <ScrollViewer> 
     <ViewBox> <-- This size is same with original image width/height. No change during zoom in/out. 
     <Image/> <-- This size is vary. 
     </ViewBox> 
    </ScrollViewer> 
    </DataTemplate> 
</FlipView> 

、あなたはスクロールビューアのリセットを避けることができます私のアプリは、次の構造を使用するXAML、それを避けるために
。 私の実装は...

  1. ユーザーはflipviewの項目を選択します。このシーケンスでは、viewsourceコードは元の画像のw/hをviewourceメンバーに設定します。このメンバーは、ビューボックスのw/hにバインドされています。
  2. 低解像度のデコードを行います。バインディングでイメージコントロールに設定します。ご存じのように、viewboxはコンテンツを自動的に拡大してビューボックスのサイズに合わせることができます。
  3. ユーザーがズームジェスチャを行うと、コードビハインドがViewModelに通知します。 ViewModelは元の解像度のデコードを開始し、イメージをバインディングでイメージコントロールに設定します。このシーケンスの間、スクロールビューアはオフセットとズーム比を維持することができます。なぜなら、ビューボックスのサイズは変更されないからです。低解像度から元の解像度への切り替えはスムーズで、グリッチもありません。
関連する問題