Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions src/Avalonia.Base/AvaloniaObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -646,10 +646,12 @@ protected internal virtual void LogBindingError(AvaloniaProperty property, Excep
/// enabled.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The new binding value for the property.</param>
protected virtual void UpdateDataValidation<T>(
AvaloniaProperty<T> property,
BindingValue<T> value)
/// <param name="state">The current data binding state.</param>
/// <param name="error">The current data binding error, if any.</param>
protected virtual void UpdateDataValidation(
AvaloniaProperty property,
BindingValueType state,
Exception? error)
{
}

Expand Down Expand Up @@ -860,7 +862,7 @@ private void SetDirectValueUnchecked<T>(DirectPropertyBase<T> property, BindingV

if (metadata.EnableDataValidation == true)
{
UpdateDataValidation(property, value);
UpdateDataValidation(property, value.Type, value.Error);
}
}

Expand Down
11 changes: 2 additions & 9 deletions src/Avalonia.Base/AvaloniaProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using Avalonia.Data;
using Avalonia.Data.Core;
using Avalonia.Styling;
using Avalonia.Utilities;

namespace Avalonia
Expand Down Expand Up @@ -454,15 +455,6 @@ public override string ToString()
return Name;
}

/// <summary>
/// Uses the visitor pattern to resolve an untyped property to a typed property.
/// </summary>
/// <typeparam name="TData">The type of user data passed.</typeparam>
/// <param name="visitor">The visitor which will accept the typed property.</param>
/// <param name="data">The user data to pass.</param>
public abstract void Accept<TData>(IAvaloniaPropertyVisitor<TData> visitor, ref TData data)
where TData : struct;

/// <summary>
/// Routes an untyped ClearValue call to a typed call.
/// </summary>
Expand Down Expand Up @@ -508,6 +500,7 @@ internal abstract IDisposable RouteBind(
BindingPriority priority);

internal abstract void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaObject? oldParent);
internal abstract ISetterInstance CreateSetterInstance(IStyleable target, object? value);

/// <summary>
/// Overrides the metadata for the property on the specified type.
Expand Down
32 changes: 26 additions & 6 deletions src/Avalonia.Base/DirectPropertyBase.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using Avalonia.Data;
using Avalonia.Reactive;
using Avalonia.Styling;
using Avalonia.Utilities;

namespace Avalonia
Expand Down Expand Up @@ -120,12 +121,6 @@ public void OverrideMetadata(Type type, DirectPropertyMetadata<TValue> metadata)
base.OverrideMetadata(type, metadata);
}

/// <inheritdoc/>
public override void Accept<TData>(IAvaloniaPropertyVisitor<TData> visitor, ref TData data)
{
visitor.Visit(this, ref data);
}

/// <inheritdoc/>
internal override void RouteClearValue(AvaloniaObject o)
{
Expand Down Expand Up @@ -181,5 +176,30 @@ internal override void RouteInheritanceParentChanged(AvaloniaObject o, AvaloniaO
{
throw new NotSupportedException("Direct properties do not support inheritance.");
}

internal override ISetterInstance CreateSetterInstance(IStyleable target, object? value)
{
if (value is IBinding binding)
{
return new PropertySetterBindingInstance<TValue>(
target,
this,
binding);
}
else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType))
{
return new PropertySetterLazyInstance<TValue>(
target,
this,
() => (TValue)template.Build());
}
else
{
return new PropertySetterInstance<TValue>(
target,
this,
(TValue)value!);
}
}
}
}
24 changes: 0 additions & 24 deletions src/Avalonia.Base/Interactivity/IInteractive.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,13 @@ void AddHandler(
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
bool handledEventsToo = false);

