Browse Source

Merge branch 'master' into fix-fluent-loader

pull/8291/head
Tako 4 years ago
committed by GitHub
parent
commit
7c8aa9e406
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 10
      samples/ControlCatalog/Converter/MathSubtractConverter.cs
  2. 10
      samples/ControlCatalog/DecoratedWindow.xaml.cs
  3. 16
      samples/ControlCatalog/MainView.xaml.cs
  4. 6
      samples/ControlCatalog/MainWindow.xaml.cs
  5. 4
      samples/ControlCatalog/Models/Countries.cs
  6. 4
      samples/ControlCatalog/Models/GDPValueConverter.cs
  7. 16
      samples/ControlCatalog/Models/Person.cs
  8. 33
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  9. 2
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs
  10. 4
      samples/ControlCatalog/Pages/ButtonsPage.xaml.cs
  11. 12
      samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs
  12. 4
      samples/ControlCatalog/Pages/CalendarPage.xaml.cs
  13. 11
      samples/ControlCatalog/Pages/CarouselPage.xaml.cs
  14. 22
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs
  15. 6
      samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
  16. 8
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  17. 4
      samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs
  18. 32
      samples/ControlCatalog/Pages/DialogsPage.xaml.cs
  19. 6
      samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs
  20. 8
      samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs
  21. 13
      samples/ControlCatalog/Pages/ImagePage.xaml.cs
  22. 26
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
  23. 2
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  24. 2
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  25. 2
      samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs
  26. 2
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  27. 10
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs
  28. 2
      samples/ControlCatalog/Pages/ScreenPage.cs
  29. 12
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  30. 2
      samples/ControlCatalog/Pages/TabStripPage.xaml.cs
  31. 2
      samples/ControlCatalog/ViewModels/ApplicationViewModel.cs
  32. 2
      samples/ControlCatalog/ViewModels/ContextPageViewModel.cs
  33. 2
      samples/ControlCatalog/ViewModels/CursorPageViewModel.cs
  34. 19
      samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
  35. 13
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  36. 8
      samples/ControlCatalog/ViewModels/MenuItemViewModel.cs
  37. 2
      samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
  38. 4
      samples/ControlCatalog/ViewModels/NotificationViewModel.cs
  39. 14
      samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
  40. 4
      samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
  41. 72
      src/Avalonia.Base/Matrix.cs
  42. 111
      src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs
  43. 6
      src/Avalonia.Controls/NumericUpDown/NumericUpDownValueChangedEventArgs.cs

10
samples/ControlCatalog/Converter/MathSubtractConverter.cs

@ -6,12 +6,16 @@ namespace ControlCatalog.Converter;
public class MathSubtractConverter : IValueConverter public class MathSubtractConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
return (double)value - (double)parameter; if (value is double dv && parameter is double dp)
{
return dv - dp;
}
return double.NaN;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
throw new NotSupportedException(); throw new NotSupportedException();
} }

10
samples/ControlCatalog/DecoratedWindow.xaml.cs

@ -15,7 +15,7 @@ namespace ControlCatalog
void SetupSide(string name, StandardCursorType cursor, WindowEdge edge) void SetupSide(string name, StandardCursorType cursor, WindowEdge edge)
{ {
var ctl = this.FindControl<Control>(name); var ctl = this.Get<Control>(name);
ctl.Cursor = new Cursor(cursor); ctl.Cursor = new Cursor(cursor);
ctl.PointerPressed += (i, e) => ctl.PointerPressed += (i, e) =>
{ {
@ -26,7 +26,7 @@ namespace ControlCatalog
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
this.FindControl<Control>("TitleBar").PointerPressed += (i, e) => this.Get<Control>("TitleBar").PointerPressed += (i, e) =>
{ {
PlatformImpl?.BeginMoveDrag(e); PlatformImpl?.BeginMoveDrag(e);
}; };
@ -38,12 +38,12 @@ namespace ControlCatalog
SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast); SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast);
SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest); SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest);
SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast); SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast);
this.FindControl<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; }; this.Get<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; };
this.FindControl<Button>("MaximizeButton").Click += delegate this.Get<Button>("MaximizeButton").Click += delegate
{ {
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}; };
this.FindControl<Button>("CloseButton").Click += delegate this.Get<Button>("CloseButton").Click += delegate
{ {
Close(); Close();
}; };

16
samples/ControlCatalog/MainView.xaml.cs

@ -18,9 +18,9 @@ namespace ControlCatalog
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
var sideBar = this.FindControl<TabControl>("Sidebar"); var sideBar = this.Get<TabControl>("Sidebar");
if (AvaloniaLocator.Current.GetService<IRuntimePlatform>().GetRuntimeInfo().IsDesktop) if (AvaloniaLocator.Current?.GetService<IRuntimePlatform>()?.GetRuntimeInfo().IsDesktop == true)
{ {
IList tabItems = ((IList)sideBar.Items); IList tabItems = ((IList)sideBar.Items);
tabItems.Add(new TabItem() tabItems.Add(new TabItem()
@ -36,7 +36,7 @@ namespace ControlCatalog
} }
var themes = this.Find<ComboBox>("Themes"); var themes = this.Get<ComboBox>("Themes");
themes.SelectionChanged += (sender, e) => themes.SelectionChanged += (sender, e) =>
{ {
if (themes.SelectedItem is CatalogTheme theme) if (themes.SelectedItem is CatalogTheme theme)
@ -80,7 +80,7 @@ namespace ControlCatalog
} }
}; };
var flowDirections = this.Find<ComboBox>("FlowDirection"); var flowDirections = this.Get<ComboBox>("FlowDirection");
flowDirections.SelectionChanged += (sender, e) => flowDirections.SelectionChanged += (sender, e) =>
{ {
if (flowDirections.SelectedItem is FlowDirection flowDirection) if (flowDirections.SelectedItem is FlowDirection flowDirection)
@ -89,7 +89,7 @@ namespace ControlCatalog
} }
}; };
var decorations = this.Find<ComboBox>("Decorations"); var decorations = this.Get<ComboBox>("Decorations");
decorations.SelectionChanged += (sender, e) => decorations.SelectionChanged += (sender, e) =>
{ {
if (VisualRoot is Window window if (VisualRoot is Window window
@ -99,8 +99,8 @@ namespace ControlCatalog
} }
}; };
var transparencyLevels = this.Find<ComboBox>("TransparencyLevels"); var transparencyLevels = this.Get<ComboBox>("TransparencyLevels");
IDisposable backgroundSetter = null, paneBackgroundSetter = null; IDisposable? backgroundSetter = null, paneBackgroundSetter = null;
transparencyLevels.SelectionChanged += (sender, e) => transparencyLevels.SelectionChanged += (sender, e) =>
{ {
backgroundSetter?.Dispose(); backgroundSetter?.Dispose();
@ -118,7 +118,7 @@ namespace ControlCatalog
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
var decorations = this.Find<ComboBox>("Decorations"); var decorations = this.Get<ComboBox>("Decorations");
if (VisualRoot is Window window) if (VisualRoot is Window window)
decorations.SelectedIndex = (int)window.SystemDecorations; decorations.SelectedIndex = (int)window.SystemDecorations;
} }

6
samples/ControlCatalog/MainWindow.xaml.cs

@ -12,7 +12,7 @@ namespace ControlCatalog
public class MainWindow : Window public class MainWindow : Window
{ {
private WindowNotificationManager _notificationArea; private WindowNotificationManager _notificationArea;
private NativeMenu _recentMenu; private NativeMenu? _recentMenu;
public MainWindow() public MainWindow()
{ {
@ -28,7 +28,7 @@ namespace ControlCatalog
}; };
DataContext = new MainWindowViewModel(_notificationArea); DataContext = new MainWindowViewModel(_notificationArea);
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu; _recentMenu = ((NativeMenu.GetMenu(this)?.Items[0] as NativeMenuItem)?.Menu?.Items[2] as NativeMenuItem)?.Menu;
} }
public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit"; public static string MenuQuitHeader => RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "Quit Avalonia" : "E_xit";
@ -39,7 +39,7 @@ namespace ControlCatalog
public void OnOpenClicked(object sender, EventArgs args) public void OnOpenClicked(object sender, EventArgs args)
{ {
_recentMenu.Items.Insert(0, new NativeMenuItem("Item " + (_recentMenu.Items.Count + 1))); _recentMenu?.Items.Insert(0, new NativeMenuItem("Item " + (_recentMenu.Items.Count + 1)));
} }
public void OnCloseClicked(object sender, EventArgs args) public void OnCloseClicked(object sender, EventArgs args)

4
samples/ControlCatalog/Models/Countries.cs

@ -237,7 +237,7 @@ namespace ControlCatalog.Models
yield return new Country("Zimbabwe", "SUB-SAHARAN AFRICA", 12236805, 390580, 31.3, 0, 0, 67.69, 1900, 90.7, 26.8, 28.01, 21.84); yield return new Country("Zimbabwe", "SUB-SAHARAN AFRICA", 12236805, 390580, 31.3, 0, 0, 67.69, 1900, 90.7, 26.8, 28.01, 21.84);
} }
static IReadOnlyList<Country> _all; static IReadOnlyList<Country>? _all;
public static IReadOnlyList<Country> All public static IReadOnlyList<Country> All
{ {
@ -253,4 +253,4 @@ namespace ControlCatalog.Models
} }
} }
} }

