diff --git a/appveyor.yml b/appveyor.yml
index aa8c19ace4..76d1ae3e1c 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -23,10 +23,6 @@ before_build:
- git submodule update --init
build_script:
- ps: .\build.ps1 -Target "AppVeyor" -Platform "$env:platform" -Configuration "$env:configuration"
-after_build:
-- "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%"
-- pip install codecov
-- codecov -f "./artifacts/coverage.xml"
test: off
artifacts:
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index 685bf83a75..e96679e643 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -326,7 +326,7 @@ namespace Avalonia
object anchor = null,
bool enableDataValidation = false)
{
- return new InstancedBinding(_source);
+ return InstancedBinding.OneWay(_source);
}
}
}
diff --git a/src/Avalonia.Base/Data/IndexerBinding.cs b/src/Avalonia.Base/Data/IndexerBinding.cs
index 729b21b0d9..6b5a84989a 100644
--- a/src/Avalonia.Base/Data/IndexerBinding.cs
+++ b/src/Avalonia.Base/Data/IndexerBinding.cs
@@ -31,13 +31,18 @@ namespace Avalonia.Data
targetProperty.GetMetadata(target.GetType()).DefaultBindingMode :
Mode;
- if (mode == BindingMode.TwoWay)
+ switch (mode)
{
- return new InstancedBinding(Source.GetSubject(Property), mode);
- }
- else
- {
- return new InstancedBinding(Source.GetObservable(Property), mode);
+ case BindingMode.OneTime:
+ return InstancedBinding.OneTime(Source.GetObservable(Property));
+ case BindingMode.OneWay:
+ return InstancedBinding.OneWay(Source.GetObservable(Property));
+ case BindingMode.OneWayToSource:
+ return InstancedBinding.OneWayToSource(Source.GetSubject(Property));
+ case BindingMode.TwoWay:
+ return InstancedBinding.TwoWay(Source.GetSubject(Property));
+ default:
+ throw new NotSupportedException("Unsupported BindingMode.");
}
}
}
diff --git a/src/Avalonia.Base/Data/InstancedBinding.cs b/src/Avalonia.Base/Data/InstancedBinding.cs
index 899cfed1fe..dc35fe076b 100644
--- a/src/Avalonia.Base/Data/InstancedBinding.cs
+++ b/src/Avalonia.Base/Data/InstancedBinding.cs
@@ -14,71 +14,35 @@ namespace Avalonia.Data
/// property on a control's DataContext"; this class represents a binding that has been
/// *instanced* by calling
/// on a target object.
- ///
- /// When a binding is initiated, it can return one of 3 possible sources for the binding:
- /// - An which can be used for any type of binding.
- /// - An which can be used for all types of bindings except
- /// and .
- /// - A plain object, which can only represent a binding.
///
public class InstancedBinding
{
///
/// Initializes a new instance of the class.
///
- ///
- /// The value used for the binding.
- ///
- /// The binding priority.
- public InstancedBinding(object value,
- BindingPriority priority = BindingPriority.LocalValue)
- {
- Mode = BindingMode.OneTime;
- Priority = priority;
- Value = value;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The observable for a one-way binding.
+ /// The binding source.
/// The binding mode.
- /// The binding priority.
- public InstancedBinding(
- IObservable observable,
- BindingMode mode = BindingMode.OneWay,
- BindingPriority priority = BindingPriority.LocalValue)
+ /// The priority of the binding.
+ ///
+ /// This constructor can be used to create any type of binding and as such requires an
+ /// as the binding source because this is the only binding
+ /// source which can be used for all binding modes. If you wish to create an instance with
+ /// something other than a subject, use one of the static creation methods on this class.
+ ///
+ public InstancedBinding(ISubject subject, BindingMode mode, BindingPriority priority)
{
- Contract.Requires(observable != null);
-
- if (mode == BindingMode.OneWayToSource || mode == BindingMode.TwoWay)
- {
- throw new ArgumentException(
- "Invalid BindingResult mode: OneWayToSource and TwoWay bindings" +
- "require a Subject.");
- }
+ Contract.Requires(subject != null);
Mode = mode;
Priority = priority;
- Observable = observable;
+ Value = subject;
}
- ///
- /// Initializes a new instance of the class.
- ///
- /// The subject for a two-way binding.
- /// The binding mode.
- /// The binding priority.
- public InstancedBinding(
- ISubject subject,
- BindingMode mode = BindingMode.OneWay,
- BindingPriority priority = BindingPriority.LocalValue)
+ private InstancedBinding(object value, BindingMode mode, BindingPriority priority)
{
- Contract.Requires(subject != null);
-
Mode = mode;
Priority = priority;
- Subject = subject;
+ Value = value;
}
///
@@ -92,18 +56,101 @@ namespace Avalonia.Data
public BindingPriority Priority { get; }
///
- /// Gets the value used for a binding.
+ /// Gets the value or source of the binding.
///
public object Value { get; }
///
- /// Gets the observable for a one-way binding.
+ /// Gets the as an observable.
///
- public IObservable Observable { get; }
+ public IObservable Observable => Value as IObservable;
///
- /// Gets the subject for a two-way binding.
+ /// Gets the as a subject.
///
- public ISubject Subject { get; }
+ public ISubject Subject => Value as ISubject;
+
+ ///
+ /// Creates a new one-time binding with a fixed value.
+ ///
+ /// The value.
+ /// The priority of the binding.
+ /// An instance.
+ public static InstancedBinding OneTime(
+ object value,
+ BindingPriority priority = BindingPriority.LocalValue)
+ {
+ return new InstancedBinding(value, BindingMode.OneTime, priority);
+ }
+
+ ///
+ /// Creates a new one-time binding.
+ ///
+ /// The source observable.
+ /// The priority of the binding.
+ /// An instance.
+ public static InstancedBinding OneTime(
+ IObservable observable,
+ BindingPriority priority = BindingPriority.LocalValue)
+ {
+ Contract.Requires(observable != null);
+
+ return new InstancedBinding(observable, BindingMode.OneTime, priority);
+ }
+
+ ///
+ /// Creates a new one-way binding.
+ ///
+ /// The source observable.
+ /// The priority of the binding.
+ /// An instance.
+ public static InstancedBinding OneWay(
+ IObservable observable,
+ BindingPriority priority = BindingPriority.LocalValue)
+ {
+ Contract.Requires(observable != null);
+
+ return new InstancedBinding(observable, BindingMode.OneWay, priority);
+ }
+
+ ///
+ /// Creates a new one-way to source binding.
+ ///
+ /// The binding source.
+ /// The priority of the binding.
+ /// An instance.
+ public static InstancedBinding OneWayToSource(
+ ISubject subject,
+ BindingPriority priority = BindingPriority.LocalValue)
+ {
+ Contract.Requires(subject != null);
+
+ return new InstancedBinding(subject, BindingMode.OneWayToSource, priority);
+ }
+
+ ///
+ /// Creates a new two-way binding.
+ ///
+ /// The binding source.
+ /// The priority of the binding.
+ /// An instance.
+ public static InstancedBinding TwoWay(
+ ISubject subject,
+ BindingPriority priority = BindingPriority.LocalValue)
+ {
+ Contract.Requires(subject != null);
+
+ return new InstancedBinding(subject, BindingMode.TwoWay, priority);
+ }
+
+ ///
+ /// Creates a copy of the with a different priority.
+ ///
+ /// The priority of the binding.
+ /// An instance.
+ public InstancedBinding WithPriority(BindingPriority priority)
+ {
+ return new InstancedBinding(Value, Mode, priority);
+ }
}
}
diff --git a/src/Avalonia.Controls/Control.cs b/src/Avalonia.Controls/Control.cs
index a7aafbf6e8..d4777b2f8a 100644
--- a/src/Avalonia.Controls/Control.cs
+++ b/src/Avalonia.Controls/Control.cs
@@ -774,7 +774,9 @@ namespace Avalonia.Controls
foreach (var child in control.LogicalChildren)
{
- if (child is Control c && !c.IsSet(DataContextProperty))
+ if (child is Control c &&
+ c.InheritanceParent == control &&
+ !c.IsSet(DataContextProperty))
{
DataContextNotifying(c, notifying);
}
diff --git a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
index 04e6ece832..2e55dd3552 100644
--- a/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
+++ b/src/Avalonia.Controls/Templates/FuncTreeDataTemplate.cs
@@ -62,7 +62,7 @@ namespace Avalonia.Controls.Templates
/// The child items, or null if no child items.
public InstancedBinding ItemsSelector(object item)
{
- return new InstancedBinding(this?._itemsSelector(item));
+ return InstancedBinding.OneTime(this?._itemsSelector(item));
}
///
diff --git a/src/Avalonia.Remote.Protocol/BsonStreamTransport.cs b/src/Avalonia.Remote.Protocol/BsonStreamTransport.cs
index 604703cac8..93a3b60599 100644
--- a/src/Avalonia.Remote.Protocol/BsonStreamTransport.cs
+++ b/src/Avalonia.Remote.Protocol/BsonStreamTransport.cs
@@ -64,7 +64,6 @@ namespace Avalonia.Remote.Protocol
async Task Reader()
{
- Task.Yield();
try
{
while (true)
@@ -147,4 +146,4 @@ namespace Avalonia.Remote.Protocol
public event Action OnMessage;
public event Action OnException;
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs
index eb5218cd6f..95db18a465 100644
--- a/src/Avalonia.Styling/Styling/Setter.cs
+++ b/src/Avalonia.Styling/Styling/Setter.cs
@@ -135,45 +135,47 @@ namespace Avalonia.Styling
private InstancedBinding Clone(InstancedBinding sourceInstance, IStyle style, IObservable activator)
{
- InstancedBinding cloned;
-
if (activator != null)
{
var description = style?.ToString();
- if (sourceInstance.Mode == BindingMode.TwoWay || sourceInstance.Mode == BindingMode.OneWayToSource)
- {
- var activated = new ActivatedSubject(activator, sourceInstance.Subject, description);
- cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger);
- }
- else if (sourceInstance.Mode == BindingMode.OneTime)
- {
- var activated = new ActivatedValue(activator, sourceInstance.Value, description);
- cloned = new InstancedBinding(activated, BindingMode.OneWay, BindingPriority.StyleTrigger);
- }
- else
+ switch (sourceInstance.Mode)
{
- var activated = new ActivatedObservable(activator, sourceInstance.Observable ?? sourceInstance.Subject, description);
- cloned = new InstancedBinding(activated, sourceInstance.Mode, BindingPriority.StyleTrigger);
+ case BindingMode.OneTime:
+ if (sourceInstance.Observable != null)
+ {
+ var activated = new ActivatedObservable(activator, sourceInstance.Observable, description);
+ return InstancedBinding.OneTime(activated, BindingPriority.StyleTrigger);
+ }
+ else
+ {
+ var activated = new ActivatedValue(activator, sourceInstance.Value, description);
+ return InstancedBinding.OneTime(activated, BindingPriority.StyleTrigger);
+ }
+ case BindingMode.OneWay:
+ {
+ var activated = new ActivatedObservable(activator, sourceInstance.Observable, description);
+ return InstancedBinding.OneWay(activated, BindingPriority.StyleTrigger);
+ }
+ case BindingMode.OneWayToSource:
+ {
+ var activated = new ActivatedSubject(activator, sourceInstance.Subject, description);
+ return InstancedBinding.OneWayToSource(activated, BindingPriority.StyleTrigger);
+ }
+ case BindingMode.TwoWay:
+ {
+ var activated = new ActivatedSubject(activator, sourceInstance.Subject, description);
+ return InstancedBinding.TwoWay(activated, BindingPriority.StyleTrigger);
+ }
+ default:
+ throw new NotSupportedException("Unsupported BindingMode.");
}
+
}
else
{
- if (sourceInstance.Subject != null)
- {
- cloned = new InstancedBinding(sourceInstance.Subject, sourceInstance.Mode, BindingPriority.Style);
- }
- else if (sourceInstance.Observable != null)
- {
- cloned = new InstancedBinding(sourceInstance.Observable, sourceInstance.Mode, BindingPriority.Style);
- }
- else
- {
- cloned = new InstancedBinding(sourceInstance.Value, BindingPriority.Style);
- }
+ return sourceInstance.WithPriority(BindingPriority.StyleTrigger);
}
-
- return cloned;
}
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index e07c22d750..a1db5c2915 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -39,7 +39,6 @@
-
@@ -73,8 +72,6 @@
-
-
diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
index ae9d2d87f1..2a65504347 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
@@ -83,6 +83,8 @@ namespace Avalonia.Markup.Xaml.Data
///
public object Source { get; set; }
+ internal WeakReference DefaultAnchor { get; set; }
+
///
public InstancedBinding Initiate(
IAvaloniaObject target,
@@ -91,6 +93,7 @@ namespace Avalonia.Markup.Xaml.Data
bool enableDataValidation = false)
{
Contract.Requires(target != null);
+ anchor = anchor ?? DefaultAnchor?.Target;
enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue;
diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs
index 621e06efba..3c29ed3a39 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs
@@ -62,41 +62,20 @@ namespace Avalonia.Markup.Xaml.Data
}
var targetType = targetProperty?.PropertyType ?? typeof(object);
- var result = new BehaviorSubject(AvaloniaProperty.UnsetValue);
var children = Bindings.Select(x => x.Initiate(target, null));
var input = children.Select(x => x.Subject).CombineLatest().Select(x => ConvertValue(x, targetType));
- input.Subscribe(result);
- return new InstancedBinding(result, Mode, Priority);
- }
-
- ///
- /// Applies a binding subject to a property on an instance.
- ///
- /// The target instance.
- /// The target property.
- /// The binding subject.
- internal void Bind(IAvaloniaObject target, AvaloniaProperty property, ISubject subject)
- {
var mode = Mode == BindingMode.Default ?
- property.GetMetadata(target.GetType()).DefaultBindingMode : Mode;
+ targetProperty.GetMetadata(target.GetType()).DefaultBindingMode : Mode;
switch (mode)
{
- case BindingMode.Default:
- case BindingMode.OneWay:
- target.Bind(property, subject, Priority);
- break;
- case BindingMode.TwoWay:
- throw new NotSupportedException("TwoWay MultiBinding not currently supported.");
case BindingMode.OneTime:
- target.GetObservable(Control.DataContextProperty).Subscribe(dataContext =>
- {
- subject.Take(1).Subscribe(x => target.SetValue(property, x, Priority));
- });
- break;
- case BindingMode.OneWayToSource:
- target.GetObservable(property).Subscribe(subject);
- break;
+ return InstancedBinding.OneTime(input, Priority);
+ case BindingMode.OneWay:
+ return InstancedBinding.OneWay(input, Priority);
+ default:
+ throw new NotSupportedException(
+ "MultiBinding currently only supports OneTime and OneWay BindingMode.");
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs
deleted file mode 100644
index 787aebbdc6..0000000000
--- a/src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) The Avalonia 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.Reactive.Disposables;
-using System.Reactive.Linq;
-using System.Reactive.Subjects;
-using Avalonia.Controls;
-using Avalonia.Data;
-using Avalonia.Styling;
-
-namespace Avalonia.Markup.Xaml.Data
-{
- public class StyleResourceBinding : IBinding
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The resource name.
- public StyleResourceBinding(string name)
- {
- Name = name;
- }
-
- ///
- public BindingMode Mode => BindingMode.OneTime;
-
- ///
- /// Gets the resource name.
- ///
- public string Name { get; }
-
- ///
- public BindingPriority Priority => BindingPriority.LocalValue;
-
- ///
- public InstancedBinding Initiate(
- IAvaloniaObject target,
- AvaloniaProperty targetProperty,
- object anchor = null,
- bool enableDataValidation = false)
- {
- var host = (target as IControl) ?? (anchor as IControl);
- var style = anchor as IStyle;
- var resource = AvaloniaProperty.UnsetValue;
-
- if (host != null)
- {
- resource = host.FindResource(Name);
- }
- else if (style != null)
- {
- if (!style.TryGetResource(Name, out resource))
- {
- resource = AvaloniaProperty.UnsetValue;
- }
- }
-
- if (resource != AvaloniaProperty.UnsetValue)
- {
- return new InstancedBinding(resource, Priority);
- }
- else
- {
- return null;
- }
- }
- }
-}
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
index ee8ce03288..c6705cbb4b 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs
@@ -34,19 +34,18 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
var pathInfo = ParsePath(Path, descriptorContext);
ValidateState(pathInfo);
- return XamlBinding.FromMarkupExtensionContext(
- new Binding
- {
- Converter = Converter,
- ConverterParameter = ConverterParameter,
- ElementName = pathInfo.ElementName ?? ElementName,
- FallbackValue = FallbackValue,
- Mode = Mode,
- Path = pathInfo.Path,
- Priority = Priority,
- RelativeSource = pathInfo.RelativeSource ?? RelativeSource,
- },
- serviceProvider);
+ return new Binding
+ {
+ Converter = Converter,
+ ConverterParameter = ConverterParameter,
+ ElementName = pathInfo.ElementName ?? ElementName,
+ FallbackValue = FallbackValue,
+ Mode = Mode,
+ Path = pathInfo.Path,
+ Priority = Priority,
+ RelativeSource = pathInfo.RelativeSource ?? RelativeSource,
+ DefaultAnchor = new WeakReference(GetDefaultAnchor((ITypeDescriptorContext)serviceProvider))
+ };
}
private class PathInfo
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
index 231778be09..52d9f043f4 100644
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
@@ -51,7 +51,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
if (control != null)
{
- return new InstancedBinding(control.GetResourceObservable(ResourceKey));
+ return InstancedBinding.OneWay(control.GetResourceObservable(ResourceKey));
}
return null;
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs
deleted file mode 100644
index 55a1b72125..0000000000
--- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StyleResourceExtension.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) The Avalonia Project. All rights reserved.
-// Licensed under the MIT license. See licence.md file in the project root for full license information.
-
-using Avalonia.Data;
-using Avalonia.Markup.Xaml.Data;
-using System;
-
-namespace Avalonia.Markup.Xaml.MarkupExtensions
-{
- using Portable.Xaml.Markup;
- using PortableXaml;
-
- [MarkupExtensionReturnType(typeof(IBinding))]
- public class StyleResourceExtension : MarkupExtension
- {
- public StyleResourceExtension(string name)
- {
- Name = name;
- }
-
- public override object ProvideValue(IServiceProvider serviceProvider)
- {
- return XamlBinding.FromMarkupExtensionContext(
- new StyleResourceBinding(Name),
- serviceProvider);
- }
-
- [ConstructorArgument("name")]
- public string Name { get; set; }
- }
-}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs
index a38029964f..7de96ea220 100644
--- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/AvaloniaXamlType.cs
@@ -212,11 +212,6 @@ namespace Avalonia.Markup.Xaml.PortableXaml
value);
}
- if (value is XamlBinding)
- {
- value = (value as XamlBinding).Value;
- }
-
if (UpdateListInsteadSet &&
value != null &&
UpdateListInsteadSetValue(instance, value))
@@ -317,9 +312,7 @@ namespace Avalonia.Markup.Xaml.PortableXaml
if (!Member.AssignBinding)
ApplyBinding(obj, (IBinding)value);
else
- obj.SetValue(Property, value is XamlBinding ?
- (value as XamlBinding).Value :
- value);
+ obj.SetValue(Property, value);
}
else
{
@@ -348,12 +341,9 @@ namespace Avalonia.Markup.Xaml.PortableXaml
{
var control = obj as IControl;
var property = Property;
- var xamlBinding = binding as XamlBinding;
if (control != null && property != Control.DataContextProperty)
DelayedBinding.Add(control, property, binding);
- else if (xamlBinding != null)
- obj.Bind(property, xamlBinding.Value, xamlBinding.Anchor?.Target);
else
obj.Bind(property, binding);
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/XamlBinding.cs b/src/Markup/Avalonia.Markup.Xaml/PortableXaml/XamlBinding.cs
deleted file mode 100644
index 1f4e66471c..0000000000
--- a/src/Markup/Avalonia.Markup.Xaml/PortableXaml/XamlBinding.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using Avalonia.Controls;
-using Avalonia.Data;
-using Avalonia.Styling;
-using Portable.Xaml;
-using Portable.Xaml.ComponentModel;
-using System.ComponentModel;
-using Portable.Xaml.Markup;
-using System;
-
-namespace Avalonia.Markup.Xaml.PortableXaml
-{
- internal class XamlBinding : IBinding
- {
- public static IBinding FromMarkupExtensionContext(
- IBinding binding,
- IServiceProvider serviceProvider)
- {
- var context = (ITypeDescriptorContext)serviceProvider;
- var pvt = context.GetService();
-
- if (pvt.TargetObject is IControl) return binding;
-
- object anchor = GetDefaultAnchor(context);
-
- if (anchor == null) return binding;
-
- return new XamlBinding(binding, anchor);
- }
-
- private static object GetDefaultAnchor(ITypeDescriptorContext context)
- {
- object anchor = null;
-
- // The target is not a control, so we need to find an anchor that will let us look
- // up named controls and style resources. First look for the closest IControl in
- // the context.
- anchor = context.GetFirstAmbientValue();
-
- // If a control was not found, then try to find the highest-level style as the XAML
- // file could be a XAML file containing only styles.
- return anchor ??
- context.GetService()?.RootObject as IStyle ??
- context.GetLastOrDefaultAmbientValue();
- }
-
- private XamlBinding(IBinding binding, object anchor)
- {
- Value = binding;
-
- Anchor = new WeakReference(anchor);
- }
-
- public WeakReference Anchor { get; }
-
- public IBinding Value { get; }
-
- public InstancedBinding Initiate(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null, bool enableDataValidation = false)
- {
- return Value.Initiate(target, targetProperty,
- anchor ?? Anchor.Target, enableDataValidation);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
index d6d3bd46ec..883e177f8a 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
@@ -42,7 +42,7 @@ namespace Avalonia.Markup.Xaml.Templates
if (ItemsSource != null)
{
var obs = new ExpressionObserver(item, ItemsSource.Path);
- return new InstancedBinding(obs, BindingMode.OneWay, BindingPriority.Style);
+ return InstancedBinding.OneWay(obs, BindingPriority.Style);
}
return null;
diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
index 66b237de06..4d6559a078 100644
--- a/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
+++ b/tests/Avalonia.Base.UnitTests/AvaloniaObjectTests_Binding.cs
@@ -428,7 +428,7 @@ namespace Avalonia.Base.UnitTests
object anchor = null,
bool enableDataValidation = false)
{
- return new InstancedBinding(_source, BindingMode.OneTime);
+ return InstancedBinding.OneTime(_source);
}
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
index ccbf04533d..85a450e1dc 100644
--- a/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
@@ -249,6 +249,37 @@ namespace Avalonia.Controls.UnitTests.Primitives
}
}
+ [Fact]
+ public void DataContextBeginUpdate_Should_Not_Be_Called_For_Controls_That_Dont_Inherit()
+ {
+ using (CreateServices())
+ {
+ TestControl child;
+ var popup = new Popup
+ {
+ Child = child = new TestControl(),
+ DataContext = "foo",
+ };
+
+ var beginCalled = false;
+ child.DataContextBeginUpdate += (s, e) => beginCalled = true;
+
+ // Test for #1245. Here, the child's logical parent is the popup but it's not yet
+ // attached to a visual tree because the popup hasn't been opened.
+ Assert.Same(popup, ((ILogical)child).LogicalParent);
+ Assert.Same(popup, child.InheritanceParent);
+ Assert.Null(child.GetVisualRoot());
+
+ popup.Open();
+
+ // #1245 was caused by the fact that DataContextBeginUpdate was called on `target`
+ // when the PopupRoot was created, even though PopupRoot isn't the
+ // InheritanceParent of child.
+ Assert.False(beginCalled);
+ }
+ }
+
+
private static IDisposable CreateServices()
{
var result = AvaloniaLocator.EnterScope();
@@ -304,5 +335,18 @@ namespace Avalonia.Controls.UnitTests.Primitives
private class PopupContentControl : ContentControl
{
}
+
+ private class TestControl : Decorator
+ {
+ public event EventHandler DataContextBeginUpdate;
+
+ public new IAvaloniaObject InheritanceParent => base.InheritanceParent;
+
+ protected override void OnDataContextBeginUpdate()
+ {
+ DataContextBeginUpdate?.Invoke(this, EventArgs.Empty);
+ base.OnDataContextBeginUpdate();
+ }
+ }
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
index 29eac3d8f5..17eccc96bc 100644
--- a/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/TreeViewTests.cs
@@ -515,7 +515,7 @@ namespace Avalonia.Controls.UnitTests
public InstancedBinding ItemsSelector(object item)
{
var obs = new ExpressionObserver(item, nameof(Node.Children));
- return new InstancedBinding(obs);
+ return InstancedBinding.OneWay(obs);
}
public bool Match(object data)
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
index 874dc18552..4450cc0c90 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/MultiBindingTests.cs
@@ -34,8 +34,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
var target = new Mock().As();
target.Setup(x => x.GetValue(Control.DataContextProperty)).Returns(source);
- var subject = binding.Initiate(target.Object, null).Subject;
- var result = await subject.Take(1);
+ var observable = binding.Initiate(target.Object, null).Observable;
+ var result = await observable.Take(1);
Assert.Equal("1,2,3", result);
}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
index 8c7dad1bce..03dc5374e0 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
@@ -411,8 +411,8 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
var xaml = @"
-
-
+
";
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
index 65fc9eaddd..b339972029 100644
--- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs
@@ -61,171 +61,6 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
}
}
- [Fact]
- public void StyleResource_Can_Be_Assigned_To_Property()
- {
- var xaml = @"
-
-
-
-
-
-
- ";
-
- var loader = new AvaloniaXamlLoader();
- var userControl = (UserControl)loader.Load(xaml);
- var border = userControl.FindControl("border");
-
- DelayedBinding.ApplyBindings(border);
-
- var brush = (SolidColorBrush)border.Background;
- Assert.Equal(0xff506070, brush.Color.ToUint32());
- }
-
- [Fact]
- public void StyleResource_Can_Be_Assigned_To_Setter()
- {
- //skip default theme and styles, they are not needed
- using (UnitTestApplication.Start(TestServices.StyledWindow
- .With(theme: () => new Styles())))
- {
- var xaml = @"
-
-
-
-
-
-
- ";
-
- var loader = new AvaloniaXamlLoader();
- var window = (Window)loader.Load(xaml);
- var button = window.FindControl("button");
- var brush = (SolidColorBrush)button.Background;
-
- Assert.Equal(0xff506070, brush.Color.ToUint32());
- }
- }
-
- [Fact]
- public void StyleResource_Can_Be_Assigned_To_StyleResource_Property()
- {
- using (UnitTestApplication.Start(TestServices.StyledWindow))
- {
- var xaml = @"
-
-
-
-
-
- ";
-
- var loader = new AvaloniaXamlLoader();
- var window = (Window)loader.Load(xaml);
- var brush = (ISolidColorBrush)window.FindResource("brush");
- var button = window.FindControl("button");
-
- DelayedBinding.ApplyBindings(button);
-
- var buttonBrush = (ISolidColorBrush)button.Background;
-
- Assert.Equal(0xff506070, brush.Color.ToUint32());
- Assert.Equal(0xff506070, buttonBrush.Color.ToUint32());
- }
- }
-
- [Fact]
- public void StyleResource_Can_Be_Found_In_TopLevel_Styles()
- {
- var xaml = @"
-
-
- ";
-
- var loader = new AvaloniaXamlLoader();
- var styles = (Styles)loader.Load(xaml);
-
- styles.TryGetResource("brush", out var brush);
-
- Assert.Equal(0xff506070, ((SolidColorBrush)brush).Color.ToUint32());
- }
-
- [Fact]
- public void StyleResource_Can_Be_Found_In_Sibling_Styles()
- {
- var xaml = @"
-
-
-
- ";
-
- var loader = new AvaloniaXamlLoader();
- var styles = (Styles)loader.Load(xaml);
-
- styles.TryGetResource("brush", out var brush);
-
- Assert.Equal(0xff506070, ((SolidColorBrush)brush).Color.ToUint32());
- }
-
- [Fact(Skip = "TODO: Issue #492")]
- public void StyleResource_Can_Be_Found_Across_Xaml_Files()
- {
- using (UnitTestApplication.Start(TestServices.StyledWindow))
- {
- var xaml = @"
-
-
-
-
-
-
- ";
-
- var loader = new AvaloniaXamlLoader();
- var window = (Window)loader.Load(xaml);
- var border = window.FindControl("border");
- var borderBrush = (ISolidColorBrush)border.Background;
-
- Assert.NotNull(borderBrush);
- Assert.Equal(0xffff0000, borderBrush.Color.ToUint32());
- }
- }
-
[Fact]
public void StyleInclude_Is_Built()
{
diff --git a/tests/Avalonia.Styling.UnitTests/SetterTests.cs b/tests/Avalonia.Styling.UnitTests/SetterTests.cs
index 9c43097a21..b65b8dcc68 100644
--- a/tests/Avalonia.Styling.UnitTests/SetterTests.cs
+++ b/tests/Avalonia.Styling.UnitTests/SetterTests.cs
@@ -29,7 +29,7 @@ namespace Avalonia.Styling.UnitTests
{
var control = new TextBlock();
var subject = new BehaviorSubject("foo");
- var descriptor = new InstancedBinding(subject);
+ var descriptor = InstancedBinding.OneWay(subject);
var binding = Mock.Of(x => x.Initiate(control, TextBlock.TextProperty, null, false) == descriptor);
var style = Mock.Of();
var setter = new Setter(TextBlock.TextProperty, binding);