1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
7
using System.Collections.Generic;
9
using System.Threading;
11
using System.Windows.Controls;
12
using System.Windows.Controls.Primitives;
13
using System.Windows.Media;
14
using System.Windows.Threading;
15
using System.Windows.Input;
19
namespace ICSharpCode.Data.EDMDesigner.Core.UI.Helpers
22
/// Helperklasse, um das Navigieren durch Visual-Trees, suchen von Resourcen in den Visuals und etc... zu erleichtern
24
public class VisualHelper
27
/// Rekursiv durch den Baum des DependencyObjects durchgehen
29
/// <param name="visual"></param>
30
/// <returns></returns>
31
public static IEnumerable<DependencyObject> GetAllVisualChildren(DependencyObject visual)
33
int childrenCount = VisualTreeHelper.GetChildrenCount(visual);
34
for (int i = 0; i < childrenCount; i++)
36
// das Child retournieren
37
DependencyObject child = VisualTreeHelper.GetChild(visual, i);
41
if (VisualTreeHelper.GetChildrenCount(child) > 0)
42
foreach (DependencyObject grandChild in GetAllVisualChildren(child))
43
yield return grandChild;
48
/// liefert das FrameworkElement mit angegebenen Namen
50
/// <param name="visualParent"></param>
51
/// <param name="name"></param>
52
/// <returns></returns>
53
public static FrameworkElement GetChild(DependencyObject visualParent, string name)
56
// Animation zum Anzeigen der neuen Grid starten
57
foreach (DependencyObject child in VisualHelper.GetAllVisualChildren(visualParent))
59
FrameworkElement childElement = child as FrameworkElement;
61
if (childElement != null && childElement.Name != string.Empty)
62
System.Diagnostics.Debug.WriteLine(string.Format("VisualHelper.GetChild: such nach [{0}] child = {1}", name, childElement.Name));
64
if (childElement != null && childElement.Name == name)
73
/// sucht ein SubElement eines 'templated' FrameworkElements
75
/// <param name="subElementName"></param>
76
/// <param name="control"></param>
77
/// <returns></returns>
78
public static ElementType TryFindSubElement<ElementType>(string subElementName, Control control) where ElementType : class
80
if (control == null || control.Template == null)
84
object subObject = control.Template.FindName(subElementName, control);
85
if (subObject == null)
88
ElementType subElement = subObject as ElementType;
89
if (subElement == null)
96
/// sucht ein SubElement eines 'templated' FrameworkElements
98
/// <param name="subElementName"></param>
99
/// <param name="control"></param>
100
/// <returns></returns>
101
public static ElementType FindSubElement<ElementType>(string subElementName, Control control) where ElementType : class
103
if (control == null || control.Template == null)
105
throw new Exception("Element hat kein Template!");
109
object subObject = control.Template.FindName(subElementName, control);
110
if (subObject == null)
112
throw new Exception("Template-Subelement nicht gefunden!");
115
ElementType subElement = subObject as ElementType;
116
if (subElement == null)
118
throw new Exception("Template-Subelement nicht gefunden!");
125
/// Sucht die Resource in dem FrameworkElement (dem 'hierarchischen Baum') aufwärts
127
/// <typeparam name="T"></typeparam>
128
/// <param name="key"></param>
129
/// <param name="element"></param>
130
/// <returns></returns>
131
public static T FindResource<T>(string key, FrameworkElement element)
135
T value = (T)element.FindResource(key);
138
catch (ResourceReferenceKeyNotFoundException)
140
throw new Exception("Control hat kein Template!");
145
/// Sucht die Resource in dem FrameworkElement (dem 'hierarchischen Baum') aufwärts,
146
/// falls nicht gefunden, wird der Defaultwerte zurückgegeben
148
/// <typeparam name="T"></typeparam>
149
/// <param name="key"></param>
150
/// <param name="element"></param>
151
/// <param name="defaultValue"></param>
152
/// <returns></returns>
153
public static T FindResource<T>(string key, FrameworkElement element, T defaultValue)
157
return (T)element.FindResource(key);
159
catch (ResourceReferenceKeyNotFoundException)
165
throw new Exception("Control hat kein Template!");
170
/// Sucht das Element unter der Mouse mit dem Namen name
172
/// <param name="reference"></param>
173
/// <param name="mousePosition"></param>
174
/// <param name="key"></param>
175
/// <returns></returns>
176
public static FrameworkElement FindElementUnderPointer(Visual reference, Point mousePosition, string name)
178
// Hit-test to find out the ItemsControl under the mouse-pointer.
180
_hittedElements = null;
182
VisualTreeHelper.HitTest(reference,
183
new HitTestFilterCallback(VisualHelper.FilterHitTestKeyCallback),
184
new HitTestResultCallback(VisualHelper.HitTestResultCallback),
185
new PointHitTestParameters(mousePosition));
194
_hittedElements = null;
201
/// Sucht das Element unter der Mouse des Typs type
203
/// <param name="reference"></param>
204
/// <param name="mousePosition"></param>
205
/// <param name="type"></param>
206
/// <returns></returns>
207
public static FrameworkElement FindElementUnderPointer(Visual reference, Point mousePosition, Type type)
209
// Hit-test to find out the ItemsControl under the mouse-pointer.
211
_hittedElements = null;
213
VisualTreeHelper.HitTest(reference,
214
new HitTestFilterCallback(VisualHelper.FilterHitTestTypeCallback),
215
new HitTestResultCallback(VisualHelper.HitTestResultCallback),
216
new PointHitTestParameters(mousePosition));
226
_hittedElements = null;
231
public static IEnumerable<FrameworkElement> GetElementsUnderPointer(Visual reference, Point mousePosition)
233
// Hit-test to find out the ItemsControl under the mouse-pointer.
235
_hittedElements = new List<FrameworkElement>();
238
VisualTreeHelper.HitTest(reference,
239
new HitTestFilterCallback(VisualHelper.NoFilterHitTestCallback),
240
new HitTestResultCallback(VisualHelper.HitTestResultCallback),
241
new PointHitTestParameters(mousePosition));
245
return _hittedElements;
250
_hittedElements = null;
256
private static FrameworkElement _element = null;
257
private static List<FrameworkElement> _hittedElements = null;
258
private static string _name = null;
259
private static Type _type = null;
261
private static HitTestFilterBehavior FilterHitTestKeyCallback(DependencyObject target)
263
FrameworkElement element = target as FrameworkElement;
264
if (element != null && element.Name == _name)
266
if (_hittedElements != null)
267
_hittedElements.Add(element);
269
return HitTestFilterBehavior.Stop;
273
if (_hittedElements != null)
274
_hittedElements.Add(element);
275
return HitTestFilterBehavior.Continue;
279
private static HitTestFilterBehavior FilterHitTestTypeCallback(DependencyObject target)
281
if (target.GetType().IsAssignableFrom(_type))
283
_element = target as FrameworkElement;
284
if (_hittedElements != null)
285
_hittedElements.Add(_element);
286
return HitTestFilterBehavior.Stop;
290
if (_hittedElements != null)
291
_hittedElements.Add(target as FrameworkElement);
292
return HitTestFilterBehavior.Continue;
296
private static HitTestFilterBehavior NoFilterHitTestCallback(DependencyObject target)
298
if (_hittedElements != null && target is FrameworkElement && (target as FrameworkElement).IsVisible)
299
_hittedElements.Add(target as FrameworkElement);
300
return HitTestFilterBehavior.Continue;
303
private static HitTestResultBehavior HitTestResultCallback(HitTestResult result)
305
return HitTestResultBehavior.Continue;
309
/// Gibt ein visuelles Child eines bestimmten Typs eines DependencyObjects zurück.
311
/// <typeparam name="TChild"></typeparam>
312
/// <param name="obj"></param>
313
/// <returns></returns>
314
public static TChild GetVisualChild<TChild>(DependencyObject obj) where TChild : DependencyObject
319
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
321
// TODO: Was passiert hier, wenn ich kein Visual, sondern z.B. ein Run will?
322
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
323
if (child != null && child is TChild)
324
return (TChild)child;
327
TChild childOfChild = GetVisualChild<TChild>(child);
328
if (childOfChild != null)
336
/// Gibt ein visuelles Child mit einem bestimmten Namen eines DependencyObjects zurück.
338
/// <typeparam name="TChild"></typeparam>
339
/// <param name="obj"></param>
340
/// <param name="name"></param>
341
/// <returns></returns>
342
public static TChild GetVisualChild<TChild>(DependencyObject obj, string name) where TChild : FrameworkElement
347
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
349
// TODO: Was passiert hier, wenn ich kein Visual, sondern z.B. ein Run will?
350
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
351
if (child != null && child is TChild && ((TChild)child).Name == name)
352
return (TChild)child;
355
TChild childOfChild = GetVisualChild<TChild>(child, name);
356
if (childOfChild != null)
364
/// Gibt ein visuelles Child mit einem bestimmten Namen eines DependencyObjects zurück.
366
/// <param name="obj"></param>
367
/// <param name="name"></param>
368
/// <returns></returns>
369
/// <remarks>Ich habe diese Methode hier aus Rückwärtskompatibilitätsgründen zurückgelassen.</remarks>
370
public static FrameworkElement GetVisualChild(DependencyObject obj, string name)
372
return GetVisualChild<FrameworkElement>(obj, name);
376
/// Gibt ein visuelles Child, welches eine übergebene Bedingung erfüllt zurück
378
/// <typeparam name="TChild"></typeparam>
379
/// <param name="obj"></param>
380
/// <param name="comparePredicate"></param>
381
/// <returns></returns>
382
public static TChild GetVisualChild<TChild>(DependencyObject obj, Func<DependencyObject, bool> comparePredicate) where TChild : FrameworkElement
387
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
389
// TODO: Was passiert hier, wenn ich kein Visual, sondern z.B. ein Run will?
390
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
391
if (child != null && child is TChild && child is DependencyObject && comparePredicate(child as DependencyObject))
392
return (TChild)child;
395
TChild childOfChild = GetVisualChild<TChild>(child, comparePredicate);
396
if (childOfChild != null)
404
/// Gibt ein visuelles Child, welches eine übergebene Bedingung erfüllt zurück
406
/// <param name="obj"></param>
407
/// <param name="name"></param>
408
/// <returns></returns>
409
/// <remarks>Ich habe diese Methode hier aus Rückwärtskompatibilitätsgründen zurückgelassen.</remarks>
410
public static FrameworkElement GetVisualChild(DependencyObject obj, Func<DependencyObject, bool> comparePredicate)
412
return GetVisualChild<FrameworkElement>(obj, comparePredicate);
416
/// Gibt einen visuellen Parent eines bestimmten Typs eines DependencyObjects zurück.
418
/// <typeparam name="TParent"></typeparam>
419
/// <param name="obj"></param>
420
/// <returns></returns>
421
public static TParent GetVisualParent<TParent>(DependencyObject obj) where TParent : DependencyObject
423
return GetVisualParent<TParent>(obj, true);
427
/// Gibt einen visuellen Parent mit einem speziellen Namen eines DependencyObjects zurück.
429
/// <typeparam name="TParent"></typeparam>
430
/// <param name="obj"></param>
431
/// <param name="parentName"></param>
432
/// <returns></returns>
433
public static FrameworkElement GetVisualParent(DependencyObject obj, string parentName)
435
return GetVisualParent<FrameworkElement>(obj, true, parent => ((FrameworkElement)parent).Name == parentName);
439
/// Gibt einen visuellen Parent eines bestimmten Typs eines DependencyObjects zurück.
441
/// <typeparam name="TParent"></typeparam>
442
/// <param name="obj"></param>
443
/// <param name="walkThroughPopupRoot">Gibt an, ob auch über einen PopupRoot weitergemacht werden soll.</param>
444
/// <returns></returns>
445
public static TParent GetVisualParent<TParent>(DependencyObject obj, bool walkThroughPopupRoot) where TParent : DependencyObject
450
return GetVisualParent<TParent>(obj, walkThroughPopupRoot,
451
parent => parent != null && parent is TParent);
455
/// Gibt einen visuellen Parent eines bestimmten Typs eines DependencyObjects zurück.
457
/// <typeparam name="TParent"></typeparam>
458
/// <param name="obj"></param>
459
/// <param name="walkThroughPopupRoot">Gibt an, ob auch über einen PopupRoot weitergemacht werden soll.</param>
460
/// <param name="comparePredicate">Func mit dem Parent-Vergleich</param>
461
/// <returns></returns>
462
public static TParent GetVisualParent<TParent>(DependencyObject obj, bool walkThroughPopupRoot,
463
Func<DependencyObject, bool> comparePredicate)
464
where TParent : DependencyObject
469
// Wenn es kein Visual (z.B. Run) oder ein PopupRoot ist, dann komme ich nur im LogicalTree weiter voran...
470
DependencyObject parent = (!(obj is Visual) || (walkThroughPopupRoot && obj.GetType().Name == "PopupRoot")) ?
471
LogicalTreeHelper.GetParent(obj) : VisualTreeHelper.GetParent(obj);
472
if (comparePredicate(parent))
473
return (TParent)parent;
475
return GetVisualParent<TParent>(parent, walkThroughPopupRoot, comparePredicate);
478
public static object GetVisualParentObject(DependencyObject obj, bool walkThroughPopupRoot,
479
Func<DependencyObject, bool> comparePredicate)
484
// Wenn es kein Visual (z.B. Run) oder ein PopupRoot ist, dann komme ich nur im LogicalTree weiter voran...
485
DependencyObject parent = (!(obj is Visual) || (walkThroughPopupRoot && obj.GetType().Name == "PopupRoot")) ?
486
LogicalTreeHelper.GetParent(obj) : VisualTreeHelper.GetParent(obj);
487
if (comparePredicate(parent))
490
return GetVisualParentObject(parent, walkThroughPopupRoot, comparePredicate);
494
/// Runs an Action in the current dispatcher.
496
/// <param name="actionToRun"></param>
497
public static void RunInDispatcher(Action actionToRun)
499
if (Application.Current != null)
500
RunInDispatcher(Application.Current.Dispatcher, actionToRun);
504
/// Runs an Action in a given dispatcher.
506
/// <param name="dispatcher"></param>
507
/// <param name="actionToRun"></param>
508
public static void RunInDispatcher(Dispatcher dispatcher, Action actionToRun)
510
dispatcher.Invoke(DispatcherPriority.Background, actionToRun);
514
/// Runs through all items in the dispatcher.
516
public static void DoEvents()
518
if (Application.Current != null)
519
DoEvents(Application.Current.Dispatcher);
523
/// Gives DispatcherFrames of the given Dispatcher priority, if
524
/// their DispatcherPriority is higher than "DispatcherPriority.Background".
526
/// <param name="dispatcherToPause"></param>
527
public static void DoEvents(Dispatcher dispatcherToPause)
529
dispatcherToPause.Invoke(DispatcherPriority.Background, new System.Action(() => { }));