4
samples/ControlCatalog/Models/GDPValueConverter.cs

@ -14,7 +14,7 @@ namespace ControlCatalog.Models
{ {
public class GDPValueConverter : IValueConverter public class GDPValueConverter : IValueConverter
{ {
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
if (value is int gdp) if (value is int gdp)
{ {
@ -29,7 +29,7 @@ namespace ControlCatalog.Models
return value; return value;
} }
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{ {
throw new NotImplementedException(); throw new NotImplementedException();
} }

16
samples/ControlCatalog/Models/Person.cs

@ -13,8 +13,8 @@ namespace ControlCatalog.Models
{ {
public class Person : INotifyDataErrorInfo, INotifyPropertyChanged public class Person : INotifyDataErrorInfo, INotifyPropertyChanged
{ {
string _firstName; string _firstName = string.Empty;
string _lastName; string _lastName = string.Empty;
bool _isBanned; bool _isBanned;
private int _age; private int _age;
@ -76,7 +76,7 @@ namespace ControlCatalog.Models
Dictionary<string, List<string>> _errorLookup = new Dictionary<string, List<string>>(); Dictionary<string, List<string>> _errorLookup = new Dictionary<string, List<string>>();
void SetError(string propertyName, string error) void SetError(string propertyName, string? error)
{ {
if (string.IsNullOrEmpty(error)) if (string.IsNullOrEmpty(error))
{ {
@ -88,11 +88,11 @@ namespace ControlCatalog.Models
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList)) if (_errorLookup.TryGetValue(propertyName, out List<string> errorList))
{ {
errorList.Clear(); errorList.Clear();
errorList.Add(error); errorList.Add(error!);
} }
else else
{ {
var errors = new List<string> { error }; var errors = new List<string> { error! };
_errorLookup.Add(propertyName, errors); _errorLookup.Add(propertyName, errors);
} }
@ -102,8 +102,8 @@ namespace ControlCatalog.Models
public bool HasErrors => _errorLookup.Count > 0; public bool HasErrors => _errorLookup.Count > 0;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; public event EventHandler<DataErrorsChangedEventArgs>? ErrorsChanged;
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler? PropertyChanged;
void OnErrorsChanged(string propertyName) void OnErrorsChanged(string propertyName)
{ {
@ -114,7 +114,7 @@ namespace ControlCatalog.Models
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
} }
public IEnumerable GetErrors(string propertyName) public IEnumerable? GetErrors(string propertyName)
{ {
if (_errorLookup.TryGetValue(propertyName, out List<string> errorList)) if (_errorLookup.TryGetValue(propertyName, out List<string> errorList))
return errorList; return errorList;

33
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -126,13 +126,13 @@ namespace ControlCatalog.Pages
binding.Bindings.Add(new Binding("Name")); binding.Bindings.Add(new Binding("Name"));
binding.Bindings.Add(new Binding("Abbreviation")); binding.Bindings.Add(new Binding("Abbreviation"));
var multibindingBox = this.FindControl<AutoCompleteBox>("MultiBindingBox"); var multibindingBox = this.Get<AutoCompleteBox>("MultiBindingBox");
multibindingBox.ValueMemberBinding = binding; multibindingBox.ValueMemberBinding = binding;
var asyncBox = this.FindControl<AutoCompleteBox>("AsyncBox"); var asyncBox = this.Get<AutoCompleteBox>("AsyncBox");
asyncBox.AsyncPopulator = PopulateAsync; asyncBox.AsyncPopulator = PopulateAsync;
var customAutocompleteBox = this.FindControl<AutoCompleteBox>("CustomAutocompleteBox"); var customAutocompleteBox = this.Get<AutoCompleteBox>("CustomAutocompleteBox");
customAutocompleteBox.Items = Sentences.SelectMany(x => x); customAutocompleteBox.Items = Sentences.SelectMany(x => x);
customAutocompleteBox.TextFilter = LastWordContains; customAutocompleteBox.TextFilter = LastWordContains;
customAutocompleteBox.TextSelector = AppendWord; customAutocompleteBox.TextSelector = AppendWord;
@ -144,11 +144,12 @@ namespace ControlCatalog.Pages
.OfType<AutoCompleteBox>(); .OfType<AutoCompleteBox>();
} }
private bool StringContains(string str, string query) private bool StringContains(string str, string? query)
{ {
if (query == null) return false;
return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0; return str.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0;
} }
private async Task<IEnumerable<object>> PopulateAsync(string searchText, CancellationToken cancellationToken) private async Task<IEnumerable<object>> PopulateAsync(string? searchText, CancellationToken cancellationToken)
{ {
await Task.Delay(TimeSpan.FromSeconds(1.5), cancellationToken); await Task.Delay(TimeSpan.FromSeconds(1.5), cancellationToken);
@ -157,14 +158,14 @@ namespace ControlCatalog.Pages
.ToList(); .ToList();
} }
private bool LastWordContains(string searchText, string item) private bool LastWordContains(string? searchText, string? item)
{ {
var words = searchText.Split(' '); var words = searchText?.Split(' ') ?? Array.Empty<string>();
var options = Sentences.Select(x => x.First).ToArray(); var options = Sentences.Select(x => x.First).ToArray();
for (var i = 0; i < words.Length; ++i) for (var i = 0; i < words.Length; ++i)
{ {
var word = words[i]; var word = words[i];
for (var j = 0; j < options.Length; ++j) for (var j = 0; word is { } && j < options.Length; ++j)
{ {
var option = options[j]; var option = options[j];
if (option == null) if (option == null)
@ -183,14 +184,18 @@ namespace ControlCatalog.Pages
return options.Any(x => x != null && x.Value == item); return options.Any(x => x != null && x.Value == item);
} }
private string AppendWord(string text, string item) private string AppendWord(string? text, string? item)
{ {
string[] parts = text.Split(' '); if (item is { })
if (parts.Length == 0) {
return item; string[] parts = text?.Split(' ') ?? Array.Empty<string>();
if (parts.Length == 0)
return item;
parts[parts.Length - 1] = item; parts[parts.Length - 1] = item;
return string.Join(" ", parts); return string.Join(" ", parts);
}
return string.Empty;
} }
private void InitializeComponent() private void InitializeComponent()

2
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml.cs

@ -23,7 +23,7 @@ namespace ControlCatalog.Pages
var spinner = (ButtonSpinner)sender; var spinner = (ButtonSpinner)sender;
var txtBox = (TextBlock)spinner.Content; var txtBox = (TextBlock)spinner.Content;
int value = Array.IndexOf(_mountains, txtBox.Text); int value = Array.IndexOf(_mountains, txtBox?.Text);
if (e.Direction == SpinDirection.Increase) if (e.Direction == SpinDirection.Increase)
value++; value++;
else else

4
samples/ControlCatalog/Pages/ButtonsPage.xaml.cs

@ -11,7 +11,7 @@ namespace ControlCatalog.Pages
{ {
InitializeComponent(); InitializeComponent();
this.FindControl<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick; this.Get<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick;
} }
private void InitializeComponent() private void InitializeComponent()
@ -22,7 +22,7 @@ namespace ControlCatalog.Pages
public void OnRepeatButtonClick(object sender, object args) public void OnRepeatButtonClick(object sender, object args)
{ {
repeatButtonClickCount++; repeatButtonClickCount++;
var textBlock = this.FindControl<TextBlock>("RepeatButtonTextBlock"); var textBlock = this.Get<TextBlock>("RepeatButtonTextBlock");
textBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; textBlock.Text = $"Repeat Button: {repeatButtonClickCount}";
} }
} }

12
samples/ControlCatalog/Pages/CalendarDatePickerPage.xaml.cs

@ -10,11 +10,11 @@ namespace ControlCatalog.Pages
{ {
InitializeComponent(); InitializeComponent();
var dp1 = this.FindControl<CalendarDatePicker>("DatePicker1"); var dp1 = this.Get<CalendarDatePicker>("DatePicker1");
var dp2 = this.FindControl<CalendarDatePicker>("DatePicker2"); var dp2 = this.Get<CalendarDatePicker>("DatePicker2");
var dp3 = this.FindControl<CalendarDatePicker>("DatePicker3"); var dp3 = this.Get<CalendarDatePicker>("DatePicker3");
var dp4 = this.FindControl<CalendarDatePicker>("DatePicker4"); var dp4 = this.Get<CalendarDatePicker>("DatePicker4");
var dp5 = this.FindControl<CalendarDatePicker>("DatePicker5"); var dp5 = this.Get<CalendarDatePicker>("DatePicker5");
dp1.SelectedDate = DateTime.Today; dp1.SelectedDate = DateTime.Today;
dp2.SelectedDate = DateTime.Today.AddDays(10); dp2.SelectedDate = DateTime.Today.AddDays(10);
@ -23,7 +23,7 @@ namespace ControlCatalog.Pages
dp4.TemplateApplied += (s, e) => dp4.TemplateApplied += (s, e) =>
{ {
dp4.BlackoutDates.AddDatesInPast(); dp4.BlackoutDates?.AddDatesInPast();
}; };
} }

4
samples/ControlCatalog/Pages/CalendarPage.xaml.cs

@ -11,11 +11,11 @@ namespace ControlCatalog.Pages
this.InitializeComponent(); this.InitializeComponent();
var today = DateTime.Today; var today = DateTime.Today;
var cal1 = this.FindControl<Calendar>("DisplayDatesCalendar"); var cal1 = this.Get<Calendar>("DisplayDatesCalendar");
cal1.DisplayDateStart = today.AddDays(-25); cal1.DisplayDateStart = today.AddDays(-25);
cal1.DisplayDateEnd = today.AddDays(25); cal1.DisplayDateEnd = today.AddDays(25);
var cal2 = this.FindControl<Calendar>("BlackoutDatesCalendar"); var cal2 = this.Get<Calendar>("BlackoutDatesCalendar");
cal2.BlackoutDates.AddDatesInPast(); cal2.BlackoutDates.AddDatesInPast();
cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6)));
} }

11
samples/ControlCatalog/Pages/CarouselPage.xaml.cs

@ -16,6 +16,11 @@ namespace ControlCatalog.Pages
public CarouselPage() public CarouselPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
_carousel = this.Get<Carousel>("carousel");
_left = this.Get<Button>("left");
_right = this.Get<Button>("right");
_transition = this.Get<ComboBox>("transition");
_orientation = this.Get<ComboBox>("orientation");
_left.Click += (s, e) => _carousel.Previous(); _left.Click += (s, e) => _carousel.Previous();
_right.Click += (s, e) => _carousel.Next(); _right.Click += (s, e) => _carousel.Next();
_transition.SelectionChanged += TransitionChanged; _transition.SelectionChanged += TransitionChanged;
@ -25,11 +30,7 @@ namespace ControlCatalog.Pages
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
_carousel = this.FindControl<Carousel>("carousel");
_left = this.FindControl<Button>("left");
_right = this.FindControl<Button>("right");
_transition = this.FindControl<ComboBox>("transition");
_orientation = this.FindControl<ComboBox>("orientation");
} }
private void TransitionChanged(object sender, SelectionChangedEventArgs e) private void TransitionChanged(object sender, SelectionChangedEventArgs e)

22
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml.cs

@ -18,29 +18,29 @@ namespace ControlCatalog.Pages
DataContext = new ContextPageViewModel(); DataContext = new ContextPageViewModel();
_textBox = this.FindControl<TextBox>("TextBox"); _textBox = this.Get<TextBox>("TextBox");
var cutButton = this.FindControl<Button>("CutButton"); var cutButton = this.Get<Button>("CutButton");
cutButton.Click += CloseFlyout; cutButton.Click += CloseFlyout;
var copyButton = this.FindControl<Button>("CopyButton"); var copyButton = this.Get<Button>("CopyButton");
copyButton.Click += CloseFlyout; copyButton.Click += CloseFlyout;
var pasteButton = this.FindControl<Button>("PasteButton"); var pasteButton = this.Get<Button>("PasteButton");
pasteButton.Click += CloseFlyout; pasteButton.Click += CloseFlyout;
var clearButton = this.FindControl<Button>("ClearButton"); var clearButton = this.Get<Button>("ClearButton");
clearButton.Click += CloseFlyout; clearButton.Click += CloseFlyout;
var customContextRequestedBorder = this.FindControl<Border>("CustomContextRequestedBorder"); var customContextRequestedBorder = this.Get<Border>("CustomContextRequestedBorder");
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel); customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.FindControl<Border>("CancellableContextBorder"); var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextFlyout!.Closing += ContextFlyoutPage_Closing; cancellableContextBorder.ContextFlyout!.Closing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextFlyout!.Opening += ContextFlyoutPage_Opening; cancellableContextBorder.ContextFlyout!.Opening += ContextFlyoutPage_Opening;
} }
private ContextPageViewModel _model; private ContextPageViewModel? _model;
protected override void OnDataContextChanged(EventArgs e) protected override void OnDataContextChanged(EventArgs e)
{ {
if (_model != null) if (_model != null)
@ -55,7 +55,7 @@ namespace ControlCatalog.Pages
private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e) private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e)
{ {
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox"); var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox");
e.Cancel = cancelCloseCheckBox.IsChecked ?? false; e.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
} }
private void ContextFlyoutPage_Opening(object sender, EventArgs e) private void ContextFlyoutPage_Opening(object sender, EventArgs e)
@ -63,13 +63,13 @@ namespace ControlCatalog.Pages
if (e is CancelEventArgs cancelArgs) if (e is CancelEventArgs cancelArgs)
{ {
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox"); var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox");
cancelArgs.Cancel = cancelCloseCheckBox.IsChecked ?? false; cancelArgs.Cancel = cancelCloseCheckBox?.IsChecked ?? false;
} }
} }
private void CloseFlyout(object sender, RoutedEventArgs e) private void CloseFlyout(object sender, RoutedEventArgs e)
{ {
_textBox.ContextFlyout.Hide(); _textBox.ContextFlyout?.Hide();
} }
public void CustomContextRequested(object sender, ContextRequestedEventArgs e) public void CustomContextRequested(object sender, ContextRequestedEventArgs e)

