committed by
GitHub
106 changed files with 961 additions and 1001 deletions
@ -1,53 +1,45 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using System; |
|||
using Avalonia.Input; |
|||
|
|||
namespace ControlCatalog |
|||
{ |
|||
public class DecoratedWindow : Window |
|||
public partial class DecoratedWindow : Window |
|||
{ |
|||
public DecoratedWindow() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
void SetupSide(string name, StandardCursorType cursor, WindowEdge edge) |
|||
{ |
|||
var ctl = this.Get<Control>(name); |
|||
ctl.Cursor = new Cursor(cursor); |
|||
ctl.PointerPressed += (i, e) => |
|||
{ |
|||
if (WindowState == WindowState.Normal) |
|||
BeginResizeDrag(edge, e); |
|||
}; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
this.Get<Control>("TitleBar").PointerPressed += (i, e) => |
|||
InitializeComponent(); |
|||
TitleBar.PointerPressed += (i, e) => |
|||
{ |
|||
BeginMoveDrag(e); |
|||
}; |
|||
SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West); |
|||
SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East); |
|||
SetupSide("Top", StandardCursorType.TopSide, WindowEdge.North); |
|||
SetupSide("Bottom", StandardCursorType.BottomSide, WindowEdge.South); |
|||
SetupSide("TopLeft", StandardCursorType.TopLeftCorner, WindowEdge.NorthWest); |
|||
SetupSide("TopRight", StandardCursorType.TopRightCorner, WindowEdge.NorthEast); |
|||
SetupSide("BottomLeft", StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest); |
|||
SetupSide("BottomRight", StandardCursorType.BottomRightCorner, WindowEdge.SouthEast); |
|||
this.Get<Button>("MinimizeButton").Click += delegate { this.WindowState = WindowState.Minimized; }; |
|||
this.Get<Button>("MaximizeButton").Click += delegate |
|||
SetupSide(Left, StandardCursorType.LeftSide, WindowEdge.West); |
|||
SetupSide(Right, StandardCursorType.RightSide, WindowEdge.East); |
|||
SetupSide(Top, StandardCursorType.TopSide, WindowEdge.North); |
|||
SetupSide(Bottom, StandardCursorType.BottomSide, WindowEdge.South); |
|||
SetupSide(TopLeft, StandardCursorType.TopLeftCorner, WindowEdge.NorthWest); |
|||
SetupSide(TopRight, StandardCursorType.TopRightCorner, WindowEdge.NorthEast); |
|||
SetupSide(BottomLeft, StandardCursorType.BottomLeftCorner, WindowEdge.SouthWest); |
|||
SetupSide(BottomRight, StandardCursorType.BottomRightCorner, WindowEdge.SouthEast); |
|||
MinimizeButton.Click += delegate |
|||
{ this.WindowState = WindowState.Minimized; }; |
|||
MaximizeButton.Click += delegate |
|||
{ |
|||
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; |
|||
}; |
|||
this.Get<Button>("CloseButton").Click += delegate |
|||
CloseButton.Click += delegate |
|||
{ |
|||
Close(); |
|||
}; |
|||
} |
|||
|
|||
private void SetupSide(Control ctl, StandardCursorType cursor, WindowEdge edge) |
|||
{ |
|||
ctl.Cursor = new Cursor(cursor); |
|||
ctl.PointerPressed += (i, e) => |
|||
{ |
|||
if (WindowState == WindowState.Normal) |
|||
BeginResizeDrag(edge, e); |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class AcceleratorPage : UserControl |
|||
public partial class AcceleratorPage : UserControl |
|||
{ |
|||
public AcceleratorPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,19 +1,12 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class AcrylicPage : UserControl |
|||
public partial class AcrylicPage : UserControl |
|||
{ |
|||
public AcrylicPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class BorderPage : UserControl |
|||
public partial class BorderPage : UserControl |
|||
{ |
|||
public BorderPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,29 +1,21 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Interactivity; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ButtonsPage : UserControl |
|||
public partial class ButtonsPage : UserControl |
|||
{ |
|||
private int repeatButtonClickCount = 0; |
|||
|
|||
public ButtonsPage() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
this.Get<RepeatButton>("RepeatButton").Click += OnRepeatButtonClick; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
public void OnRepeatButtonClick(object? sender, object args) |
|||
public void OnRepeatButtonClick(object? sender, RoutedEventArgs args) |
|||
{ |
|||
repeatButtonClickCount++; |
|||
var textBlock = this.Get<TextBlock>("RepeatButtonTextBlock"); |
|||
textBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; |
|||
RepeatButtonTextBlock.Text = $"Repeat Button: {repeatButtonClickCount}"; |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,36 +1,23 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using System; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class CalendarDatePickerPage : UserControl |
|||
public partial class CalendarDatePickerPage : UserControl |
|||
{ |
|||
public CalendarDatePickerPage() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
var dp1 = this.Get<CalendarDatePicker>("DatePicker1"); |
|||
var dp2 = this.Get<CalendarDatePicker>("DatePicker2"); |
|||
var dp3 = this.Get<CalendarDatePicker>("DatePicker3"); |
|||
var dp4 = this.Get<CalendarDatePicker>("DatePicker4"); |
|||
var dp5 = this.Get<CalendarDatePicker>("DatePicker5"); |
|||
|
|||
dp1.SelectedDate = DateTime.Today; |
|||
dp2.SelectedDate = DateTime.Today.AddDays(10); |
|||
dp3.SelectedDate = DateTime.Today.AddDays(20); |
|||
dp5.SelectedDate = DateTime.Today; |
|||
DatePicker1.SelectedDate = DateTime.Today; |
|||
DatePicker2.SelectedDate = DateTime.Today.AddDays(10); |
|||
DatePicker3.SelectedDate = DateTime.Today.AddDays(20); |
|||
DatePicker5.SelectedDate = DateTime.Today; |
|||
|
|||
dp4.TemplateApplied += (s, e) => |
|||
DatePicker4.TemplateApplied += (s, e) => |
|||
{ |
|||
dp4.BlackoutDates?.AddDatesInPast(); |
|||
DatePicker4.BlackoutDates?.AddDatesInPast(); |
|||
}; |
|||
|
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,28 +1,20 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using System; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class CalendarPage : UserControl |
|||
public partial class CalendarPage : UserControl |
|||
{ |
|||
public CalendarPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
InitializeComponent(); |
|||
|
|||
var today = DateTime.Today; |
|||
var cal1 = this.Get<Calendar>("DisplayDatesCalendar"); |
|||
cal1.DisplayDateStart = today.AddDays(-25); |
|||
cal1.DisplayDateEnd = today.AddDays(25); |
|||
var today = DateTime.Today; |
|||
DisplayDatesCalendar.DisplayDateStart = today.AddDays(-25); |
|||
DisplayDatesCalendar.DisplayDateEnd = today.AddDays(25); |
|||
|
|||
var cal2 = this.Get<Calendar>("BlackoutDatesCalendar"); |
|||
cal2.BlackoutDates.AddDatesInPast(); |
|||
cal2.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
BlackoutDatesCalendar.BlackoutDates.AddDatesInPast(); |
|||
BlackoutDatesCalendar.BlackoutDates.Add(new CalendarDateRange(today.AddDays(6))); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class CanvasPage : UserControl |
|||
public partial class CanvasPage : UserControl |
|||
{ |
|||
public CanvasPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class CheckBoxPage : UserControl |
|||
public partial class CheckBoxPage : UserControl |
|||
{ |
|||
public CheckBoxPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,25 +1,17 @@ |
|||
using System.Linq; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Media; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ComboBoxPage : UserControl |
|||
public partial class ComboBoxPage : UserControl |
|||
{ |
|||
public ComboBoxPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
DataContext = new ComboBoxPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
var fontComboBox = this.Get<ComboBox>("fontComboBox"); |
|||
InitializeComponent(); |
|||
fontComboBox.ItemsSource = FontManager.Current.SystemFonts; |
|||
fontComboBox.SelectedIndex = 0; |
|||
DataContext = new ComboBoxPageViewModel(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ContainerQueryPage : UserControl |
|||
public partial class ContainerQueryPage : UserControl |
|||
{ |
|||
public ContainerQueryPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,20 +1,14 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class CursorPage : UserControl |
|||
public partial class CursorPage : UserControl |
|||
{ |
|||
public CursorPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
InitializeComponent(); |
|||
DataContext = new CursorPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,30 +1,23 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class DateTimePickerPage : UserControl |
|||
public partial class DateTimePickerPage : UserControl |
|||
{ |
|||
public DateTimePickerPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
this.Get<TextBlock>("DatePickerDesc").Text = "Use a DatePicker to let users set a date in your app, " + |
|||
InitializeComponent(); |
|||
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. " + |
|||
"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"; |
|||
|
|||
this.Get<TextBlock>("TimePickerDesc").Text = "Use a TimePicker to let users set a time in your app, for example " + |
|||
TimePickerDesc.Text = "Use a TimePicker to let users set a time in your app, for example " + |
|||
"to set a reminder. The TimePicker displays four controls for hour, minute, seconds(optional), 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. " + |
|||
"12 - hour or 24 - hour clock and visibility of AM / PM is dynamically set based on user time settings, or can be overridden."; |
|||
|
|||
|
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,26 +1,17 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ExpanderPage : UserControl |
|||
public partial class ExpanderPage : UserControl |
|||
{ |
|||
public ExpanderPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
InitializeComponent(); |
|||
DataContext = new ExpanderPageViewModel(); |
|||
|
|||
var CollapsingDisabledExpander = this.Get<Expander>("CollapsingDisabledExpander"); |
|||
var ExpandingDisabledExpander = this.Get<Expander>("ExpandingDisabledExpander"); |
|||
|
|||
CollapsingDisabledExpander.Collapsing += (s, e) => { e.Cancel = true; }; |
|||
ExpandingDisabledExpander.Expanding += (s, e) => { e.Cancel = true; }; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class LayoutTransformControlPage : UserControl |
|||
public partial class LayoutTransformControlPage : UserControl |
|||
{ |
|||
public LayoutTransformControlPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,20 +1,14 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ListBoxPage : UserControl |
|||
public partial class ListBoxPage : UserControl |
|||
{ |
|||
public ListBoxPage() |
|||
{ |
|||
InitializeComponent(); |
|||
DataContext = new ListBoxPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,37 +1,28 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using System.Windows.Input; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class MenuPage : UserControl |
|||
public partial class MenuPage : UserControl |
|||
{ |
|||
public MenuPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
InitializeComponent(); |
|||
DataContext = new MenuPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
|
|||
private MenuPageViewModel? _model; |
|||
protected override void OnDataContextChanged(EventArgs e) |
|||
{ |
|||
if (_model != null) |
|||
_model.View = null; |
|||
_model = DataContext as MenuPageViewModel; |
|||
_model = DataContext as MenuPageViewModel; |
|||
if (_model != null) |
|||
_model.View = this; |
|||
|
|||
base.OnDataContextChanged(e); |
|||
} |
|||
|
|||
|
|||
} |
|||
} |
|||
|
|||
@ -1,23 +1,14 @@ |
|||
using System; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Markup.Xaml.MarkupExtensions; |
|||
using Avalonia.Media.Immutable; |
|||
using Avalonia.Controls; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class PlatformInfoPage : UserControl |
|||
public partial class PlatformInfoPage : UserControl |
|||
{ |
|||
public PlatformInfoPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
InitializeComponent(); |
|||
DataContext = new PlatformInformationViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ProgressBarPage : UserControl |
|||
public partial class ProgressBarPage : UserControl |
|||
{ |
|||
public ProgressBarPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class RadioButtonPage : UserControl |
|||
public partial class RadioButtonPage : UserControl |
|||
{ |
|||
public RadioButtonPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class SliderPage : UserControl |
|||
public partial class SliderPage : UserControl |
|||
{ |
|||
public SliderPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,21 +1,14 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Controls; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class SplitViewPage : UserControl |
|||
public partial class SplitViewPage : UserControl |
|||
{ |
|||
public SplitViewPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
InitializeComponent(); |
|||
DataContext = new SplitViewPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class TextBlockPage : UserControl |
|||
public partial class TextBlockPage : UserControl |
|||
{ |
|||
public TextBlockPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class TextBoxPage : UserControl |
|||
public partial class TextBoxPage : UserControl |
|||
{ |
|||
public TextBoxPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,19 +1,12 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ToggleSwitchPage : UserControl |
|||
public partial class ToggleSwitchPage : UserControl |
|||
{ |
|||
public ToggleSwitchPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,20 +1,14 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class TreeViewPage : UserControl |
|||
public partial class TreeViewPage : UserControl |
|||
{ |
|||
public TreeViewPage() |
|||
{ |
|||
InitializeComponent(); |
|||
DataContext = new TreeViewPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ViewboxPage : UserControl |
|||
public partial class ViewboxPage : UserControl |
|||
{ |
|||
public ViewboxPage() |
|||
{ |
|||
InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,19 +1,12 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using Avalonia.Controls; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class WindowCustomizationsPage : UserControl |
|||
public partial class WindowCustomizationsPage : UserControl |
|||
{ |
|||
public WindowCustomizationsPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,18 +1,12 @@ |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
|
|||
namespace ControlCatalog.Views |
|||
{ |
|||
public class CustomNotificationView : UserControl |
|||
public partial class CustomNotificationView : UserControl |
|||
{ |
|||
public CustomNotificationView() |
|||
{ |
|||
this.InitializeComponent(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
InitializeComponent(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,12 +1,19 @@ |
|||
using System; |
|||
using Avalonia.Media; |
|||
using Avalonia.Media.Immutable; |
|||
using Avalonia.Rendering.Composition.Server; |
|||
using Avalonia.Rendering.Composition.Transport; |
|||
|
|||
namespace Avalonia.Rendering.Composition.Server; |
|||
|
|||
internal partial class ServerCompositionSimplePen : IPen |
|||
{ |
|||
IDashStyle? IPen.DashStyle => DashStyle; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Dispose() |
|||
{ |
|||
// Remove the pen from the brush observers.
|
|||
// Without this, the pen was being retained in memory by long lived brush resources (e.g. those defined in
|
|||
// the theme or app resources), hence was causing memory leaks; see Issue #16451
|
|||
RemoveObserversFromProperty(ref _brush); |
|||
_brush = null; |
|||
base.Dispose(); |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,47 @@ |
|||
using System; |
|||
|
|||
namespace Avalonia.Headless; |
|||
|
|||
/// <summary>
|
|||
/// Defines the isolation level for headless unit tests,
|
|||
/// controlling how <see cref="Avalonia.Application"/> and its
|
|||
/// associated <see cref="Avalonia.Threading.Dispatcher"/> are managed
|
|||
/// between test runs.
|
|||
/// </summary>
|
|||
public enum AvaloniaTestIsolationLevel |
|||
{ |
|||
/// <summary>
|
|||
/// Reuses a single <see cref="Avalonia.Application"/> and <see cref="Avalonia.Threading.Dispatcher"/>
|
|||
/// instance across all tests within the assembly.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// Tests must not rely on any global or persistent state that could leak between runs.
|
|||
/// Headless framework won't dispose any resources after tests when using this mode.
|
|||
/// </remarks>
|
|||
PerAssembly, |
|||
|
|||
/// <summary>
|
|||
/// Recreates the <see cref="Avalonia.Application"/> and <see cref="Avalonia.Threading.Dispatcher"/>
|
|||
/// for each individual test method.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This mode ensures complete test isolation, and should be used for tests that modify global
|
|||
/// application state or rely on a clean dispatcher environment.
|
|||
/// This is the default isolation level if none is specified.
|
|||
/// </remarks>
|
|||
PerTest |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Specifies how headless unit tests should be isolated from each other,
|
|||
/// defining when the test runtime should recreate the
|
|||
/// <see cref="Avalonia.Application"/> and <see cref="Avalonia.Threading.Dispatcher"/> instances.
|
|||
/// </summary>
|
|||
[AttributeUsage(AttributeTargets.Assembly)] |
|||
public sealed class AvaloniaTestIsolationAttribute(AvaloniaTestIsolationLevel isolationLevel) : Attribute |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the isolation level for headless tests.
|
|||
/// </summary>
|
|||
public AvaloniaTestIsolationLevel IsolationLevel { get; } = isolationLevel; |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
global using NUnit.Framework; |
|||
global using Avalonia.Headless.NUnit; |
|||
|
|||
using Avalonia.Headless; |
|||
using Avalonia.Headless.UnitTests; |
|||
|
|||
[assembly: AvaloniaTestApplication(typeof(TestApplication))] |
|||
[assembly: AvaloniaTestIsolation(AvaloniaTestIsolationLevel.PerAssembly)] |
|||
@ -0,0 +1,31 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk"> |
|||
<PropertyGroup> |
|||
<TargetFramework>$(AvsCurrentTargetFramework)</TargetFramework> |
|||
<IsTestProject>true</IsTestProject> |
|||
<DefineConstants>$(DefineConstants);NUNIT</DefineConstants> |
|||
</PropertyGroup> |
|||
|
|||
<Import Project="..\..\build\UnitTests.NetCore.targets" /> |
|||
<Import Project="..\..\build\UnitTests.NetFX.props" /> |
|||
<Import Project="..\..\build\Moq.props" /> |
|||
<Import Project="..\..\build\Rx.props" /> |
|||
<Import Project="..\..\build\SharedVersion.props" /> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="NUnit" Version="3.13.3" /> |
|||
<PackageReference Include="NUnit3TestAdapter" Version="4.4.2" /> |
|||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<Compile Include="..\Avalonia.Headless.UnitTests\**\*.cs" /> |
|||
<Compile Remove="..\Avalonia.Headless.UnitTests\bin\**\*.cs" /> |
|||
<Compile Remove="..\Avalonia.Headless.UnitTests\obj\**\*.cs" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\src\Avalonia.Themes.Simple\Avalonia.Themes.Simple.csproj" /> |
|||
<ProjectReference Include="..\..\src\Headless\Avalonia.Headless.NUnit\Avalonia.Headless.NUnit.csproj" /> |
|||
<ProjectReference Include="..\..\src\Skia\Avalonia.Skia\Avalonia.Skia.csproj" /> |
|||
</ItemGroup> |
|||
</Project> |
|||
@ -0,0 +1,63 @@ |
|||
using System; |
|||
using System.Reflection; |
|||
using Avalonia.Threading; |
|||
|
|||
namespace Avalonia.Headless.UnitTests; |
|||
|
|||
public class IsolationTests |
|||
{ |
|||
private static WeakReference<Application> s_previousAppRef; |
|||
private static WeakReference<Dispatcher> s_previousDispatcherRef; |
|||
|
|||
#if NUNIT
|
|||
[AvaloniaTheory, Timeout(10000)] |
|||
[TestCase(1), TestCase(2), TestCase(3)] |
|||
#elif XUNIT
|
|||
[AvaloniaTheory] |
|||
[InlineData(1), InlineData(2), InlineData(3)] |
|||
#endif
|
|||
public void Application_Instance_Should_Match_Isolation_Level(int runIndex) |
|||
{ |
|||
var currentApp = Application.Current; |
|||
var currentDispatcher = Dispatcher.UIThread; |
|||
|
|||
if (s_previousAppRef is not null && s_previousDispatcherRef is not null) |
|||
{ |
|||
var isolationLevel = |
|||
GetType().Assembly.GetCustomAttribute<AvaloniaTestIsolationAttribute>()?.IsolationLevel ?? |
|||
AvaloniaTestIsolationLevel.PerTest; |
|||
|
|||
if (isolationLevel == AvaloniaTestIsolationLevel.PerTest) |
|||
{ |
|||
GC.Collect(); |
|||
GC.WaitForPendingFinalizers(); |
|||
GC.Collect(); |
|||
|
|||
Assert.False(s_previousAppRef.TryGetTarget(out var previousApp), |
|||
"Previous Application instance should have been collected."); |
|||
Assert.False(s_previousDispatcherRef.TryGetTarget(out var previousDispatcher), |
|||
"Previous Dispatcher instance should have been collected."); |
|||
|
|||
Assert.False(previousApp == currentApp); |
|||
Assert.False(previousDispatcher == currentDispatcher); |
|||
} |
|||
else if (isolationLevel == AvaloniaTestIsolationLevel.PerAssembly) |
|||
{ |
|||
Assert.True(s_previousAppRef.TryGetTarget(out var previousApp), |
|||
"Previous Application instance should still be alive."); |
|||
Assert.True(s_previousDispatcherRef.TryGetTarget(out var previousDispatcher), |
|||
"Previous Dispatcher instance should still be alive."); |
|||
|
|||
Assert.True(previousApp == currentApp); |
|||
Assert.True(previousDispatcher == currentDispatcher); |
|||
} |
|||
else |
|||
{ |
|||
throw new InvalidOperationException($"Unknown isolation level: {isolationLevel}"); |
|||
} |
|||
} |
|||
|
|||
s_previousAppRef = new WeakReference<Application>(currentApp); |
|||
s_previousDispatcherRef = new WeakReference<Dispatcher>(currentDispatcher); |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue