diff --git a/build/XUnit.props b/build/XUnit.props index 53f524b8e9..a75e1bac86 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -13,6 +13,6 @@ $(MSBuildThisFileDirectory)\avalonia.snk - True + False diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index 488aa0535f..f001425964 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -14,7 +14,6 @@ - @@ -45,6 +44,7 @@ ScrollViewer.HorizontalScrollBarVisibility="Disabled"> + diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml index a49616e543..1a53217842 100644 --- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml +++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml @@ -1,5 +1,6 @@ AutoCompleteBox @@ -56,6 +57,16 @@ Width="200" Margin="0,0,0,8" FilterMode="None"/> + + + + + + + diff --git a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml index c3f9f65dd9..4ac2330403 100644 --- a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml +++ b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml @@ -1,6 +1,7 @@  + x:Class="ControlCatalog.Pages.ButtonSpinnerPage" + xmlns:sys="clr-namespace:System;assembly=netstandard"> ButtonSpinner @@ -19,6 +20,14 @@ ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}"> + + + + + + diff --git a/samples/ControlCatalog/Pages/ComboBoxPage.xaml b/samples/ControlCatalog/Pages/ComboBoxPage.xaml index 369f703718..025b85492c 100644 --- a/samples/ControlCatalog/Pages/ComboBoxPage.xaml +++ b/samples/ControlCatalog/Pages/ComboBoxPage.xaml @@ -1,6 +1,7 @@ + x:Class="ControlCatalog.Pages.ComboBoxPage" + xmlns:sys="clr-namespace:System;assembly=netstandard"> ComboBox A drop-down list. @@ -35,6 +36,16 @@ + + + Inline Items + Inline Item 2 + Inline Item 3 + Inline Item 4 + + + + diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml index af6b6e8605..45056a9a76 100644 --- a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:sys="clr-namespace:System;assembly=netstandard" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="ControlCatalog.Pages.DateTimePickerPage"> @@ -30,6 +31,16 @@ + + + + + + + + + A DatePicker with day formatted and year hidden. + + + + + + + + A TimePicker with a header and minute increments specified. diff --git a/samples/ControlCatalog/Pages/LabelsPage.axaml b/samples/ControlCatalog/Pages/LabelsPage.axaml index 32c46f080d..961e7ba7e6 100644 --- a/samples/ControlCatalog/Pages/LabelsPage.axaml +++ b/samples/ControlCatalog/Pages/LabelsPage.axaml @@ -25,11 +25,11 @@ - + - + - + diff --git a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml index 0d7e5da17f..d75622f1fb 100644 --- a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml +++ b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml @@ -1,5 +1,6 @@  Numeric up-down control @@ -75,6 +76,15 @@ + + NumericUpDown with Validation Errors: + + + + + diff --git a/samples/ControlCatalog/Pages/RelativePanelPage.axaml b/samples/ControlCatalog/Pages/RelativePanelPage.axaml index 3657d52bd9..4dcdcc195f 100644 --- a/samples/ControlCatalog/Pages/RelativePanelPage.axaml +++ b/samples/ControlCatalog/Pages/RelativePanelPage.axaml @@ -23,16 +23,16 @@ - + - + - + @@ -41,19 +41,19 @@ - + - + - + - + - + diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index ea31ed0050..b3f32ed421 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -1,5 +1,6 @@ Slider @@ -21,6 +22,15 @@ IsSnapToTickEnabled="True" Ticks="0,20,25,40,75,100" Width="300" /> + + + + + + x:Class="ControlCatalog.Pages.TextBoxPage" + xmlns:sys="clr-namespace:System;assembly=netstandard"> @@ -11,12 +12,18 @@ Spacing="16"> - + + + + + + + /// Label focus Target /// + [ResolveByName] public IInputElement Target { get => _target; diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index becb489557..b445de0472 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -265,6 +265,7 @@ namespace Avalonia.Controls.Primitives /// /// Gets or sets the control that is used to determine the popup's position. /// + [ResolveByName] public Control? PlacementTarget { get { return GetValue(PlacementTargetProperty); } diff --git a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs index f64c26682b..562b104b04 100644 --- a/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs +++ b/src/Avalonia.Controls/RelativePanel.AttachedProperties.cs @@ -55,6 +55,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element above.) + [ResolveByName] public static void SetAbove(AvaloniaObject obj, object value) { obj.SetValue(AboveProperty, value); @@ -121,6 +122,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's bottom edge with.) + [ResolveByName] public static void SetAlignBottomWith(AvaloniaObject obj, object value) { obj.SetValue(AlignBottomWithProperty, value); @@ -185,6 +187,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's horizontal center with.) + [ResolveByName] public static void SetAlignHorizontalCenterWith(AvaloniaObject obj, object value) { obj.SetValue(AlignHorizontalCenterWithProperty, value); @@ -250,6 +253,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's left edge with.) + [ResolveByName] public static void SetAlignLeftWith(AvaloniaObject obj, object value) { obj.SetValue(AlignLeftWithProperty, value); @@ -315,6 +319,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's right edge with.) + [ResolveByName] public static void SetAlignRightWith(AvaloniaObject obj, object value) { obj.SetValue(AlignRightWithProperty, value); @@ -376,6 +381,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's top edge with.) + [ResolveByName] public static void SetAlignTopWith(AvaloniaObject obj, object value) { obj.SetValue(AlignTopWithProperty, value); @@ -437,7 +443,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's horizontal center with.) - + [ResolveByName] public static void SetAlignVerticalCenterWith(AvaloniaObject obj, object value) { obj.SetValue(AlignVerticalCenterWithProperty, value); @@ -468,7 +474,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element below.) - + [ResolveByName] public static void SetBelow(AvaloniaObject obj, object value) { obj.SetValue(BelowProperty, value); @@ -500,6 +506,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element to the left of.) + [ResolveByName] public static void SetLeftOf(AvaloniaObject obj, object value) { obj.SetValue(LeftOfProperty, value); @@ -531,6 +538,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element to the right of.) + [ResolveByName] public static void SetRightOf(AvaloniaObject obj, object value) { obj.SetValue(RightOfProperty, value); diff --git a/src/Avalonia.Controls/ResolveByNameAttribute.cs b/src/Avalonia.Controls/ResolveByNameAttribute.cs index a00e3f8a1b..a13b10d630 100644 --- a/src/Avalonia.Controls/ResolveByNameAttribute.cs +++ b/src/Avalonia.Controls/ResolveByNameAttribute.cs @@ -2,8 +2,12 @@ namespace Avalonia.Controls { + /// + /// Indicates that the property resolves an element by Name or x:Name. + /// When applying this to attached properties, ensure to put on both + /// the Getter and Setter methods. + /// public class ResolveByNameAttribute : Attribute { - } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index d9a0d17518..9363c28705 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -23,6 +23,8 @@ namespace Avalonia.Diagnostics.ViewModels if (visual is IControl control) { + ElementName = control.Name; + var removed = Observable.FromEventPattern( x => control.DetachedFromLogicalTree += x, x => control.DetachedFromLogicalTree -= x); @@ -61,6 +63,11 @@ namespace Avalonia.Diagnostics.ViewModels private set { RaiseAndSetIfChanged(ref _classes, value); } } + public string ElementName + { + get; + } + public IVisual Visual { get; diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index b2d3a8bddb..8aad5fffd8 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -26,6 +26,12 @@ + + + + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 10861538ae..c4f9185728 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -76,7 +76,13 @@ namespace Avalonia.Diagnostics.Views if (e.Modifiers == modifiers) { var point = (Root as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default; - var control = Root.GetVisualsAt(point, x => (!(x is AdornerLayer) && x.IsVisible)) + + var control = Root.GetVisualsAt(point, x => + { + if (x is AdornerLayer || !x.IsVisible) return false; + if (!(x is IInputElement ie)) return true; + return ie.IsHitTestVisible; + }) .FirstOrDefault(); if (control != null) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml index a1e6ca7d37..98de9b611e 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels" x:Class="Avalonia.Diagnostics.Views.TreePageView"> - + + diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index bc0916c8da..2cf1fe2963 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -341,8 +341,7 @@ namespace Avalonia.Native public void Invalidate(Rect rect) { - if (!_deferredRendering && _native != null) - _native.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y }); + _native?.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y }); } public void SetInputRoot(IInputRoot inputRoot) diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs index fc48a8853d..31f4691c90 100644 --- a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs +++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs @@ -1,3 +1,6 @@ +using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; using Avalonia; using Avalonia.VisualTree; using Avalonia.Controls; @@ -6,8 +9,10 @@ using ReactiveUI; namespace Avalonia.ReactiveUI { /// - /// A ReactiveUI UserControl that implements - /// and will activate your ViewModel automatically if it supports activation. + /// A ReactiveUI that implements the interface and + /// will activate your ViewModel automatically if the view model implements . + /// When the DataContext property changes, this class will update the ViewModel property with the new DataContext + /// value, and vice versa. /// /// ViewModel type. public class ReactiveUserControl : UserControl, IViewFor where TViewModel : class @@ -20,7 +25,14 @@ namespace Avalonia.ReactiveUI /// public ReactiveUserControl() { - DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; + // This WhenActivated block calls ViewModel's WhenActivated + // block if the ViewModel implements IActivatableViewModel. + this.WhenActivated(disposables => { }); + + this.ObservableForProperty(x => x.ViewModel, false, true) + .Subscribe(args => DataContext = args.Value); + this.ObservableForProperty(x => x.DataContext, false, true) + .Subscribe(args => ViewModel = args.Value as TViewModel); } /// diff --git a/src/Avalonia.ReactiveUI/ReactiveWindow.cs b/src/Avalonia.ReactiveUI/ReactiveWindow.cs index 5695a727af..1204266b63 100644 --- a/src/Avalonia.ReactiveUI/ReactiveWindow.cs +++ b/src/Avalonia.ReactiveUI/ReactiveWindow.cs @@ -1,3 +1,6 @@ +using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; using Avalonia; using Avalonia.VisualTree; using Avalonia.Controls; @@ -6,8 +9,10 @@ using ReactiveUI; namespace Avalonia.ReactiveUI { /// - /// A ReactiveUI Window that implements - /// and will activate your ViewModel automatically if it supports activation. + /// A ReactiveUI that implements the interface and will + /// activate your ViewModel automatically if the view model implements . When + /// the DataContext property changes, this class will update the ViewModel property with the new DataContext value, + /// and vice versa. /// /// ViewModel type. public class ReactiveWindow : Window, IViewFor where TViewModel : class @@ -20,7 +25,14 @@ namespace Avalonia.ReactiveUI /// public ReactiveWindow() { - DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; + // This WhenActivated block calls ViewModel's WhenActivated + // block if the ViewModel implements IActivatableViewModel. + this.WhenActivated(disposables => { }); + + this.ObservableForProperty(x => x.ViewModel, false, true) + .Subscribe(args => DataContext = args.Value); + this.ObservableForProperty(x => x.DataContext, false, true) + .Subscribe(args => ViewModel = args.Value as TViewModel); } /// diff --git a/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml index 82265ea282..12b4845522 100644 --- a/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml +++ b/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml @@ -65,56 +65,59 @@ - - - + + + + - - - - + + + + - - - - - - + + + + + + + diff --git a/src/Avalonia.Themes.Fluent/ComboBox.xaml b/src/Avalonia.Themes.Fluent/ComboBox.xaml index 8155264f18..2eee656dc6 100644 --- a/src/Avalonia.Themes.Fluent/ComboBox.xaml +++ b/src/Avalonia.Themes.Fluent/ComboBox.xaml @@ -44,105 +44,107 @@ - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - + Grid.Column="1" + IsHitTestVisible="False" + Margin="0,0,10,0" + Height="12" + Width="12" + HorizontalAlignment="Right" + VerticalAlignment="Center"> + + + + + + + + + + + + + + @@ -232,4 +234,9 @@ + + + diff --git a/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml b/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml index 902fc74c0c..ed31f7b573 100644 --- a/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml +++ b/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml @@ -14,39 +14,31 @@ - - + + - - - - - - - - - - + + + + + + + diff --git a/src/Avalonia.Themes.Fluent/DatePicker.xaml b/src/Avalonia.Themes.Fluent/DatePicker.xaml index 6fbfa1bbf7..b6e36861e0 100644 --- a/src/Avalonia.Themes.Fluent/DatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/DatePicker.xaml @@ -125,77 +125,79 @@ - - + + + - + - - - + + + - + + @@ -228,6 +230,11 @@ + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -102,56 +104,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -260,4 +264,12 @@ + + + + diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 162835ae10..139a61abdf 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -36,16 +36,7 @@ - - - - - + - - - + - - + diff --git a/src/Avalonia.Themes.Fluent/TimePicker.xaml b/src/Avalonia.Themes.Fluent/TimePicker.xaml index 84352213e1..91969d8733 100644 --- a/src/Avalonia.Themes.Fluent/TimePicker.xaml +++ b/src/Avalonia.Themes.Fluent/TimePicker.xaml @@ -41,94 +41,96 @@ - - + + + - + Width="{DynamicResource TimePickerSpacerThemeWidth}" + Grid.Column="3" /> + + + + + + - - - + + + - + + @@ -161,6 +163,10 @@ + +