6
samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs

@ -15,15 +15,15 @@ namespace ControlCatalog.Pages
this.InitializeComponent(); this.InitializeComponent();
DataContext = new ContextPageViewModel(); DataContext = new ContextPageViewModel();
var customContextRequestedBorder = this.FindControl<Border>("CustomContextRequestedBorder"); var customContextRequestedBorder = this.Get<Border>("CustomContextRequestedBorder");
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel); customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel);
var cancellableContextBorder = this.FindControl<Border>("CancellableContextBorder"); var cancellableContextBorder = this.Get<Border>("CancellableContextBorder");
cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing; cancellableContextBorder.ContextMenu!.ContextMenuClosing += ContextFlyoutPage_Closing;
cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening; cancellableContextBorder.ContextMenu!.ContextMenuOpening += ContextFlyoutPage_Opening;
} }
private ContextPageViewModel _model; private ContextPageViewModel? _model;
protected override void OnDataContextChanged(EventArgs e) protected override void OnDataContextChanged(EventArgs e)
{ {
if (_model != null) if (_model != null)

8
samples/ControlCatalog/Pages/DataGridPage.xaml.cs

@ -21,7 +21,7 @@ namespace ControlCatalog.Pages
var dataGridSortDescription = DataGridSortDescription.FromPath(nameof(Country.Region), ListSortDirection.Ascending, new ReversedStringComparer()); var dataGridSortDescription = DataGridSortDescription.FromPath(nameof(Country.Region), ListSortDirection.Ascending, new ReversedStringComparer());
var collectionView1 = new DataGridCollectionView(Countries.All); var collectionView1 = new DataGridCollectionView(Countries.All);
collectionView1.SortDescriptions.Add(dataGridSortDescription); collectionView1.SortDescriptions.Add(dataGridSortDescription);
var dg1 = this.FindControl<DataGrid>("dataGrid1"); var dg1 = this.Get<DataGrid>("dataGrid1");
dg1.IsReadOnly = true; dg1.IsReadOnly = true;
dg1.LoadingRow += Dg1_LoadingRow; dg1.LoadingRow += Dg1_LoadingRow;
dg1.Sorting += (s, a) => dg1.Sorting += (s, a) =>
@ -37,7 +37,7 @@ namespace ControlCatalog.Pages
}; };
dg1.Items = collectionView1; dg1.Items = collectionView1;
var dg2 = this.FindControl<DataGrid>("dataGridGrouping"); var dg2 = this.Get<DataGrid>("dataGridGrouping");
dg2.IsReadOnly = true; dg2.IsReadOnly = true;
var collectionView2 = new DataGridCollectionView(Countries.All); var collectionView2 = new DataGridCollectionView(Countries.All);
@ -45,7 +45,7 @@ namespace ControlCatalog.Pages
dg2.Items = collectionView2; dg2.Items = collectionView2;
var dg3 = this.FindControl<DataGrid>("dataGridEdit"); var dg3 = this.Get<DataGrid>("dataGridEdit");
dg3.IsReadOnly = false; dg3.IsReadOnly = false;
var items = new List<Person> var items = new List<Person>
@ -58,7 +58,7 @@ namespace ControlCatalog.Pages
dg3.Items = collectionView3; dg3.Items = collectionView3;
var addButton = this.FindControl<Button>("btnAdd"); var addButton = this.Get<Button>("btnAdd");
addButton.Click += (a, b) => collectionView3.AddNew(); addButton.Click += (a, b) => collectionView3.AddNew();
} }

4
samples/ControlCatalog/Pages/DateTimePickerPage.xaml.cs

@ -9,12 +9,12 @@ namespace ControlCatalog.Pages
public DateTimePickerPage() public DateTimePickerPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
this.FindControl<TextBlock>("DatePickerDesc").Text = "Use a DatePicker to let users set a date in your app, " + this.Get<TextBlock>("DatePickerDesc").Text = "Use a DatePicker to let users set a date in your app, " +
"for example to schedule an appointment. The DatePicker displays three controls for month, day, and year. " + "for example to schedule an appointment. The DatePicker displays three controls for month, day, and year. " +
"These controls are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + "These controls are easy to use with touch or mouse, and they can be styled and configured in several different ways. " +
"Order of month, day, and year is dynamically set based on user date settings"; "Order of month, day, and year is dynamically set based on user date settings";
this.FindControl<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " + this.Get<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " +
"to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " + "to set a reminder. The TimePicker displays three controls for hour, minute, and AM / PM(if necessary).These controls " +
"are easy to use with touch or mouse, and they can be styled and configured in several different ways. " + "are easy to use with touch or mouse, and they can be styled and configured in several different ways. " +
"12 - hour or 24 - hour clock and visiblility of AM / PM is dynamically set based on user time settings, or can be overridden."; "12 - hour or 24 - hour clock and visiblility of AM / PM is dynamically set based on user time settings, or can be overridden.";

