White Whale Studio

[WPF] ScrollView Mouse Click & Move 마우스 클릭으로 Child 움직이기 본문

IT Engineering/.Net (WPF)

[WPF] ScrollView Mouse Click & Move 마우스 클릭으로 Child 움직이기

glorymind 2015. 1. 21. 17:32
반응형

WPF ScrollView 에서 기본적으로는 마우스 클릭해서 내부에 있는 컨텐츠 이리저리 굴려봤자 이동을 하지는 않습니다.

다행히도 어떤 친절한 외국 개발자님께서 이미 Y축을 구현해 두셔서 X축을 더하여 완성했습니다.

사용법은 간단합니다.


XAML 창에서 해당 Class가 포함된 프로젝트를  xmlns:my="clr-namespace:PROJECT" 와 같이

참조 추가한 뒤


<ScrollViewer my:TouchScrolling.IsEnabled="True" HorizontalScrollBarVisibility="Auto" Margin="0,0,0,30" VerticalScrollBarVisibility="Auto" Name="sv_image" CanContentScroll="True">


이런식으로 스크롤 뷰어에 my:TouchScrolling.IsEnabled="True" 항목만 추가하시면

간단하게 구현 끝~!


간만에 보는 깔끔한 코드라 기분이 좋습니다 ㅎ.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
public class TouchScrolling : DependencyObject
    {
        public static bool GetIsEnabled(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }
 
        public static void SetIsEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }
 
        public bool IsEnabled
        {
            get { return (bool)GetValue(IsEnabledProperty); }
            set { SetValue(IsEnabledProperty, value); }
        }
 
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled"typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged));
 
        static Dictionary<object, MouseCapture> _captures = new Dictionary<object, MouseCapture>();
 
        static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var target = d as ScrollViewer;
            if (target == nullreturn;
 
            if ((bool)e.NewValue)
            {
                target.Loaded += target_Loaded;
            }
            else
            {
                target_Unloaded(target, new RoutedEventArgs());
            }
        }
 
        static void target_Unloaded(object sender, RoutedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("Target Unloaded");
 
            var target = sender as ScrollViewer;
            if (target == nullreturn;
 
            _captures.Remove(sender);
 
            target.Loaded -= target_Loaded;
            target.Unloaded -= target_Unloaded;
            target.PreviewMouseLeftButtonDown -= target_PreviewMouseLeftButtonDown;
            target.PreviewMouseMove -= target_PreviewMouseMove;
 
            target.PreviewMouseLeftButtonUp -= target_PreviewMouseLeftButtonUp;
        }
 
        static void target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var target = sender as ScrollViewer;
            if (target == nullreturn;
 
            _captures[sender] = new MouseCapture
            {
                VerticalOffset = target.VerticalOffset,
                Point = e.GetPosition(target),
            };
        }
 
        static void target_Loaded(object sender, RoutedEventArgs e)
        {
            var target = sender as ScrollViewer;
            if (target == nullreturn;
 
            System.Diagnostics.Debug.WriteLine("Target Loaded");
 
            target.Unloaded += target_Unloaded;
            target.PreviewMouseLeftButtonDown += target_PreviewMouseLeftButtonDown;
            target.PreviewMouseMove += target_PreviewMouseMove;
 
            target.PreviewMouseLeftButtonUp += target_PreviewMouseLeftButtonUp;
        }
 
        static void target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            var target = sender as ScrollViewer;
            if (target == nullreturn;
 
            target.ReleaseMouseCapture();
        }
 
        static void target_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (!_captures.ContainsKey(sender)) return;
 
            if (e.LeftButton != MouseButtonState.Pressed)
            {
                _captures.Remove(sender);
                return;
            }
 
            var target = sender as ScrollViewer;
            if (target == nullreturn;
 
            var capture = _captures[sender];
 
            var point = e.GetPosition(target);
 
            var dy = point.Y - capture.Point.Y; // Y축 이동
            if (Math.Abs(dy) > 5)
            {
                target.CaptureMouse();
            }
 
            var dx = point.X - capture.Point.X; // X축 이동
            if (Math.Abs(dx) > 5)
            {
                target.CaptureMouse();
            }
 
            target.ScrollToVerticalOffset(capture.VerticalOffset - dy); // Y축 이동 상하
            target.ScrollToHorizontalOffset(capture.VerticalOffset - dx); // X축 이동 좌우
        }
 
        internal class MouseCapture
        {
            public Double VerticalOffset { get; set; }
            public Point Point { get; set; }
        }
    }
cs



public class TouchScrolling : DependencyObject

    {

        public static bool GetIsEnabled(DependencyObject obj)

        {

            return (bool)obj.GetValue(IsEnabledProperty);

        }


        public static void SetIsEnabled(DependencyObject obj, bool value)

        {

            obj.SetValue(IsEnabledProperty, value);

        }


        public bool IsEnabled

        {

            get { return (bool)GetValue(IsEnabledProperty); }

            set { SetValue(IsEnabledProperty, value); }

        }


        public static readonly DependencyProperty IsEnabledProperty =

            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(TouchScrolling), new UIPropertyMetadata(false, IsEnabledChanged));


        static Dictionary<object, MouseCapture> _captures = new Dictionary<object, MouseCapture>();


        static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

        {

            var target = d as ScrollViewer;

            if (target == null) return;


            if ((bool)e.NewValue)

            {

                target.Loaded += target_Loaded;

            }

            else

            {

                target_Unloaded(target, new RoutedEventArgs());

            }

        }


        static void target_Unloaded(object sender, RoutedEventArgs e)

        {

            System.Diagnostics.Debug.WriteLine("Target Unloaded");


            var target = sender as ScrollViewer;

            if (target == null) return;


            _captures.Remove(sender);


            target.Loaded -= target_Loaded;

            target.Unloaded -= target_Unloaded;

            target.PreviewMouseLeftButtonDown -= target_PreviewMouseLeftButtonDown;

            target.PreviewMouseMove -= target_PreviewMouseMove;


            target.PreviewMouseLeftButtonUp -= target_PreviewMouseLeftButtonUp;

        }


        static void target_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

        {

            var target = sender as ScrollViewer;

            if (target == null) return;


            _captures[sender] = new MouseCapture

            {

                VerticalOffset = target.VerticalOffset,

                Point = e.GetPosition(target),

            };

        }


        static void target_Loaded(object sender, RoutedEventArgs e)

        {

            var target = sender as ScrollViewer;

            if (target == null) return;


            System.Diagnostics.Debug.WriteLine("Target Loaded");


            target.Unloaded += target_Unloaded;

            target.PreviewMouseLeftButtonDown += target_PreviewMouseLeftButtonDown;

            target.PreviewMouseMove += target_PreviewMouseMove;


            target.PreviewMouseLeftButtonUp += target_PreviewMouseLeftButtonUp;

        }


        static void target_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)

        {

            var target = sender as ScrollViewer;

            if (target == null) return;


            target.ReleaseMouseCapture();

        }


        static void target_PreviewMouseMove(object sender, MouseEventArgs e)

        {

            if (!_captures.ContainsKey(sender)) return;


            if (e.LeftButton != MouseButtonState.Pressed)

            {

                _captures.Remove(sender);

                return;

            }


            var target = sender as ScrollViewer;

            if (target == null) return;


            var capture = _captures[sender];


            var point = e.GetPosition(target);


            var dy = point.Y - capture.Point.Y; // Y축 이동

            if (Math.Abs(dy) > 5)

            {

                target.CaptureMouse();

            }


            var dx = point.X - capture.Point.X; // X축 이동

            if (Math.Abs(dx) > 5)

            {

                target.CaptureMouse();

            }


            target.ScrollToVerticalOffset(capture.VerticalOffset - dy); // Y축 이동 상하

            target.ScrollToHorizontalOffset(capture.VerticalOffset - dx); // X축 이동 좌우

        }


        internal class MouseCapture

        {

            public Double VerticalOffset { get; set; }

            public Point Point { get; set; }

        }

    }

반응형
Comments