/// <summary>
/// Adds a handler for the specified routed event.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event's args.</typeparam>
/// <param name="routedEvent">The routed event.</param>
/// <param name="handler">The handler.</param>
/// <param name="routes">The routing strategies to listen to.</param>
/// <param name="handledEventsToo">Whether handled events should also be listened for.</param>
/// <returns>A disposable that terminates the event subscription.</returns>
void AddHandler<TEventArgs>(
RoutedEvent<TEventArgs> routedEvent,
EventHandler<TEventArgs> handler,
RoutingStrategies routes = RoutingStrategies.Direct | RoutingStrategies.Bubble,
bool handledEventsToo = false) where TEventArgs : RoutedEventArgs;

/// <summary>
/// Removes a handler for the specified routed event.
/// </summary>
/// <param name="routedEvent">The routed event.</param>
/// <param name="handler">The handler.</param>
void RemoveHandler(RoutedEvent routedEvent, Delegate handler);

/// <summary>
/// Removes a handler for the specified routed event.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event's args.</typeparam>
/// <param name="routedEvent">The routed event.</param>
/// <param name="handler">The handler.</param>
void RemoveHandler<TEventArgs>(RoutedEvent<TEventArgs> routedEvent, EventHandler<TEventArgs> handler)
where TEventArgs : RoutedEventArgs;

/// <summary>
/// Adds the object's handlers for a routed event to an event route.
/// </summary>
Expand Down
32 changes: 26 additions & 6 deletions src/Avalonia.Base/StyledPropertyBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Diagnostics;
using Avalonia.Data;
using Avalonia.Reactive;
using Avalonia.Styling;
using Avalonia.Utilities;

namespace Avalonia
Expand Down Expand Up @@ -158,12 +159,6 @@ public void OverrideMetadata(Type type, StyledPropertyMetadata<TValue> metadata)
base.OverrideMetadata(type, metadata);
}

/// <inheritdoc/>
public override void Accept<TData>(IAvaloniaPropertyVisitor<TData> visitor, ref TData data)
{
visitor.Visit(this, ref data);
}

/// <summary>
/// Gets the string representation of the property.
/// </summary>
Expand Down Expand Up @@ -237,6 +232,31 @@ internal override void RouteInheritanceParentChanged(
o.InheritanceParentChanged(this, oldParent);
}

internal override ISetterInstance CreateSetterInstance(IStyleable target, object? value)
{
if (value is IBinding binding)
{
return new PropertySetterBindingInstance<TValue>(
target,
this,
binding);
}
else if (value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(PropertyType))
{
return new PropertySetterLazyInstance<TValue>(
target,
this,
() => (TValue)template.Build());
}
else
{
return new PropertySetterInstance<TValue>(
target,
this,
(TValue)value!);
}
}

private object? GetDefaultBoxedValue(Type type)
{
_ = type ?? throw new ArgumentNullException(nameof(type));
Expand Down
65 changes: 2 additions & 63 deletions src/Avalonia.Base/Styling/Setter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace Avalonia.Styling
/// A <see cref="Setter"/> is used to set a <see cref="AvaloniaProperty"/> value on a
/// <see cref="AvaloniaObject"/> depending on a condition.
/// </remarks>
public class Setter : ISetter, IAnimationSetter, IAvaloniaPropertyVisitor<Setter.SetterVisitorData>
public class Setter : ISetter, IAnimationSetter
{
private object? _value;

Expand Down Expand Up @@ -68,68 +68,7 @@ public ISetterInstance Instance(IStyleable target)
throw new InvalidOperationException("Setter.Property must be set.");
}

var data = new SetterVisitorData
{
target = target,
value = Value,
};

Property.Accept(this, ref data);
return data.result!;
}

void IAvaloniaPropertyVisitor<SetterVisitorData>.Visit<T>(
StyledPropertyBase<T> property,
ref SetterVisitorData data)
{
if (data.value is IBinding binding)
{
data.result = new PropertySetterBindingInstance<T>(
data.target,
property,
binding);
}
else if (data.value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(property.PropertyType))
{
data.result = new PropertySetterLazyInstance<T>(
data.target,
property,
() => (T)template.Build());
}
else
{
data.result = new PropertySetterInstance<T>(
data.target,
property,
(T)data.value!);
}
}