32
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@ -16,14 +16,14 @@ namespace ControlCatalog.Pages
{ {
this.InitializeComponent(); this.InitializeComponent();
var results = this.FindControl<ItemsPresenter>("PickerLastResults"); var results = this.Get<ItemsPresenter>("PickerLastResults");
var resultsVisible = this.FindControl<TextBlock>("PickerLastResultsVisible"); var resultsVisible = this.Get<TextBlock>("PickerLastResultsVisible");
string lastSelectedDirectory = null; string? lastSelectedDirectory = null;
List<FileDialogFilter>? GetFilters() List<FileDialogFilter>? GetFilters()
{ {
if (this.FindControl<CheckBox>("UseFilters").IsChecked != true) if (this.Get<CheckBox>("UseFilters").IsChecked != true)
return null; return null;
return new List<FileDialogFilter> return new List<FileDialogFilter>
{ {
@ -39,7 +39,7 @@ namespace ControlCatalog.Pages
}; };
} }
this.FindControl<Button>("OpenFile").Click += async delegate this.Get<Button>("OpenFile").Click += async delegate
{ {
// Almost guaranteed to exist // Almost guaranteed to exist
var fullPath = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName; var fullPath = Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName;
@ -56,7 +56,7 @@ namespace ControlCatalog.Pages
results.Items = result; results.Items = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.FindControl<Button>("OpenMultipleFiles").Click += async delegate this.Get<Button>("OpenMultipleFiles").Click += async delegate
{ {
var result = await new OpenFileDialog() var result = await new OpenFileDialog()
{ {
@ -68,7 +68,7 @@ namespace ControlCatalog.Pages
results.Items = result; results.Items = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.FindControl<Button>("SaveFile").Click += async delegate this.Get<Button>("SaveFile").Click += async delegate
{ {
var result = await new SaveFileDialog() var result = await new SaveFileDialog()
{ {
@ -80,7 +80,7 @@ namespace ControlCatalog.Pages
results.Items = new[] { result }; results.Items = new[] { result };
resultsVisible.IsVisible = result != null; resultsVisible.IsVisible = result != null;
}; };
this.FindControl<Button>("SelectFolder").Click += async delegate this.Get<Button>("SelectFolder").Click += async delegate
{ {
var result = await new OpenFolderDialog() var result = await new OpenFolderDialog()
{ {
@ -96,7 +96,7 @@ namespace ControlCatalog.Pages
results.Items = new [] { result }; results.Items = new [] { result };
resultsVisible.IsVisible = result != null; resultsVisible.IsVisible = result != null;
}; };
this.FindControl<Button>("OpenBoth").Click += async delegate this.Get<Button>("OpenBoth").Click += async delegate
{ {
var result = await new OpenFileDialog() var result = await new OpenFileDialog()
{ {
@ -110,35 +110,35 @@ namespace ControlCatalog.Pages
results.Items = result; results.Items = result;
resultsVisible.IsVisible = result?.Any() == true; resultsVisible.IsVisible = result?.Any() == true;
}; };
this.FindControl<Button>("DecoratedWindow").Click += delegate this.Get<Button>("DecoratedWindow").Click += delegate
{ {
new DecoratedWindow().Show(); new DecoratedWindow().Show();
}; };
this.FindControl<Button>("DecoratedWindowDialog").Click += delegate this.Get<Button>("DecoratedWindowDialog").Click += delegate
{ {
new DecoratedWindow().ShowDialog(GetWindow()); new DecoratedWindow().ShowDialog(GetWindow());
}; };
this.FindControl<Button>("Dialog").Click += delegate this.Get<Button>("Dialog").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
window.Height = 200; window.Height = 200;
window.ShowDialog(GetWindow()); window.ShowDialog(GetWindow());
}; };
this.FindControl<Button>("DialogNoTaskbar").Click += delegate this.Get<Button>("DialogNoTaskbar").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
window.Height = 200; window.Height = 200;
window.ShowInTaskbar = false; window.ShowInTaskbar = false;
window.ShowDialog(GetWindow()); window.ShowDialog(GetWindow());
}; };
this.FindControl<Button>("OwnedWindow").Click += delegate this.Get<Button>("OwnedWindow").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
window.Show(GetWindow()); window.Show(GetWindow());
}; };
this.FindControl<Button>("OwnedWindowNoTaskbar").Click += delegate this.Get<Button>("OwnedWindowNoTaskbar").Click += delegate
{ {
var window = CreateSampleWindow(); var window = CreateSampleWindow();
@ -191,7 +191,7 @@ namespace ControlCatalog.Pages
return window; return window;
} }
Window GetWindow() => (Window)this.VisualRoot; Window GetWindow() => this.VisualRoot as Window ?? throw new NullReferenceException("Invalid Owner");
private void InitializeComponent() private void InitializeComponent()
{ {

6
samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs

@ -14,7 +14,7 @@ namespace ControlCatalog.Pages
public DragAndDropPage() public DragAndDropPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
_DropState = this.Find<TextBlock>("DropState"); _DropState = this.Get<TextBlock>("DropState");
int textCount = 0; int textCount = 0;
SetupDnd("Text", d => d.Set(DataFormats.Text, SetupDnd("Text", d => d.Set(DataFormats.Text,
@ -26,8 +26,8 @@ namespace ControlCatalog.Pages
void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects) void SetupDnd(string suffix, Action<DataObject> factory, DragDropEffects effects)
{ {
var dragMe = this.Find<Border>("DragMe" + suffix); var dragMe = this.Get<Border>("DragMe" + suffix);
var dragState = this.Find<TextBlock>("DragState"+suffix); var dragState = this.Get<TextBlock>("DragState"+suffix);
async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e) async void DoDrag(object sender, Avalonia.Input.PointerPressedEventArgs e)
{ {

8
samples/ControlCatalog/Pages/FlyoutsPage.axaml.cs

@ -35,7 +35,7 @@ namespace ControlCatalog.Pages
private void SetXamlTexts() private void SetXamlTexts()
{ {
var bfxt = this.FindControl<TextBlock>("ButtonFlyoutXamlText"); var bfxt = this.Get<TextBlock>("ButtonFlyoutXamlText");
bfxt.Text = "<Button Content=\"Click me!\">\n" + bfxt.Text = "<Button Content=\"Click me!\">\n" +
" <Button.Flyout>\n" + " <Button.Flyout>\n" +
" <Flyout>\n" + " <Flyout>\n" +
@ -45,7 +45,7 @@ namespace ControlCatalog.Pages
" </Flyout>\n" + " </Flyout>\n" +
" </Button.Flyout>\n</Button>"; " </Button.Flyout>\n</Button>";
var mfxt = this.FindControl<TextBlock>("MenuFlyoutXamlText"); var mfxt = this.Get<TextBlock>("MenuFlyoutXamlText");
mfxt.Text = "<Button Content=\"Click me!\">\n" + mfxt.Text = "<Button Content=\"Click me!\">\n" +
" <Button.Flyout>\n" + " <Button.Flyout>\n" +
" <MenuFlyout>\n" + " <MenuFlyout>\n" +
@ -54,7 +54,7 @@ namespace ControlCatalog.Pages
" </MenuFlyout>\n" + " </MenuFlyout>\n" +
" </Button.Flyout>\n</Button>"; " </Button.Flyout>\n</Button>";
var afxt = this.FindControl<TextBlock>("AttachedFlyoutXamlText"); var afxt = this.Get<TextBlock>("AttachedFlyoutXamlText");
afxt.Text = "<Panel Name=\"AttachedFlyoutPanel\">\n" + afxt.Text = "<Panel Name=\"AttachedFlyoutPanel\">\n" +
" <FlyoutBase.AttachedFlyout>\n" + " <FlyoutBase.AttachedFlyout>\n" +
" <Flyout>\n" + " <Flyout>\n" +
@ -66,7 +66,7 @@ namespace ControlCatalog.Pages
"\n\n In DoubleTapped handler:\n" + "\n\n In DoubleTapped handler:\n" +
"FlyoutBase.ShowAttachedFlyout(AttachedFlyoutPanel);"; "FlyoutBase.ShowAttachedFlyout(AttachedFlyoutPanel);";
var sfxt = this.FindControl<TextBlock>("SharedFlyoutXamlText"); var sfxt = this.Get<TextBlock>("SharedFlyoutXamlText");
sfxt.Text = "Declare a flyout in Resources:\n" + sfxt.Text = "Declare a flyout in Resources:\n" +
"<Window.Resources>\n" + "<Window.Resources>\n" +
" <Flyout x:Key=\"SharedFlyout\">\n" + " <Flyout x:Key=\"SharedFlyout\">\n" +

13
samples/ControlCatalog/Pages/ImagePage.xaml.cs

@ -17,9 +17,9 @@ namespace ControlCatalog.Pages
public ImagePage() public ImagePage()
{ {
InitializeComponent(); InitializeComponent();
_bitmapImage = this.FindControl<Image>("bitmapImage"); _bitmapImage = this.Get<Image>("bitmapImage");
_drawingImage = this.FindControl<Image>("drawingImage"); _drawingImage = this.Get<Image>("drawingImage");
_croppedImage = this.FindControl<Image>("croppedImage"); _croppedImage = this.Get<Image>("croppedImage");
} }
private void InitializeComponent() private void InitializeComponent()
@ -50,8 +50,11 @@ namespace ControlCatalog.Pages
if (_croppedImage != null) if (_croppedImage != null)
{ {
var comboxBox = (ComboBox)sender; var comboxBox = (ComboBox)sender;
var croppedBitmap = _croppedImage.Source as CroppedBitmap; if (_croppedImage.Source is CroppedBitmap croppedBitmap)
croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex); {
croppedBitmap.SourceRect = GetCropRect(comboxBox.SelectedIndex);
}
} }
} }

26
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs

@ -24,11 +24,11 @@ namespace ControlCatalog.Pages
public ItemsRepeaterPage() public ItemsRepeaterPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
_repeater = this.FindControl<ItemsRepeater>("repeater"); _repeater = this.Get<ItemsRepeater>("repeater");
_scroller = this.FindControl<ScrollViewer>("scroller"); _scroller = this.Get<ScrollViewer>("scroller");
_scrollToLast = this.FindControl<Button>("scrollToLast"); _scrollToLast = this.Get<Button>("scrollToLast");
_scrollToRandom = this.FindControl<Button>("scrollToRandom"); _scrollToRandom = this.Get<Button>("scrollToRandom");
_scrollToSelected = this.FindControl<Button>("scrollToSelected"); _scrollToSelected = this.Get<Button>("scrollToSelected");
_repeater.PointerPressed += RepeaterClick; _repeater.PointerPressed += RepeaterClick;
_repeater.KeyDown += RepeaterOnKeyDown; _repeater.KeyDown += RepeaterOnKeyDown;
_scrollToLast.Click += scrollToLast_Click; _scrollToLast.Click += scrollToLast_Click;
@ -44,8 +44,10 @@ namespace ControlCatalog.Pages
public void OnSelectTemplateKey(object sender, SelectTemplateEventArgs e) public void OnSelectTemplateKey(object sender, SelectTemplateEventArgs e)
{ {
var item = (ItemsRepeaterPageViewModel.Item)e.DataContext; if (e.DataContext is ItemsRepeaterPageViewModel.Item item)
e.TemplateKey = (item.Index % 2 == 0) ? "even" : "odd"; {
e.TemplateKey = (item.Index % 2 == 0) ? "even" : "odd";
}
} }
private void LayoutChanged(object sender, SelectionChangedEventArgs e) private void LayoutChanged(object sender, SelectionChangedEventArgs e)
@ -115,7 +117,7 @@ namespace ControlCatalog.Pages
private void ScrollTo(int index) private void ScrollTo(int index)
{ {
System.Diagnostics.Debug.WriteLine("Scroll to " + index); System.Diagnostics.Debug.WriteLine("Scroll to " + index);
var layoutManager = ((TopLevel)VisualRoot).LayoutManager; var layoutManager = ((TopLevel)VisualRoot!).LayoutManager;
var element = _repeater.GetOrCreateElement(index); var element = _repeater.GetOrCreateElement(index);
layoutManager.ExecuteLayoutPass(); layoutManager.ExecuteLayoutPass();
element.BringIntoView(); element.BringIntoView();
@ -123,9 +125,11 @@ namespace ControlCatalog.Pages
private void RepeaterClick(object sender, PointerPressedEventArgs e) private void RepeaterClick(object sender, PointerPressedEventArgs e)
{ {
var item = (e.Source as TextBlock)?.DataContext as ItemsRepeaterPageViewModel.Item; if ((e.Source as TextBlock)?.DataContext is ItemsRepeaterPageViewModel.Item item)
_viewModel.SelectedItem = item; {
_selectedIndex = _viewModel.Items.IndexOf(item); _viewModel.SelectedItem = item;
_selectedIndex = _viewModel.Items.IndexOf(item);
}
} }
private void RepeaterOnKeyDown(object sender, KeyEventArgs e) private void RepeaterOnKeyDown(object sender, KeyEventArgs e)

2
samples/ControlCatalog/Pages/LabelsPage.axaml.cs

@ -7,7 +7,7 @@ namespace ControlCatalog.Pages
{ {
public class LabelsPage : UserControl public class LabelsPage : UserControl
{ {
private Person _person; private Person? _person;
public LabelsPage() public LabelsPage()
{ {

2
samples/ControlCatalog/Pages/MenuPage.xaml.cs

@ -22,7 +22,7 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
private MenuPageViewModel _model; private MenuPageViewModel? _model;
protected override void OnDataContextChanged(EventArgs e) protected override void OnDataContextChanged(EventArgs e)
{ {
if (_model != null) if (_model != null)

2
samples/ControlCatalog/Pages/NativeEmbedPage.xaml.cs

@ -79,6 +79,8 @@ namespace ControlCatalog.Pages
public interface INativeDemoControl public interface INativeDemoControl
{ {
/// <param name="isSecond">Used to specify which control should be displayed as a demo</param> /// <param name="isSecond">Used to specify which control should be displayed as a demo</param>
/// <param name="parent"></param>
/// <param name="createDefault"></param>
IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault); IPlatformHandle CreateControl(bool isSecond, IPlatformHandle parent, Func<IPlatformHandle> createDefault);
} }
} }

2
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -65,7 +65,7 @@
Margin="2" HorizontalAlignment="Center"/> Margin="2" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock> <TextBlock Grid.Row="3" Grid.Column="0" VerticalAlignment="Center" Margin="10,2,2,2">Value:</TextBlock>
<NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding #upDown.Value}" VerticalAlignment="Center" <NumericUpDown Grid.Row="3" Grid.Column="1" Value="{Binding DecimalValue}" VerticalAlignment="Center"
Margin="2" HorizontalAlignment="Center"/> Margin="2" HorizontalAlignment="Center"/>

10
samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs

@ -28,16 +28,16 @@ namespace ControlCatalog.Pages
public class NumbersPageViewModel : ViewModelBase public class NumbersPageViewModel : ViewModelBase
{ {
private IList<FormatObject> _formats; private IList<FormatObject>? _formats;
private FormatObject _selectedFormat; private FormatObject _selectedFormat;
private IList<Location> _spinnerLocations; private IList<Location>? _spinnerLocations;
private double _doubleValue; private double _doubleValue;
private decimal _decimalValue; private decimal _decimalValue;
public NumbersPageViewModel() public NumbersPageViewModel()
{ {
SelectedFormat = Formats.FirstOrDefault(); _selectedFormat = Formats.FirstOrDefault();
} }
public double DoubleValue public double DoubleValue
@ -103,7 +103,7 @@ namespace ControlCatalog.Pages
public class FormatObject public class FormatObject
{ {
public string Value { get; set; } public string? Value { get; set; }
public string Name { get; set; } public string? Name { get; set; }
} }
} }

2
samples/ControlCatalog/Pages/ScreenPage.cs

@ -18,7 +18,7 @@ namespace ControlCatalog.Pages
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnAttachedToVisualTree(e); base.OnAttachedToVisualTree(e);
Window w = (Window)VisualRoot; Window w = (Window)VisualRoot!;
w.PositionChanged += (sender, args) => InvalidateVisual(); w.PositionChanged += (sender, args) => InvalidateVisual();
} }

12
samples/ControlCatalog/Pages/TabControlPage.xaml.cs

@ -52,7 +52,7 @@ namespace ControlCatalog.Pages
private IBitmap LoadBitmap(string uri) private IBitmap LoadBitmap(string uri)
{ {
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>(); var assets = AvaloniaLocator.Current!.GetService<IAssetLoader>()!;
return new Bitmap(assets.Open(new Uri(uri))); return new Bitmap(assets.Open(new Uri(uri)));
} }
@ -60,7 +60,7 @@ namespace ControlCatalog.Pages
{ {
private Dock _tabPlacement; private Dock _tabPlacement;
public TabItemViewModel[] Tabs { get; set; } public TabItemViewModel[]? Tabs { get; set; }
public Dock TabPlacement public Dock TabPlacement
{ {
@ -71,10 +71,10 @@ namespace ControlCatalog.Pages
private class TabItemViewModel private class TabItemViewModel
{ {
public string Header { get; set; } public string? Header { get; set; }
public string Text { get; set; } public string? Text { get; set; }
public IBitmap Image { get; set; } public IBitmap? Image { get; set; }
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
} }
} }
} }

2
samples/ControlCatalog/Pages/TabStripPage.xaml.cs

@ -38,7 +38,7 @@ namespace ControlCatalog.Pages
private class TabStripItemViewModel private class TabStripItemViewModel
{ {
public string Header { get; set; } public string? Header { get; set; }
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
} }
} }

2
samples/ControlCatalog/ViewModels/ApplicationViewModel.cs

@ -10,7 +10,7 @@ namespace ControlCatalog.ViewModels
{ {
ExitCommand = MiniCommand.Create(() => ExitCommand = MiniCommand.Create(() =>
{ {
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime)
{ {
lifetime.Shutdown(); lifetime.Shutdown();
} }

2
samples/ControlCatalog/ViewModels/ContextPageViewModel.cs

@ -9,7 +9,7 @@ namespace ControlCatalog.ViewModels
{ {
public class ContextPageViewModel public class ContextPageViewModel
{ {
public Control View { get; set; } public Control? View { get; set; }
public ContextPageViewModel() public ContextPageViewModel()
{ {
OpenCommand = MiniCommand.CreateFromTask(Open); OpenCommand = MiniCommand.CreateFromTask(Open);

2
samples/ControlCatalog/ViewModels/CursorPageViewModel.cs

@ -18,7 +18,7 @@ namespace ControlCatalog.ViewModels
.Select(x => new StandardCursorModel(x)) .Select(x => new StandardCursorModel(x))
.ToList(); .ToList();
var loader = AvaloniaLocator.Current.GetService<IAssetLoader>(); var loader = AvaloniaLocator.Current!.GetService<IAssetLoader>()!;
var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png")); var s = loader.Open(new Uri("avares://ControlCatalog/Assets/avalonia-32.png"));
var bitmap = new Bitmap(s); var bitmap = new Bitmap(s);
CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16)); CustomCursor = new Cursor(bitmap, new PixelPoint(16, 16));

19
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs

@ -14,7 +14,7 @@ namespace ControlCatalog.ViewModels
public ItemsRepeaterPageViewModel() public ItemsRepeaterPageViewModel()
{ {
Items = CreateItems(); _items = CreateItems();
} }
public ObservableCollection<Item> Items public ObservableCollection<Item> Items
@ -23,12 +23,12 @@ namespace ControlCatalog.ViewModels
set => this.RaiseAndSetIfChanged(ref _items, value); set => this.RaiseAndSetIfChanged(ref _items, value);
} }
public Item SelectedItem { get; set; } public Item? SelectedItem { get; set; }
public void AddItem() public void AddItem()
{ {
var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1; var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1;
Items.Insert(index + 1, new Item(index + 1) { Text = $"New Item {_newItemIndex++}" }); Items.Insert(index + 1, new Item(index + 1, $"New Item {_newItemIndex++}"));
} }
public void RemoveItem() public void RemoveItem()
@ -66,19 +66,20 @@ namespace ControlCatalog.ViewModels
_newGenerationIndex++; _newGenerationIndex++;
return new ObservableCollection<Item>( return new ObservableCollection<Item>(
Enumerable.Range(1, 100000).Select(i => new Item(i) Enumerable.Range(1, 100000).Select(i => new Item(i, $"Item {i.ToString()} {suffix}")));
{
Text = $"Item {i.ToString()} {suffix}"
}));
} }
public class Item : ViewModelBase public class Item : ViewModelBase
{ {
private double _height = double.NaN; private double _height = double.NaN;
public Item(int index) => Index = index; public Item(int index, string text)
{
Index = index;
Text = text;
}
public int Index { get; } public int Index { get; }
public string Text { get; set; } public string Text { get; }
public double Height public double Height
{ {

13
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -16,11 +16,11 @@ namespace ControlCatalog.ViewModels
private bool _isMenuItemChecked = true; private bool _isMenuItemChecked = true;
private WindowState _windowState; private WindowState _windowState;
private WindowState[] _windowStates; private WindowState[] _windowStates = Array.Empty<WindowState>();
private int _transparencyLevel; private int _transparencyLevel;
private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome; private ExtendClientAreaChromeHints _chromeHints = ExtendClientAreaChromeHints.PreferSystemChrome;
private bool _extendClientAreaEnabled; private bool _extendClientAreaEnabled;
private bool _systemTitleBarEnabled; private bool _systemTitleBarEnabled;
private bool _preferSystemChromeEnabled; private bool _preferSystemChromeEnabled;
private double _titleBarHeight; private double _titleBarHeight;
@ -47,14 +47,15 @@ namespace ControlCatalog.ViewModels
{ {
var dialog = new AboutAvaloniaDialog(); var dialog = new AboutAvaloniaDialog();
var mainWindow = (App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow; if ((App.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow is { } mainWindow)
{
await dialog.ShowDialog(mainWindow); await dialog.ShowDialog(mainWindow);
}
}); });
ExitCommand = MiniCommand.Create(() => ExitCommand = MiniCommand.Create(() =>
{ {
(App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown(); (App.Current?.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.Shutdown();
}); });
ToggleMenuItemCheckedCommand = MiniCommand.Create(() => ToggleMenuItemCheckedCommand = MiniCommand.Create(() =>

8
samples/ControlCatalog/ViewModels/MenuItemViewModel.cs

@ -5,9 +5,9 @@ namespace ControlCatalog.ViewModels
{ {
public class MenuItemViewModel public class MenuItemViewModel
{ {
public string Header { get; set; } public string? Header { get; set; }
public ICommand Command { get; set; } public ICommand? Command { get; set; }
public object CommandParameter { get; set; } public object? CommandParameter { get; set; }
public IList<MenuItemViewModel> Items { get; set; } public IList<MenuItemViewModel>? Items { get; set; }
} }
} }

2
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@ -10,7 +10,7 @@ namespace ControlCatalog.ViewModels
{ {
public class MenuPageViewModel public class MenuPageViewModel
{ {
public Control View { get; set; } public Control? View { get; set; }
public MenuPageViewModel() public MenuPageViewModel()
{ {
OpenCommand = MiniCommand.CreateFromTask(Open); OpenCommand = MiniCommand.CreateFromTask(Open);

4
samples/ControlCatalog/ViewModels/NotificationViewModel.cs

@ -19,8 +19,8 @@ namespace ControlCatalog.ViewModels
}); });
} }
public string Title { get; set; } public string? Title { get; set; }
public string Message { get; set; } public string? Message { get; set; }
public MiniCommand YesCommand { get; } public MiniCommand YesCommand { get; }

14
samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs

@ -19,7 +19,7 @@ namespace ControlCatalog.ViewModels
{ {
public TransitioningContentControlPageViewModel() public TransitioningContentControlPageViewModel()
{ {
var assetLoader = AvaloniaLocator.Current.GetService<IAssetLoader>(); var assetLoader = AvaloniaLocator.Current?.GetService<IAssetLoader>()!;
var images = new string[] var images = new string[]
{ {
@ -36,8 +36,8 @@ namespace ControlCatalog.ViewModels
SetupTransitions(); SetupTransitions();
SelectedTransition = PageTransitions[1]; _SelectedTransition = PageTransitions[1];
SelectedImage = Images[0]; _SelectedImage = Images[0];
} }
public List<PageTransition> PageTransitions { get; } = new List<PageTransition>(); public List<PageTransition> PageTransitions { get; } = new List<PageTransition>();
@ -160,12 +160,12 @@ namespace ControlCatalog.ViewModels
public string DisplayTitle { get; } public string DisplayTitle { get; }
private IPageTransition _Transition; private IPageTransition? _Transition;
/// <summary> /// <summary>
/// Gets or sets the transition /// Gets or sets the transition
/// </summary> /// </summary>
public IPageTransition Transition public IPageTransition? Transition
{ {
get { return _Transition; } get { return _Transition; }
set { this.RaiseAndSetIfChanged(ref _Transition, value); } set { this.RaiseAndSetIfChanged(ref _Transition, value); }
@ -201,7 +201,7 @@ namespace ControlCatalog.ViewModels
/// </summary> /// </summary>
public TimeSpan Duration { get; set; } public TimeSpan Duration { get; set; }
public async Task Start(Visual from, Visual to, bool forward, CancellationToken cancellationToken) public async Task Start(Visual? from, Visual? to, bool forward, CancellationToken cancellationToken)
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ {
@ -293,7 +293,7 @@ namespace ControlCatalog.ViewModels
/// <remarks> /// <remarks>
/// Any one of the parameters may be null, but not both. /// Any one of the parameters may be null, but not both.
/// </remarks> /// </remarks>
private static IVisual GetVisualParent(IVisual from, IVisual to) private static IVisual GetVisualParent(IVisual? from, IVisual? to)
{ {
var p1 = (from ?? to)!.VisualParent; var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent; var p2 = (to ?? from)!.VisualParent;

4
samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs

@ -92,7 +92,7 @@ namespace ControlCatalog.ViewModels
public class Node public class Node
{ {
private ObservableCollection<Node> _children; private ObservableCollection<Node>? _children;
private int _childIndex = 10; private int _childIndex = 10;
public Node() public Node()
@ -106,7 +106,7 @@ namespace ControlCatalog.ViewModels
Header = parent.Header + ' ' + index; Header = parent.Header + ' ' + index;
} }
public Node Parent { get; } public Node? Parent { get; }
public string Header { get; } public string Header { get; }
public bool AreChildrenInitialized => _children != null; public bool AreChildrenInitialized => _children != null;
public ObservableCollection<Node> Children => _children ??= CreateChildren(); public ObservableCollection<Node> Children => _children ??= CreateChildren();

72
src/Avalonia.Base/Matrix.cs

@ -9,14 +9,14 @@ namespace Avalonia
/// <summary> /// <summary>
/// A 3x3 matrix. /// A 3x3 matrix.
/// </summary> /// </summary>
/// <remakrs>Matrix layout: /// <remarks>Matrix layout:
/// | 1st col | 2nd col | 3r col | /// | 1st col | 2nd col | 3r col |
/// 1st row | scaleX | skrewY | persX | /// 1st row | scaleX | skewY | perspX |
/// 2nd row | skrewX | scaleY | persY | /// 2nd row | skewX | scaleY | perspY |
/// 3rd row | transX | transY | persZ | /// 3rd row | transX | transY | perspZ |
/// ///
/// Note: Skia.SkMatrix uses a transposed layout (where for example skrewX/skrewY and perspp0/tranX are swapped). /// Note: Skia.SkMatrix uses a transposed layout (where for example skewX/skewY and persp0/transX are swapped).
/// </remakrs> /// </remarks>
#if !BUILDTASK #if !BUILDTASK
public public
#endif #endif
@ -36,18 +36,18 @@ namespace Avalonia
/// Initializes a new instance of the <see cref="Matrix"/> struct (equivalent to a 2x3 Matrix without perspective). /// Initializes a new instance of the <see cref="Matrix"/> struct (equivalent to a 2x3 Matrix without perspective).
/// </summary> /// </summary>
/// <param name="scaleX">The first element of the first row.</param> /// <param name="scaleX">The first element of the first row.</param>
/// <param name="skrewY">The second element of the first row.</param> /// <param name="skewY">The second element of the first row.</param>
/// <param name="skrewX">The first element of the second row.</param> /// <param name="skewX">The first element of the second row.</param>
/// <param name="scaleY">The second element of the second row.</param> /// <param name="scaleY">The second element of the second row.</param>
/// <param name="offsetX">The first element of the third row.</param> /// <param name="offsetX">The first element of the third row.</param>
/// <param name="offsetY">The second element of the third row.</param> /// <param name="offsetY">The second element of the third row.</param>
public Matrix( public Matrix(
double scaleX, double scaleX,
double skrewY, double skewY,
double skrewX, double skewX,
double scaleY, double scaleY,
double offsetX, double offsetX,
double offsetY) : this( scaleX, skrewY, 0, skrewX, scaleY, 0, offsetX, offsetY, 1) double offsetY) : this( scaleX, skewY, 0, skewX, scaleY, 0, offsetX, offsetY, 1)
{ {
} }
@ -57,34 +57,34 @@ namespace Avalonia
/// Initializes a new instance of the <see cref="Matrix"/> struct. /// Initializes a new instance of the <see cref="Matrix"/> struct.
/// </summary> /// </summary>
/// <param name="scaleX">The first element of the first row.</param> /// <param name="scaleX">The first element of the first row.</param>
/// <param name="skrewY">The second element of the first row.</param> /// <param name="skewY">The second element of the first row.</param>
/// <param name="persX">The third element of the first row.</param> /// <param name="perspX">The third element of the first row.</param>
/// <param name="skrewX">The first element of the second row.</param> /// <param name="skewX">The first element of the second row.</param>
/// <param name="scaleY">The second element of the second row.</param> /// <param name="scaleY">The second element of the second row.</param>
/// <param name="persY">The third element of the second row.</param> /// <param name="perspY">The third element of the second row.</param>
/// <param name="offsetX">The first element of the third row.</param> /// <param name="offsetX">The first element of the third row.</param>
/// <param name="offsetY">The second element of the third row.</param> /// <param name="offsetY">The second element of the third row.</param>
/// <param name="persZ">The third element of the third row.</param> /// <param name="perspZ">The third element of the third row.</param>
public Matrix( public Matrix(
double scaleX, double scaleX,
double skrewY, double skewY,
double persX, double perspX,
double skrewX, double skewX,
double scaleY, double scaleY,
double persY, double perspY,
double offsetX, double offsetX,
double offsetY, double offsetY,
double persZ) double perspZ)
{ {
_m11 = scaleX; _m11 = scaleX;
_m12 = skrewY; _m12 = skewY;
_m13 = persX; _m13 = perspX;
_m21 = skrewX; _m21 = skewX;
_m22 = scaleY; _m22 = scaleY;
_m23 = persY; _m23 = perspY;
_m31 = offsetX; _m31 = offsetX;
_m32 = offsetY; _m32 = offsetY;
_m33 = persZ; _m33 = perspZ;
} }
/// <summary> /// <summary>
@ -111,17 +111,17 @@ namespace Avalonia
public double M11 => _m11; public double M11 => _m11;
/// <summary> /// <summary>
/// The second element of the first row (skrewY). /// The second element of the first row (skewY).
/// </summary> /// </summary>
public double M12 => _m12; public double M12 => _m12;
/// <summary> /// <summary>
/// The third element of the first row (persX: input x-axis perspective factor). /// The third element of the first row (perspX: input x-axis perspective factor).
/// </summary> /// </summary>
public double M13 => _m13; public double M13 => _m13;
/// <summary> /// <summary>
/// The first element of the second row (skrewX). /// The first element of the second row (skewX).
/// </summary> /// </summary>
public double M21 => _m21; public double M21 => _m21;
@ -131,7 +131,7 @@ namespace Avalonia
public double M22 => _m22; public double M22 => _m22;
/// <summary> /// <summary>
/// The third element of the second row (persY: input y-axis perspective factor). /// The third element of the second row (perspY: input y-axis perspective factor).
/// </summary> /// </summary>
public double M23 => _m23; public double M23 => _m23;
@ -146,7 +146,7 @@ namespace Avalonia
public double M32 => _m32; public double M32 => _m32;
/// <summary> /// <summary>
/// The third element of the third row (persZ: perspective scale factor). /// The third element of the third row (perspZ: perspective scale factor).
/// </summary> /// </summary>
public double M33 => _m33; public double M33 => _m33;
@ -481,7 +481,7 @@ namespace Avalonia
/// <summary> /// <summary>
/// Parses a <see cref="Matrix"/> string. /// Parses a <see cref="Matrix"/> string.
/// </summary> /// </summary>
/// <param name="s">Six or nine comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY[, persX, persY, persZ]) that describe the new <see cref="Matrix"/></param> /// <param name="s">Six or nine comma-delimited double values (m11, m12, m21, m22, offsetX, offsetY[, perspX, perspY, perspZ]) that describe the new <see cref="Matrix"/></param>
/// <returns>The <see cref="Matrix"/>.</returns> /// <returns>The <see cref="Matrix"/>.</returns>
public static Matrix Parse(string s) public static Matrix Parse(string s)
{ {
@ -497,11 +497,11 @@ namespace Avalonia
var v4 = tokenizer.ReadDouble(); var v4 = tokenizer.ReadDouble();
var v5 = tokenizer.ReadDouble(); var v5 = tokenizer.ReadDouble();
var v6 = tokenizer.ReadDouble(); var v6 = tokenizer.ReadDouble();
var pers = tokenizer.TryReadDouble(out var v7); var persp = tokenizer.TryReadDouble(out var v7);
pers = pers && tokenizer.TryReadDouble(out v8); persp = persp && tokenizer.TryReadDouble(out v8);
pers = pers && tokenizer.TryReadDouble(out v9); persp = persp && tokenizer.TryReadDouble(out v9);
if (pers) if (persp)
return new Matrix(v1, v2, v7, v3, v4, v8, v5, v6, v9); return new Matrix(v1, v2, v7, v3, v4, v8, v5, v6, v9);
else else
return new Matrix(v1, v2, v3, v4, v5, v6); return new Matrix(v1, v2, v3, v4, v5, v6);

111
src/Avalonia.Controls/NumericUpDown/NumericUpDown.cs

@ -107,8 +107,8 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="Value"/> property. /// Defines the <see cref="Value"/> property.
/// </summary> /// </summary>
public static readonly DirectProperty<NumericUpDown, decimal> ValueProperty = public static readonly DirectProperty<NumericUpDown, decimal?> ValueProperty =
AvaloniaProperty.RegisterDirect<NumericUpDown, decimal>(nameof(Value), updown => updown.Value, AvaloniaProperty.RegisterDirect<NumericUpDown, decimal?>(nameof(Value), updown => updown.Value,
(updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true); (updown, v) => updown.Value = v, defaultBindingMode: BindingMode.TwoWay, enableDataValidation: true);
/// <summary> /// <summary>
@ -131,7 +131,7 @@ namespace Avalonia.Controls
private IDisposable? _textBoxTextChangedSubscription; private IDisposable? _textBoxTextChangedSubscription;
private decimal _value; private decimal? _value;
private string? _text; private string? _text;
private bool _internalValueSet; private bool _internalValueSet;
private bool _clipValueToMinMax; private bool _clipValueToMinMax;
@ -277,7 +277,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Gets or sets the value. /// Gets or sets the value.
/// </summary> /// </summary>
public decimal Value public decimal? Value
{ {
get { return _value; } get { return _value; }
set set
@ -351,7 +351,7 @@ namespace Avalonia.Controls
/// <inheritdoc /> /// <inheritdoc />
protected override void OnLostFocus(RoutedEventArgs e) protected override void OnLostFocus(RoutedEventArgs e)
{ {
CommitInput(); CommitInput(true);
base.OnLostFocus(e); base.OnLostFocus(e);
} }
@ -489,9 +489,9 @@ namespace Avalonia.Controls
{ {
SetValidSpinDirection(); SetValidSpinDirection();
} }
if (ClipValueToMinMax) if (ClipValueToMinMax && Value.HasValue)
{ {
Value = MathUtilities.Clamp(Value, Minimum, Maximum); Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum);
} }
} }
@ -506,9 +506,9 @@ namespace Avalonia.Controls
{ {
SetValidSpinDirection(); SetValidSpinDirection();
} }
if (ClipValueToMinMax) if (ClipValueToMinMax && Value.HasValue)
{ {
Value = MathUtilities.Clamp(Value, Minimum, Maximum); Value = MathUtilities.Clamp(Value.Value, Minimum, Maximum);
} }
} }
@ -530,7 +530,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="oldValue">The old value.</param> /// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param> /// <param name="newValue">The new value.</param>
protected virtual void OnValueChanged(decimal oldValue, decimal newValue) protected virtual void OnValueChanged(decimal? oldValue, decimal? newValue)
{ {
if (!_internalValueSet && IsInitialized) if (!_internalValueSet && IsInitialized)
{ {
@ -573,7 +573,7 @@ namespace Avalonia.Controls
/// Called when the <see cref="Value"/> property has to be coerced. /// Called when the <see cref="Value"/> property has to be coerced.
/// </summary> /// </summary>
/// <param name="baseValue">The value.</param> /// <param name="baseValue">The value.</param>
protected virtual decimal OnCoerceValue(decimal baseValue) protected virtual decimal? OnCoerceValue(decimal? baseValue)
{ {
return baseValue; return baseValue;
} }
@ -607,7 +607,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="oldValue">The old value.</param> /// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param> /// <param name="newValue">The new value.</param>
protected virtual void RaiseValueChangedEvent(decimal oldValue, decimal newValue) protected virtual void RaiseValueChangedEvent(decimal? oldValue, decimal? newValue)
{ {
var e = new NumericUpDownValueChangedEventArgs(ValueChangedEvent, oldValue, newValue); var e = new NumericUpDownValueChangedEventArgs(ValueChangedEvent, oldValue, newValue);
RaiseEvent(e); RaiseEvent(e);
@ -616,9 +616,9 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Converts the formatted text to a value. /// Converts the formatted text to a value.
/// </summary> /// </summary>
private decimal ConvertTextToValue(string text) private decimal? ConvertTextToValue(string? text)
{ {
decimal result = 0; decimal? result = null;
if (string.IsNullOrEmpty(text)) if (string.IsNullOrEmpty(text))
{ {
@ -635,9 +635,9 @@ namespace Avalonia.Controls
result = ConvertTextToValueCore(currentValueText, text); result = ConvertTextToValueCore(currentValueText, text);
if (ClipValueToMinMax) if (ClipValueToMinMax && result.HasValue)
{ {
return MathUtilities.Clamp(result, Minimum, Maximum); return MathUtilities.Clamp(result.Value, Minimum, Maximum);
} }
ValidateMinMax(result); ValidateMinMax(result);
@ -649,7 +649,7 @@ namespace Avalonia.Controls
/// Converts the value to formatted text. /// Converts the value to formatted text.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
private string ConvertValueToText() private string? ConvertValueToText()
{ {
//Manage FormatString of type "{}{0:N2} °" (in xaml) or "{0:N2} °" in code-behind. //Manage FormatString of type "{}{0:N2} °" (in xaml) or "{0:N2} °" in code-behind.
if (FormatString.Contains("{0")) if (FormatString.Contains("{0"))
@ -657,7 +657,7 @@ namespace Avalonia.Controls
return string.Format(NumberFormat, FormatString, Value); return string.Format(NumberFormat, FormatString, Value);
} }
return Value.ToString(FormatString, NumberFormat); return Value?.ToString(FormatString, NumberFormat);
} }
/// <summary> /// <summary>
@ -665,7 +665,16 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private void OnIncrement() private void OnIncrement()
{ {
var result = Value + Increment; decimal result;
if (Value.HasValue)
{
result = Value.Value + Increment;
}
else
{
result = Minimum;
}
Value = MathUtilities.Clamp(result, Minimum, Maximum); Value = MathUtilities.Clamp(result, Minimum, Maximum);
} }
@ -674,7 +683,17 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
private void OnDecrement() private void OnDecrement()
{ {
var result = Value - Increment; decimal result;
if (Value.HasValue)
{
result = Value.Value - Increment;
}
else
{
result = Maximum;
}
Value = MathUtilities.Clamp(result, Minimum, Maximum); Value = MathUtilities.Clamp(result, Minimum, Maximum);
} }
@ -688,6 +707,11 @@ namespace Avalonia.Controls
// Zero increment always prevents spin. // Zero increment always prevents spin.
if (Increment != 0 && !IsReadOnly) if (Increment != 0 && !IsReadOnly)
{ {
if (!Value.HasValue)
{
validDirections = ValidSpinDirections.Increase | ValidSpinDirections.Decrease;
}
if (Value < Maximum) if (Value < Maximum)
{ {
validDirections = validDirections | ValidSpinDirections.Increase; validDirections = validDirections | ValidSpinDirections.Increase;
@ -825,13 +849,13 @@ namespace Avalonia.Controls
{ {
if (e.Sender is NumericUpDown upDown) if (e.Sender is NumericUpDown upDown)
{ {
var oldValue = (decimal)e.OldValue!; var oldValue = (decimal?)e.OldValue;
var newValue = (decimal)e.NewValue!; var newValue = (decimal?)e.NewValue;
upDown.OnValueChanged(oldValue, newValue); upDown.OnValueChanged(oldValue, newValue);
} }
} }
private void SetValueInternal(decimal value) private void SetValueInternal(decimal? value)
{ {
_internalValueSet = true; _internalValueSet = true;
try try
@ -946,9 +970,9 @@ namespace Avalonia.Controls
remove { RemoveHandler(ValueChangedEvent, value); } remove { RemoveHandler(ValueChangedEvent, value); }
} }
private bool CommitInput() private bool CommitInput(bool forceTextUpdate = false)
{ {
return SyncTextAndValueProperties(true, Text); return SyncTextAndValueProperties(true, Text, forceTextUpdate);
} }
/// <summary> /// <summary>
@ -978,28 +1002,24 @@ namespace Avalonia.Controls
{ {
if (updateValueFromText) if (updateValueFromText)
{ {
if (!string.IsNullOrEmpty(text)) try
{ {
try var newValue = ConvertTextToValue(text);
if (!Equals(newValue, Value))
{ {
var newValue = ConvertTextToValue(text); SetValueInternal(newValue);
if (!Equals(newValue, Value))
{
SetValueInternal(newValue);
}
}
catch
{
parsedTextIsValid = false;
} }
} }
catch
{
parsedTextIsValid = false;
}
} }
// Do not touch the ongoing text input from user. // Do not touch the ongoing text input from user.
if (!_isTextChangedFromUI) if (!_isTextChangedFromUI)
{ {
var keepEmpty = !forceTextUpdate && string.IsNullOrEmpty(Text); if (forceTextUpdate)
if (!keepEmpty)
{ {
var newText = ConvertValueToText(); var newText = ConvertValueToText();
if (!Equals(Text, newText)) if (!Equals(Text, newText))
@ -1036,10 +1056,15 @@ namespace Avalonia.Controls
return parsedTextIsValid; return parsedTextIsValid;
} }
private decimal ConvertTextToValueCore(string currentValueText, string text) private decimal? ConvertTextToValueCore(string? currentValueText, string? text)
{ {
decimal result; decimal result;
if (string.IsNullOrEmpty(text))
{
return null;
}
if (IsPercent(FormatString)) if (IsPercent(FormatString))
{ {
result = ParsePercent(text, NumberFormat); result = ParsePercent(text, NumberFormat);
@ -1052,7 +1077,7 @@ namespace Avalonia.Controls
var shouldThrow = true; var shouldThrow = true;
// Check if CurrentValueText is also failing => it also contains special characters. ex : 90° // Check if CurrentValueText is also failing => it also contains special characters. ex : 90°
if (!decimal.TryParse(currentValueText, ParsingNumberStyle, NumberFormat, out var _)) if (!string.IsNullOrEmpty(currentValueText) && !decimal.TryParse(currentValueText, ParsingNumberStyle, NumberFormat, out var _))
{ {
// extract non-digit characters // extract non-digit characters
var currentValueTextSpecialCharacters = currentValueText.Where(c => !char.IsDigit(c)); var currentValueTextSpecialCharacters = currentValueText.Where(c => !char.IsDigit(c));
@ -1082,8 +1107,12 @@ namespace Avalonia.Controls
return result; return result;
} }
private void ValidateMinMax(decimal value) private void ValidateMinMax(decimal? value)
{ {
if (!value.HasValue)
{
return;
}
if (value < Minimum) if (value < Minimum)
{ {
throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be greater than Minimum value of {0}", Minimum)); throw new ArgumentOutOfRangeException(nameof(value), string.Format("Value must be greater than Minimum value of {0}", Minimum));

6
src/Avalonia.Controls/NumericUpDown/NumericUpDownValueChangedEventArgs.cs

@ -4,13 +4,13 @@ namespace Avalonia.Controls
{ {
public class NumericUpDownValueChangedEventArgs : RoutedEventArgs public class NumericUpDownValueChangedEventArgs : RoutedEventArgs
{ {
public NumericUpDownValueChangedEventArgs(RoutedEvent routedEvent, decimal oldValue, decimal newValue) : base(routedEvent) public NumericUpDownValueChangedEventArgs(RoutedEvent routedEvent, decimal? oldValue, decimal? newValue) : base(routedEvent)
{ {
OldValue = oldValue; OldValue = oldValue;
NewValue = newValue; NewValue = newValue;
} }
public decimal OldValue { get; } public decimal? OldValue { get; }
public decimal NewValue { get; } public decimal? NewValue { get; }
} }
} }

Loading…
Cancel
Save