|
@@ -0,0 +1,135 @@
|
|
|
+// 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.Collections.Generic;
|
|
|
+using System.Linq;
|
|
|
+using System.Reactive.Linq;
|
|
|
+using Avalonia.Controls.Primitives;
|
|
|
+using Avalonia.Controls.Templates;
|
|
|
+using Avalonia.Data;
|
|
|
+
|
|
|
+namespace Avalonia.Controls
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// A control which displays an error notifier when there is a DataValidationError.
|
|
|
+ /// Provides attached properties to track errors on a control
|
|
|
+ /// </summary>
|
|
|
+ /// <remarks>
|
|
|
+ /// You will probably only want to create instances inside of control templates.
|
|
|
+ /// </remarks>
|
|
|
+ public class DataValidationErrors : ContentControl
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// Defines the DataValidationErrors.Errors attached property.
|
|
|
+ /// </summary>
|
|
|
+ public static readonly AttachedProperty<IEnumerable<Exception>> ErrorsProperty =
|
|
|
+ AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, IEnumerable<Exception>>("Errors");
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Defines the DataValidationErrors.HasErrors attached property.
|
|
|
+ /// </summary>
|
|
|
+ public static readonly AttachedProperty<bool> HasErrorsProperty =
|
|
|
+ AvaloniaProperty.RegisterAttached<DataValidationErrors, Control, bool>("HasErrors");
|
|
|
+
|
|
|
+ public static readonly StyledProperty<IDataTemplate> ErrorTemplateProperty =
|
|
|
+ AvaloniaProperty.Register<DataValidationErrors, IDataTemplate>(nameof(ErrorTemplate));
|
|
|
+
|
|
|
+
|
|
|
+ private Control _owner;
|
|
|
+
|
|
|
+ public static readonly DirectProperty<DataValidationErrors, Control> OwnerProperty =
|
|
|
+ AvaloniaProperty.RegisterDirect<DataValidationErrors, Control>(
|
|
|
+ nameof(Owner),
|
|
|
+ o => o.Owner,
|
|
|
+ (o, v) => o.Owner = v);
|
|
|
+
|
|
|
+ public Control Owner
|
|
|
+ {
|
|
|
+ get { return _owner; }
|
|
|
+ set { SetAndRaise(OwnerProperty, ref _owner, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Initializes static members of the <see cref="DataValidationErrors"/> class.
|
|
|
+ /// </summary>
|
|
|
+ static DataValidationErrors()
|
|
|
+ {
|
|
|
+ ErrorsProperty.Changed.Subscribe(ErrorsChanged);
|
|
|
+ HasErrorsProperty.Changed.Subscribe(HasErrorsChanged);
|
|
|
+ TemplatedParentProperty.Changed.AddClassHandler<DataValidationErrors>(x => x.OnTemplatedParentChange);
|
|
|
+ }
|
|
|
+
|
|
|
+ private void OnTemplatedParentChange(AvaloniaPropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (Owner == null)
|
|
|
+ {
|
|
|
+ Owner = (e.NewValue as Control);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public IDataTemplate ErrorTemplate
|
|
|
+ {
|
|
|
+ get { return GetValue(ErrorTemplateProperty); }
|
|
|
+ set { SetValue(ErrorTemplateProperty, value); }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static void ErrorsChanged(AvaloniaPropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ var control = (Control)e.Sender;
|
|
|
+ var errors = (IEnumerable<Exception>)e.NewValue;
|
|
|
+
|
|
|
+ var hasErrors = false;
|
|
|
+ if (errors != null && errors.Any())
|
|
|
+ hasErrors = true;
|
|
|
+
|
|
|
+ control.SetValue(HasErrorsProperty, hasErrors);
|
|
|
+ }
|
|
|
+ private static void HasErrorsChanged(AvaloniaPropertyChangedEventArgs e)
|
|
|
+ {
|
|
|
+ var control = (Control)e.Sender;
|
|
|
+ var classes = (IPseudoClasses)control.Classes;
|
|
|
+ classes.Set(":error", (bool)e.NewValue);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static IEnumerable<Exception> GetErrors(Control control)
|
|
|
+ {
|
|
|
+ return control.GetValue(ErrorsProperty);
|
|
|
+ }
|
|
|
+ public static void SetErrors(Control control, IEnumerable<Exception> errors)
|
|
|
+ {
|
|
|
+ control.SetValue(ErrorsProperty, errors);
|
|
|
+ }
|
|
|
+ public static void SetError(Control control, Exception error)
|
|
|
+ {
|
|
|
+ SetErrors(control, UnpackException(error));
|
|
|
+ }
|
|
|
+ public static void ClearErrors(Control control)
|
|
|
+ {
|
|
|
+ SetErrors(control, null);
|
|
|
+ }
|
|
|
+ public static bool GetHasErrors(Control control)
|
|
|
+ {
|
|
|
+ return control.GetValue(HasErrorsProperty);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static IEnumerable<Exception> UnpackException(Exception exception)
|
|
|
+ {
|
|
|
+ if (exception != null)
|
|
|
+ {
|
|
|
+ var aggregate = exception as AggregateException;
|
|
|
+ var exceptions = aggregate == null ?
|
|
|
+ (IEnumerable<Exception>)new[] { exception } :
|
|
|
+ aggregate.InnerExceptions;
|
|
|
+ var filtered = exceptions.Where(x => !(x is BindingChainException)).ToList();
|
|
|
+
|
|
|
+ if (filtered.Count > 0)
|
|
|
+ {
|
|
|
+ return filtered;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|