forked from ClassIsland/ClassIsland
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathVisualTargetPresentationSource.cs
166 lines (143 loc) · 4.62 KB
/
VisualTargetPresentationSource.cs
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
// ReSharper disable once CheckNamespace
namespace Walterlv;
/// <summary>
/// The VisualTargetPresentationSource represents the root
/// of a visual subtree owned by a different thread that the
/// visual tree in which is is displayed.
/// </summary>
/// <remarks>
/// A HostVisual belongs to the same UI thread that owns the
/// visual tree in which it resides.
///
/// A HostVisual can reference a VisualTarget owned by another
/// thread.
///
/// A VisualTarget has a root visual.
///
/// VisualTargetPresentationSource wraps the VisualTarget and
/// enables basic functionality like Loaded, which depends on
/// a PresentationSource being available.
/// </remarks>
public class VisualTargetPresentationSource : PresentationSource, IDisposable
{
public VisualTargetPresentationSource(HostVisual hostVisual)
{
_visualTarget = new VisualTarget(hostVisual);
}
public override Visual RootVisual
{
get => _visualTarget.RootVisual;
set
{
if (IsDisposed)
{
throw new ObjectDisposedException("VisualTarget");
}
var oldRoot = _visualTarget.RootVisual;
// Set the root visual of the VisualTarget. This visual will
// now be used to visually compose the scene.
_visualTarget.RootVisual = value;
// Hook the SizeChanged event on framework elements for all
// future changed to the layout size of our root, and manually
// trigger a size change.
if (oldRoot is FrameworkElement oldRootFe)
{
oldRootFe.SizeChanged -= root_SizeChanged;
}
if (value is FrameworkElement rootFe)
{
rootFe.SizeChanged += root_SizeChanged;
rootFe.DataContext = _dataContext;
if (_propertyName != null)
{
var myBinding = new Binding(_propertyName)
{
Source = _dataContext
};
rootFe.SetBinding(TextBlock.TextProperty, myBinding);
}
}
// Tell the PresentationSource that the root visual has
// changed. This kicks off a bunch of stuff like the
// Loaded event.
RootChanged(oldRoot, value);
// Kickoff layout...
if (value is UIElement rootElement)
{
rootElement.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
rootElement.Arrange(new Rect(rootElement.DesiredSize));
}
}
}
public object DataContext
{
get => _dataContext;
set
{
if (IsDisposed)
{
throw new ObjectDisposedException("VisualTarget");
}
if (_dataContext == value)
{
return;
}
_dataContext = value;
if (_visualTarget.RootVisual is FrameworkElement rootElement)
{
rootElement.DataContext = _dataContext;
}
}
}
public string PropertyName
{
get => _propertyName;
set
{
if (IsDisposed)
{
throw new ObjectDisposedException("VisualTarget");
}
_propertyName = value;
if (_visualTarget.RootVisual is TextBlock rootElement)
{
if (!rootElement.CheckAccess())
{
throw new InvalidOperationException("What?");
}
var myBinding = new Binding(_propertyName)
{
Source = _dataContext
};
rootElement.SetBinding(TextBlock.TextProperty, myBinding);
}
}
}
public event SizeChangedEventHandler SizeChanged;
public override bool IsDisposed => _isDisposed;
protected override CompositionTarget GetCompositionTargetCore()
{
return _visualTarget;
}
private void root_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (IsDisposed)
{
return;
}
SizeChanged?.Invoke(this, e);
}
private readonly VisualTarget _visualTarget;
private object _dataContext;
private string _propertyName;
private bool _isDisposed;
public void Dispose()
{
_visualTarget?.Dispose();
_isDisposed = true;
}
}