Sie sind nicht angemeldet.

1

Sonntag, 6. Februar 2011, 21:05

AutoScroll-Komponente mit C# und WPF, ScrollViewer Erweiterung

Folgendes Code-Schnipsel erweitert die Scrollviewer-Komponente von WPF mit einer Auto-Scrolling Funktionalität.


Was bedeutet Auto-Scrolling?
Auto-Scrolling erlaubt einen schnellen Bildlauf durch einen Container mittels Klick der Mouse-Wheel (mittlere) Maus-Taste.
Scroll-Richtung und -Geschwindigkeit ändern sich dabei je nach Verhältnis zwischen der aktuellen Position der Maus und dem Anfangspunkt des Scroll-Ereignisses.

Der ganze Code wurde von mir ungefähr vor einem halben Jahr für den Editor meiner 2D-Engine herausgearbeitet, da alle online gefundenen Lösungen entweder zu funktionsarm oder extrem verbuggt waren. Ich stells hier als Public Domain zu Verfügung, ihr könnt damit machen, was ihr wollt :D


Das Verhalten lässt sich durch ein paar Werte am Anfang des Codes je nach Geschmack anpassen, ich habe alles so programmiert, damit es möglichst dem Scrolling von Firefox ähneln soll.

Quellcode

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
129
130
using System;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Input;

namespace RPG.Editor.Framework {
    public class AutoScrollViewer : ScrollViewer {
        readonly VisualCollection _visuals;
        const double ScrollBaseSize = 2.5,
            InvisibleCursorRadius = 12,
            FourWayCursorRadius = 60;

        Point _scrollBasePosition;
        Vector _vector;
        readonly Timer _ht,
            _vt;

        readonly DrawingVisual _scrollBase;

        public AutoScrollViewer()
            : base() {
            _visuals = new VisualCollection(this);

            _ht = new Timer {Interval = 80};
            _ht.Elapsed += new ElapsedEventHandler(ScrollTickX);

            _vt = new Timer {Interval = 80};
            _vt.Elapsed += new ElapsedEventHandler(ScrollTickY);

            _scrollBase = new DrawingVisual();
            using (DrawingContext dc = _scrollBase.RenderOpen()) {
                dc.DrawEllipse(Brushes.Black, new Pen(Brushes.White, 1), new Point(ScrollBaseSize, ScrollBaseSize), ScrollBaseSize, ScrollBaseSize);
            }
            _scrollBase.Opacity = 0;
            _visuals.Add(_scrollBase);
        }

        private Timer HorizontalTimer {
            get { return _ht; }
        }

        private Timer VerticalTimer {
            get {  return _vt; }
        }

        private DrawingVisual ScrollBase {
            get { return _scrollBase; }
        }

        protected override Visual GetVisualChild(int index) {
            if(index >= base.VisualChildrenCount)
                return _visuals[index - base.VisualChildrenCount];
            return base.GetVisualChild(index);
        }

        protected override int VisualChildrenCount {
            get { return _visuals.Count + base.VisualChildrenCount; }
        }

        protected override void OnMouseDown(MouseButtonEventArgs e) {
            base.OnMouseDown(e);
            if (e.MouseDevice.MiddleButton == MouseButtonState.Pressed) {
                _scrollBasePosition = e.MouseDevice.GetPosition(this);

                ScrollBase.Opacity = 1;
                ScrollBase.Offset = new Vector(_scrollBasePosition.X, _scrollBasePosition.Y);
                Cursor = Cursors.None;

                if (HorizontalScrollBarVisibility == ScrollBarVisibility.Visible)
                    HorizontalTimer.Enabled = true;
                if (VerticalScrollBarVisibility == ScrollBarVisibility.Visible)
                    VerticalTimer.Enabled = true;
            }
        }
        protected override void OnMouseUp(MouseButtonEventArgs e) {
            base.OnMouseUp(e);
            if (e.MouseDevice.MiddleButton == MouseButtonState.Released) {
                ScrollBase.Opacity = 0;
                HorizontalTimer.Stop();
                VerticalTimer.Stop();
                Cursor = Cursors.Arrow;
            }
        }
        protected override void OnMouseMove(MouseEventArgs e) {
            base.OnMouseMove(e);
            if (e.MiddleButton == MouseButtonState.Pressed) {
                _vector = _scrollBasePosition - e.MouseDevice.GetPosition(this);

                if (_vector.Length < InvisibleCursorRadius) {
                    Cursor = Cursors.None;
                    return;
                }

                if (HorizontalTimer.Enabled && VerticalTimer.Enabled) {
                    double absX = Math.Abs(_vector.X),
                        absY = Math.Abs(_vector.Y);
                    if (_vector.X > 0 && absX > absY) Cursor = Cursors.ScrollW;
                    if (_vector.X < 0 && absX > absY) Cursor = Cursors.ScrollE;
                    if (_vector.Y > 0 && absY > absX) Cursor = Cursors.ScrollN;
                    if (_vector.Y < 0 && absY > absX) Cursor = Cursors.ScrollS;

                    if (_vector.Length > FourWayCursorRadius && Math.Abs(absX - absY) < _vector.Length / 2 && Math.Abs(absY - absX) < _vector.Length / 2) {
                        if (_vector.X > 0 && _vector.Y > 0) Cursor = Cursors.ScrollNW;
                        if (_vector.X < 0 && _vector.Y > 0) Cursor = Cursors.ScrollNE;
                        if (_vector.X > 0 && _vector.Y < 0) Cursor = Cursors.ScrollSW;
                        if (_vector.X < 0 && _vector.Y < 0) Cursor = Cursors.ScrollSE;
                    }
                } else {
                    if (HorizontalTimer.Enabled) {
                        if (_vector.X > 0) Cursor = Cursors.ScrollW;
                        if (_vector.X < 0) Cursor = Cursors.ScrollE;
                    }
                    if (VerticalTimer.Enabled) {
                        if (_vector.Y > 0) Cursor = Cursors.ScrollN;
                        if (_vector.Y < 0) Cursor = Cursors.ScrollS;
                    }
                }
            }
        }
        void ScrollTickX(object sender, ElapsedEventArgs e) {
            Dispatcher.Invoke((Action)(() => ScrollToHorizontalOffset(HorizontalOffset - _vector.X)));
        }
        void ScrollTickY(object sender, ElapsedEventArgs e) {
            Dispatcher.Invoke((Action)(() => ScrollToVerticalOffset(VerticalOffset - _vector.Y)));
        }
    }
}

Thema bewerten

Seitwert W3C Validator W3
[Casino | Barcodescanner | …finden und gefunden werden | Displayschutzfolie Samsung Galaxy S2 | IconShock Icons | Klassische PC-Spiele ]
[ Webmaster Bibel | IT-System-Kaufleute | Datenrettung Service | Greensmilies | Avatare | Autokredit online | Computer Forum ]


Einfach himmlisch ist auch der Besuch im online Casino.
Man kann auch ohne lästigen Download die spannende Casino Welt erleben und bei Spielen wie Black Jack oder Roulette richtig absahnen.