8 changed files with 123 additions and 17 deletions
@ -0,0 +1,95 @@ |
|||||
|
// Copyright (c) The Perspex Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using Perspex.Controls; |
||||
|
using Perspex.Data; |
||||
|
|
||||
|
namespace Perspex.Markup.Xaml.Data |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides delayed bindings for controls.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// The XAML engine applies its bindings in a delayed manner where bindings are only applied
|
||||
|
/// when a control is added to the visual tree. This was done because applying bindings as soon
|
||||
|
/// as controls are created means that long-form bindings (i.e. bindings that don't use the
|
||||
|
/// `{Binding}` markup extension) don't work as the binding is applied to the property before
|
||||
|
/// the binding properties are set, and looking at WPF it uses a similar mechanism for bindings
|
||||
|
/// that come from XAML.
|
||||
|
/// </remarks>
|
||||
|
public static class DelayedBinding |
||||
|
{ |
||||
|
private static ConditionalWeakTable<IControl, List<Entry>> _entries = |
||||
|
new ConditionalWeakTable<IControl, List<Entry>>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Adds a delayed binding to a control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="target">The control.</param>
|
||||
|
/// <param name="property">The property on the control to bind to.</param>
|
||||
|
/// <param name="binding">The binding.</param>
|
||||
|
public static void Add(IControl target, PerspexProperty property, IBinding binding) |
||||
|
{ |
||||
|
if (target.IsAttachedToVisualTree) |
||||
|
{ |
||||
|
target.Bind(property, binding); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
List<Entry> bindings; |
||||
|
|
||||
|
if (!_entries.TryGetValue(target, out bindings)) |
||||
|
{ |
||||
|
bindings = new List<Entry>(); |
||||
|
_entries.Add(target, bindings); |
||||
|
|
||||
|
// TODO: Make this a weak event listener.
|
||||
|
target.AttachedToVisualTree += ApplyBindings; |
||||
|
} |
||||
|
|
||||
|
bindings.Add(new Entry(binding, property)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Applies any delayed bindings to a control.
|
||||
|
/// </summary>
|
||||
|
/// <param name="control">The control.</param>
|
||||
|
public static void ApplyBindings(IControl control) |
||||
|
{ |
||||
|
List<Entry> bindings; |
||||
|
|
||||
|
if (_entries.TryGetValue(control, out bindings)) |
||||
|
{ |
||||
|
foreach (var binding in bindings) |
||||
|
{ |
||||
|
control.Bind(binding.Property, binding.Binding); |
||||
|
} |
||||
|
|
||||
|
_entries.Remove(control); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static void ApplyBindings(object sender, VisualTreeAttachmentEventArgs e) |
||||
|
{ |
||||
|
var target = (IControl)sender; |
||||
|
ApplyBindings(target); |
||||
|
target.AttachedToVisualTree -= ApplyBindings; |
||||
|
} |
||||
|
|
||||
|
private class Entry |
||||
|
{ |
||||
|
public Entry(IBinding binding, PerspexProperty property) |
||||
|
{ |
||||
|
Binding = binding; |
||||
|
Property = property; |
||||
|
} |
||||
|
|
||||
|
public IBinding Binding { get; } |
||||
|
public PerspexProperty Property { get; } |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1 +1 @@ |
|||||
Subproject commit c2b86b9d1ae638c788f44bc63d17911986d766fb |
Subproject commit 43698917d00c5aaf789605fd7434798a748fba89 |
||||
Loading…
Reference in new issue