Browse Source

Updated implementation based on PR feedback.

pull/1209/head
Jeremy Koritzinsky 9 years ago
parent
commit
5e1f5046c0
  1. 15
      src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
  2. 2
      src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs
  3. 5
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
  4. 92
      src/Markup/Avalonia.Markup/ControlLocator.cs

15
src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs

@ -219,18 +219,9 @@ namespace Avalonia.Markup.Xaml.Data
{
Contract.Requires<ArgumentNullException>(target != null);
if (relativeSource.AncestorType == null)
{
return new ExpressionObserver(
ControlLocator.Track(target, relativeSource.AncestorLevel - 1),
path);
}
else
{
return new ExpressionObserver(
ControlLocator.Track(target, relativeSource.AncestorType, relativeSource.AncestorLevel - 1),
path);
}
return new ExpressionObserver(
ControlLocator.Track(target, relativeSource.AncestorType != null ? relativeSource.Tree : TreeType.Logical, relativeSource.AncestorLevel - 1, relativeSource.AncestorType),
path);
}
private ExpressionObserver CreateSourceObserver(

2
src/Markup/Avalonia.Markup.Xaml/Data/RelativeSource.cs

@ -87,5 +87,7 @@ namespace Avalonia.Markup.Xaml.Data
/// Gets or sets a value that describes the type of relative source lookup.
/// </summary>
public RelativeSourceMode Mode { get; set; }
public TreeType Tree { get; set; } = TreeType.Visual;
}
}

5
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

@ -103,7 +103,10 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
}
else if (path.StartsWith("$"))
{
var relativeSource = new RelativeSource();
var relativeSource = new RelativeSource
{
Tree = TreeType.Logical
};
result.RelativeSource = relativeSource;
var dot = path.IndexOf('.');
string relativeSourceMode;

92
src/Markup/Avalonia.Markup/ControlLocator.cs

@ -11,6 +11,21 @@ using Avalonia.VisualTree;
namespace Avalonia.Markup
{
/// <summary>
/// The type of tree via which to track a control.
/// </summary>
public enum TreeType
{
/// <summary>
/// The visual tree.
/// </summary>
Visual,
/// <summary>
/// The logical tree.
/// </summary>
Logical,
}
/// <summary>
/// Locates controls relative to other controls.
/// </summary>
@ -68,12 +83,44 @@ namespace Avalonia.Markup
/// <param name="relativeTo">
/// The control relative from which the other control should be found.
/// </param>
/// <param name="ancestorType">The type of the ancestor to find.</param>
/// <param name="tree">The tree via which to track the control.</param>
/// <param name="ancestorLevel">
/// The level of ancestor control to look for. Use 0 for the first ancestor of the
/// requested type.
/// </param>
public static IObservable<IControl> Track(IControl relativeTo, Type ancestorType, int ancestorLevel)
/// <param name="ancestorType">The type of the ancestor to find.</param>
public static IObservable<IControl> Track(IControl relativeTo, TreeType tree, int ancestorLevel, Type ancestorType = null)
{
return TrackAttachmentToTree(relativeTo, tree).Select(isAttachedToTree =>
{
if (isAttachedToTree)
{
if (tree == TreeType.Visual)
{
return relativeTo.GetVisualAncestors()
.Where(x => ancestorType?.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()) ?? true)
.ElementAtOrDefault(ancestorLevel) as IControl;
}
else
{
return relativeTo.GetLogicalAncestors()
.Where(x => ancestorType?.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()) ?? true)
.ElementAtOrDefault(ancestorLevel) as IControl;
}
}
else
{
return null;
}
});
}
private static IObservable<bool> TrackAttachmentToTree(IControl relativeTo, TreeType tree)
{
return tree == TreeType.Visual ? TrackAttachmentToVisualTree(relativeTo) : TrackAttachmentToLogicalTree(relativeTo);
}
private static IObservable<bool> TrackAttachmentToVisualTree(IControl relativeTo)
{
var attached = Observable.FromEventPattern<VisualTreeAttachmentEventArgs>(
x => relativeTo.AttachedToVisualTree += x,
@ -86,32 +133,11 @@ namespace Avalonia.Markup
x => relativeTo.DetachedFromVisualTree -= x)
.Select(x => false);
return attached.Merge(detached).Select(isAttachedToVisualTree =>
{
if (isAttachedToVisualTree)
{
return relativeTo.GetVisualAncestors()
.Where(x => ancestorType.GetTypeInfo().IsAssignableFrom(x.GetType().GetTypeInfo()))
.ElementAtOrDefault(ancestorLevel) as IControl;
}
else
{
return null;
}
});
var attachmentStatus = attached.Merge(detached);
return attachmentStatus;
}
/// <summary>
/// Tracks a typed logical ancestor control.
/// </summary>
/// <param name="relativeTo">
/// The control relative from which the other control should be found.
/// </param>
/// <param name="ancestorLevel">
/// The level of ancestor control to look for. Use 0 for the first ancestor of the
/// requested type.
/// </param>
public static IObservable<IControl> Track(IControl relativeTo, int ancestorLevel)
private static IObservable<bool> TrackAttachmentToLogicalTree(IControl relativeTo)
{
var attached = Observable.FromEventPattern<LogicalTreeAttachmentEventArgs>(
x => relativeTo.AttachedToLogicalTree += x,
@ -124,18 +150,8 @@ namespace Avalonia.Markup
x => relativeTo.DetachedFromLogicalTree += x)
.Select(x => false);
return attached.Merge(detached).Select(isAttachedToLogicalTree =>
{
if (isAttachedToLogicalTree)
{
return relativeTo.GetLogicalAncestors()
.ElementAtOrDefault(ancestorLevel) as IControl;
}
else
{
return null;
}
});
var attachmentStatus = attached.Merge(detached);
return attachmentStatus;
}
}
}

Loading…
Cancel
Save