質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

2233閲覧

WPFでの画像ズーム機能

pon-suke

総合スコア16

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

MVVM

MVVM(Model View ViewModel)は構築上のデザインパターンで、表現ロジック(ViewModel)によってデータ(Model)からページ(View)を分離させます。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

0クリップ

投稿2017/08/30 10:21

###前提・実現したいこと
はじめまして.

最近,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

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

ユーザーコントロールを作るでいいんじゃないですかね。
そっちで、コードビハインドでバリバリ書けば。

標準のコントロールはピュアなものばかりですし。

Viewの仕事なので、Viewのコンポーネントでやるのが正しいんじゃないかな。

投稿2017/08/31 10:30

kiichi54321

総合スコア1984

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pon-suke

2017/09/04 02:46

アドバイスありがとうございました. ユーザーコントロールを使って,試してみたいと思います!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問