###前提・実現したいこと
はじめまして.
最近,C#を独学で勉強しています.特に,MVVMモデルを使ったWPFアプリケーション開発に興味があります.
ScrollViewerとImageを使って,簡単な画像ビューワをMVVMモデルに沿うようにトライしています.Google Mapのようにホイールを回すと,マウスで示した位置を維持したまま拡大縮小する機能を追加したいです.できるだけ,コードビハインドからコードは排除しようと考えて,ImageのBehaviorとして追加しようと考えています.
###発生している問題・エラーメッセージ・質問
下記のように,Imageに対して,依存関係プロパティで拡大縮小機能を追加しました.
拡大・縮小処理はうまく動くのですが,スケーリングを行うとスクロール位置がくるってしまいます(スケール中心が原点になるからだと思います).拡大縮小処理を行う際に,"LayoutTransform"ではなく,"RenderTransform"を使うと.拡大縮小の挙動は思った通りに動くのですが,全体の座標系まで変わってしまい,ScrollViewerが正しく動かなくなりました.
そこで,拡大縮小処理の後に,マウスポインタの位置を維持するように,ScrollViewerの位置を制御しようと考えました.しかし,Imageのビヘイビアから,ScrollViewerの制御ができない(ScrollViewerのobjectが取得できない)ため困っています.どのようにするのが良いでしょうか?できるだけ,コードビハインドには書きたくないため,Behaviorか,ViewModelで処理ができないかと考えています.
また,現在は拡大縮小処理はBehaviorで実装していますが,本来はViewModelで行うべきなのでしょうか?表示の処理なので,Viewに書くべきなのかなと思っているのですが...
不足している情報などありましたら,お知らせいただければ幸いです.
お手数をお掛けしますが,どうぞよろしくお願いします.
###該当のソースコード
MainWindow.xaml
XAML
1<Window x:Class="ImageViewer.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:Behaviors="clr-namespace:ImageViewer.Views.Behaviors" 5 Title="MainWindow" Height="512" Width="512"> 6 <Grid> 7 <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> 8 <Image Behaviors:WheelScale.IsEnabled="true" Stretch="None" Margin="2"> 9 <Image.Source> 10 <BitmapImage UriSource="https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png"/> 11 </Image.Source> 12 </Image> 13 </ScrollViewer> 14 </Grid> 15</Window>
WheelScale.cs
C#
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using System.Text; 5using System.Threading.Tasks; 6using System.Windows; 7using System.Windows.Controls; 8using System.Windows.Input; 9using System.Windows.Media; 10 11namespace ImageViewer.Views.Behaviors 12{ 13 public class WheelScale : DependencyObject 14 { 15 public static bool GetIsEnabled(DependencyObject obj) 16 { 17 return (bool)obj.GetValue(IsEnabledProperty); 18 } 19 public static void SetIsEnabled(DependencyObject obj, bool value) 20 { 21 obj.SetValue(IsEnabledProperty, value); 22 } 23 24 public bool IsEnabled 25 { 26 get { return (bool)GetValue(IsEnabledProperty); } 27 set { SetValue(IsEnabledProperty, value); } 28 } 29 30 public static readonly DependencyProperty IsEnabledProperty = 31 DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(WheelScale), new UIPropertyMetadata(false, IsEnabledChanged)); 32 33 static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 34 { 35 var img = d as Image; 36 if (img == null) return; 37 38 if ((bool)e.NewValue) 39 { 40 img.Loaded += img_Loaded; 41 } 42 else img_Unloaded(img, new RoutedEventArgs()); 43 } 44 45 // アタッチ 46 static void img_Loaded(object sender, RoutedEventArgs e) 47 { 48 var img = sender as Image; 49 if (img == null) return; 50 img.Unloaded += img_Unloaded; 51 // ホイールのイベントハンドラと関連付け 52 img.PreviewMouseWheel += imgScaleChange; 53 } 54 55 // デタッチ 56 static void img_Unloaded(object sender, RoutedEventArgs e) 57 { 58 var img = sender as Image; 59 if (img == null) return; 60 img.Loaded -= img_Loaded; 61 img.Unloaded -= img_Unloaded; 62 } 63 64 // 実際のスケーリング処理 65 static double total_scale = 1.0; 66 static void imgScaleChange(object sender, MouseWheelEventArgs e) 67 { 68 var img = sender as Image; 69 if (img != null) 70 { 71 double scale = (0 < e.Delta) ? 1.1 : (1.0 / 1.1); 72 total_scale = total_scale * scale; 73 // ScaleTransformでは,Centerの座標は反映されない.水平方向の移動が無視される? 74 // 実際のスケール処理 75 img.LayoutTransform = new ScaleTransform(total_scale, total_scale, e.GetPosition(img).X, e.GetPosition(img).Y); 76 // スクロールが無効になるように 77 e.Handled = true; 78 } 79 } 80 } 81}
###補足情報(言語/FW/ツール等のバージョンなど)
VisualStudio2013
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/09/04 02:46