void IAvaloniaPropertyVisitor<SetterVisitorData>.Visit<T>(
DirectPropertyBase<T> property,
ref SetterVisitorData data)
{
if (data.value is IBinding binding)
{
data.result = new PropertySetterBindingInstance<T>(
data.target,
property,
binding);
}
else if (data.value is ITemplate template && !typeof(ITemplate).IsAssignableFrom(property.PropertyType))
{
data.result = new PropertySetterLazyInstance<T>(
data.target,
property,
() => (T)template.Build());
}
else
{
data.result = new PropertySetterInstance<T>(
data.target,
property,
(T)data.value!);
}
return Property.CreateSetterInstance(target, Value);
}

private struct SetterVisitorData
Expand Down
26 changes: 0 additions & 26 deletions src/Avalonia.Base/Threading/IDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,6 @@ public interface IDispatcher
/// <param name="priority">The priority with which to invoke the method.</param>
void Post(Action action, DispatcherPriority priority = default);

/// <summary>
/// Posts an action that will be invoked on the dispatcher thread.
/// </summary>
/// <typeparam name="T">type of argument</typeparam>
/// <param name="action">The method to call.</param>
/// <param name="arg">The argument of method to call.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
void Post<T>(Action<T> action, T arg, DispatcherPriority priority = default);

/// <summary>
/// Invokes a action on the dispatcher thread.
/// </summary>
Expand All @@ -43,14 +34,6 @@ public interface IDispatcher
/// <returns>A task that can be used to track the method's execution.</returns>
Task InvokeAsync(Action action, DispatcherPriority priority = default);

/// <summary>
/// Invokes a method on the dispatcher thread.
/// </summary>
/// <param name="function">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that can be used to track the method's execution.</returns>
Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = default);

/// <summary>
/// Queues the specified work to run on the dispatcher thread and returns a proxy for the
/// task returned by <paramref name="function"/>.
Expand All @@ -59,14 +42,5 @@ public interface IDispatcher
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that represents a proxy for the task returned by <paramref name="function"/>.</returns>
Task InvokeAsync(Func<Task> function, DispatcherPriority priority = default);

/// <summary>
/// Queues the specified work to run on the dispatcher thread and returns a proxy for the
/// task returned by <paramref name="function"/>.
/// </summary>
/// <param name="function">The work to execute asynchronously.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that represents a proxy for the task returned by <paramref name="function"/>.</returns>
Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority = default);
}
}
32 changes: 0 additions & 32 deletions src/Avalonia.Base/Utilities/IAvaloniaPropertyVisitor.cs

This file was deleted.

10 changes: 7 additions & 3 deletions src/Avalonia.Controls/AutoCompleteBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,12 +1346,16 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
/// enabled.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The new binding value for the property.</param>
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
/// <param name="state">The current data binding state.</param>
/// <param name="error">The current data binding error, if any.</param>
protected override void UpdateDataValidation(
AvaloniaProperty property,
BindingValueType state,
Exception? error)
{
if (property == TextProperty || property == SelectedItemProperty)
{
DataValidationErrors.SetError(this, value.Error);
DataValidationErrors.SetError(this, error);
}
}

Expand Down
9 changes: 6 additions & 3 deletions src/Avalonia.Controls/Button.cs
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,15 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
protected override AutomationPeer OnCreateAutomationPeer() => new ButtonAutomationPeer(this);

/// <inheritdoc/>
protected override void UpdateDataValidation<T>(AvaloniaProperty<T> property, BindingValue<T> value)
protected override void UpdateDataValidation(
AvaloniaProperty property,
BindingValueType state,
Exception? error)
{
base.UpdateDataValidation(property, value);
base.UpdateDataValidation(property, state, error);
if (property == CommandProperty)
{
if (value.Type == BindingValueType.BindingError)
if (state == BindingValueType.BindingError)
{
if (_commandCanExecute)
{
Expand Down
Loading