Browse Source
* Refactor IntegrationTestApp. Use a `ListBox` to switch pages instead of a `TabControl`: the `TabControl` didn't adapt well to smaller screen sizes, and the `MainWindow` was getting unwieldy anyway. * Update tests to use new pager. Move logic for selecting the page to a base class as we may need to handle scrolling manually on macOS at some point (Appium on macOS doesn't scroll elements into view automatically). * Add AutomationPeer.IsOffscreen. This is needed in order for controls to be scrolled into view using WinAppDriver. The default is the same as WPF and the default value is overridden in the same controls as WPF (where present). #Conflicts: # samples/IntegrationTestApp/App.axaml.cs # samples/IntegrationTestApp/MainWindow.axaml # samples/IntegrationTestApp/MainWindow.axaml.cs # samples/IntegrationTestApp/TopmostWindowTest.axaml.cs # src/Avalonia.Controls/TreeViewItem.cs # tests/Avalonia.IntegrationTests.Appium/ContextMenuTests.cs # tests/Avalonia.IntegrationTests.Appium/PointerTests.cs # tests/Avalonia.IntegrationTests.Appium/ScreenTests.cs # tests/Avalonia.IntegrationTests.Appium/TrayIconTests.cs # tests/Avalonia.IntegrationTests.Appium/WindowDecorationsTests.cs # tests/Avalonia.IntegrationTests.Appium/WindowTests.cs # tests/Avalonia.IntegrationTests.Appium/WindowTests_MacOS.csrelease/11.1.3
committed by
Max Katz
66 changed files with 1292 additions and 782 deletions
@ -0,0 +1,6 @@ |
|||||
|
using System; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Models; |
||||
|
|
||||
|
internal record Page(string Name, Func<Control> CreateContent); |
||||
@ -0,0 +1,17 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.AutomationPage"> |
||||
|
<StackPanel> |
||||
|
<TextBlock Name="TextBlockWithName">TextBlockWithName</TextBlock> |
||||
|
<TextBlock Name="NotTheAutomationId" AutomationProperties.AutomationId="TextBlockWithNameAndAutomationId"> |
||||
|
TextBlockWithNameAndAutomationId |
||||
|
</TextBlock> |
||||
|
<TextBlock Name="TextBlockAsLabel">Label for TextBox</TextBlock> |
||||
|
<TextBox Name="LabeledByTextBox" AutomationProperties.LabeledBy="{Binding #TextBlockAsLabel}"> |
||||
|
Foo |
||||
|
</TextBox> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class AutomationPage : UserControl |
||||
|
{ |
||||
|
public AutomationPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.ButtonPage"> |
||||
|
<StackPanel> |
||||
|
<Button Name="DisabledButton" IsEnabled="False"> |
||||
|
Disabled Button |
||||
|
</Button> |
||||
|
<Button Name="EffectivelyDisabledButton" Command="{ReflectionBinding DoesntExist}"> |
||||
|
Effectively Disabled Button |
||||
|
</Button> |
||||
|
<Button Name="BasicButton"> |
||||
|
Basic Button |
||||
|
</Button> |
||||
|
<Button Name="ButtonWithTextBlock"> |
||||
|
<TextBlock>Button with TextBlock</TextBlock> |
||||
|
</Button> |
||||
|
<Button Name="ButtonWithAcceleratorKey" HotKey="Ctrl+B">Button with Accelerator Key</Button> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class ButtonPage : UserControl |
||||
|
{ |
||||
|
public ButtonPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,12 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.CheckBoxPage"> |
||||
|
<StackPanel> |
||||
|
<CheckBox Name="UncheckedCheckBox">Unchecked</CheckBox> |
||||
|
<CheckBox Name="CheckedCheckBox" IsChecked="True">Checked</CheckBox> |
||||
|
<CheckBox Name="ThreeStateCheckBox" IsThreeState="True" IsChecked="{x:Null}">ThreeState</CheckBox> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class CheckBoxPage : UserControl |
||||
|
{ |
||||
|
public CheckBoxPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.ComboBoxPage"> |
||||
|
<StackPanel> |
||||
|
<ComboBox Name="BasicComboBox"> |
||||
|
<ComboBoxItem>Item 0</ComboBoxItem> |
||||
|
<ComboBoxItem>Item 1</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
<CheckBox Name="ComboBoxWrapSelection" IsChecked="{Binding #BasicComboBox.WrapSelection}">Wrap Selection</CheckBox> |
||||
|
<Button Name="ComboBoxSelectionClear" Click="ComboBoxSelectionClear_Click">Clear Selection</Button> |
||||
|
<Button Name="ComboBoxSelectFirst" Click="ComboBoxSelectFirst_Click">Select First</Button> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,22 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class ComboBoxPage : UserControl |
||||
|
{ |
||||
|
public ComboBoxPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void ComboBoxSelectionClear_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
BasicComboBox.SelectedIndex = -1; |
||||
|
} |
||||
|
|
||||
|
private void ComboBoxSelectFirst_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
BasicComboBox.SelectedIndex = 0; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.ContextMenuPage"> |
||||
|
<StackPanel> |
||||
|
<Button Name="ShowContextMenu" Content="Right-click to show context menu."> |
||||
|
<Button.ContextMenu> |
||||
|
<ContextMenu> |
||||
|
<MenuItem Name="ContextMenuItem1" Header="Item 1"/> |
||||
|
<MenuItem Name="ContextMenuItem2" Header="Item 2"/> |
||||
|
</ContextMenu> |
||||
|
</Button.ContextMenu> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class ContextMenuPage : UserControl |
||||
|
{ |
||||
|
public ContextMenuPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.DesktopPage"> |
||||
|
<StackPanel> |
||||
|
<CheckBox x:FieldModifier="public" Name="TrayIconClicked">Tray Icon Clicked</CheckBox> |
||||
|
<CheckBox x:FieldModifier="public" Name="TrayIconMenuClicked">Tray Icon Menu Clicked</CheckBox> |
||||
|
<Button Name="ToggleTrayIconVisible" |
||||
|
Content="Toggle TrayIcon Visible" |
||||
|
Click="ToggleTrayIconVisible_Click"/> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,19 @@ |
|||||
|
using System.Linq; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class DesktopPage : UserControl |
||||
|
{ |
||||
|
public DesktopPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void ToggleTrayIconVisible_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) |
||||
|
{ |
||||
|
var icon = TrayIcon.GetIcons(Application.Current!)!.FirstOrDefault()!; |
||||
|
icon.IsVisible = !icon.IsVisible; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.GesturesPage"> |
||||
|
<DockPanel> |
||||
|
<DockPanel DockPanel.Dock="Top"> |
||||
|
<Button Name="ResetGestures" |
||||
|
DockPanel.Dock="Right" |
||||
|
Click="ResetGestures_Click"> |
||||
|
Reset |
||||
|
</Button> |
||||
|
<TextBlock Name="LastGesture" /> |
||||
|
</DockPanel> |
||||
|
<Panel> |
||||
|
<Border Name="GestureBorder" Background="Blue" |
||||
|
AutomationProperties.AccessibilityView="Content" |
||||
|
AutomationProperties.ControlTypeOverride="Image" |
||||
|
Tapped="GestureBorder_Tapped" |
||||
|
DoubleTapped="GestureBorder_DoubleTapped" |
||||
|
Gestures.RightTapped="GestureBorder_RightTapped"/> |
||||
|
<Border Name="GestureBorder2" Background="Green" IsVisible="False" |
||||
|
AutomationProperties.AccessibilityView="Content" |
||||
|
AutomationProperties.ControlTypeOverride="Image" |
||||
|
DoubleTapped="GestureBorder2_DoubleTapped"/> |
||||
|
</Panel> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,44 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class GesturesPage : UserControl |
||||
|
{ |
||||
|
public GesturesPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void GestureBorder_Tapped(object? sender, TappedEventArgs e) |
||||
|
{ |
||||
|
LastGesture.Text = "Tapped"; |
||||
|
} |
||||
|
|
||||
|
private void GestureBorder_DoubleTapped(object? sender, TappedEventArgs e) |
||||
|
{ |
||||
|
LastGesture.Text = "DoubleTapped"; |
||||
|
|
||||
|
// Testing #8733
|
||||
|
GestureBorder.IsVisible = false; |
||||
|
GestureBorder2.IsVisible = true; |
||||
|
} |
||||
|
|
||||
|
private void GestureBorder_RightTapped(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
LastGesture.Text = "RightTapped"; |
||||
|
} |
||||
|
|
||||
|
private void GestureBorder2_DoubleTapped(object? sender, TappedEventArgs e) |
||||
|
{ |
||||
|
LastGesture.Text = "DoubleTapped2"; |
||||
|
} |
||||
|
|
||||
|
private void ResetGestures_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
LastGesture.Text = string.Empty; |
||||
|
GestureBorder.IsVisible = true; |
||||
|
GestureBorder2.IsVisible = false; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:pages="using:IntegrationTestApp.Pages" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.ListBoxPage" |
||||
|
x:DataType="pages:ListBoxPage"> |
||||
|
<DockPanel> |
||||
|
<StackPanel DockPanel.Dock="Bottom"> |
||||
|
<Button Name="ListBoxSelectionClear" Click="ListBoxSelectionClear_Click">Clear Selection</Button> |
||||
|
</StackPanel> |
||||
|
<ListBox Name="BasicListBox" ItemsSource="{Binding ListBoxItems}" SelectionMode="Multiple"/> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class ListBoxPage : UserControl |
||||
|
{ |
||||
|
public ListBoxPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
ListBoxItems = Enumerable.Range(0, 100).Select(x => "Item " + x).ToList(); |
||||
|
DataContext = this; |
||||
|
} |
||||
|
|
||||
|
public List<string> ListBoxItems { get; } |
||||
|
|
||||
|
private void ListBoxSelectionClear_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
BasicListBox.SelectedIndex = -1; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.MenuPage"> |
||||
|
<DockPanel> |
||||
|
<Menu DockPanel.Dock="Top"> |
||||
|
<MenuItem Name="RootMenuItem" Header="_Root"> |
||||
|
<MenuItem Name="Child1MenuItem" Header="_Child 1" InputGesture="Ctrl+O" Click="MenuClicked"/> |
||||
|
<MenuItem Name="Child2MenuItem" Header="C_hild 2"> |
||||
|
<MenuItem Name="GrandchildMenuItem" Header="_Grandchild" Click="MenuClicked"/> |
||||
|
</MenuItem> |
||||
|
</MenuItem> |
||||
|
</Menu> |
||||
|
<StackPanel> |
||||
|
<TextBlock Name="ClickedMenuItem">None</TextBlock> |
||||
|
<Button Name="MenuClickedMenuItemReset" Click="MenuClickedMenuItemReset_Click">Reset</Button> |
||||
|
<TextBox Name="MenuFocusTest"/> |
||||
|
</StackPanel> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,24 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class MenuPage : UserControl |
||||
|
{ |
||||
|
public MenuPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void MenuClicked(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var clickedMenuItemTextBlock = ClickedMenuItem; |
||||
|
clickedMenuItemTextBlock.Text = (sender as MenuItem)?.Header?.ToString(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
private void MenuClickedMenuItemReset_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
ClickedMenuItem.Text = "None"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.PointerPage"> |
||||
|
<StackPanel> |
||||
|
<!-- Trigger with PointerPressed rather using a Button so we have access to the pointer. --> |
||||
|
<Border Name="PointerPageShowDialog" |
||||
|
Background="{DynamicResource ButtonBackground}" |
||||
|
HorizontalAlignment="Left" |
||||
|
Padding="{DynamicResource ButtonPadding}" |
||||
|
AutomationProperties.AccessibilityView="Control" |
||||
|
PointerPressed="PointerPageShowDialog_PointerPressed"> |
||||
|
<TextBlock>Show Dialog</TextBlock> |
||||
|
</Border> |
||||
|
<TextBlock Name="PointerCaptureStatus"/> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,47 @@ |
|||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class PointerPage : UserControl |
||||
|
{ |
||||
|
public PointerPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void PointerPageShowDialog_PointerPressed(object? sender, PointerPressedEventArgs e) |
||||
|
{ |
||||
|
void CaptureLost(object? sender, PointerCaptureLostEventArgs e) |
||||
|
{ |
||||
|
PointerCaptureStatus.Text = "None"; |
||||
|
((Control)sender!).PointerCaptureLost -= CaptureLost; |
||||
|
} |
||||
|
|
||||
|
var window = TopLevel.GetTopLevel(this) as Window ?? |
||||
|
throw new AvaloniaInternalException("PointerPage is not attached to a Window."); |
||||
|
var captured = e.Pointer.Captured as Control; |
||||
|
|
||||
|
if (captured is not null) |
||||
|
{ |
||||
|
captured.PointerCaptureLost += CaptureLost; |
||||
|
} |
||||
|
|
||||
|
PointerCaptureStatus.Text = captured?.ToString() ?? "None"; |
||||
|
|
||||
|
var dialog = new Window |
||||
|
{ |
||||
|
Width = 200, |
||||
|
Height = 200, |
||||
|
}; |
||||
|
|
||||
|
dialog.Content = new Button |
||||
|
{ |
||||
|
Content = "Close", |
||||
|
Command = new DelegateCommand(() => dialog.Close()), |
||||
|
}; |
||||
|
|
||||
|
dialog.ShowDialog(window); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.RadioButtonPage"> |
||||
|
<StackPanel Orientation="Vertical"> |
||||
|
<RadioButton Name="BasicRadioButton">Sample RadioButton</RadioButton> |
||||
|
<StackPanel Orientation="Vertical"> |
||||
|
<RadioButton Name="ThreeStatesRadioButton1" IsChecked="True" IsThreeState="True">Three States: Option 1</RadioButton> |
||||
|
<RadioButton Name="ThreeStatesRadioButton2" IsChecked="False" IsThreeState="True">Three States: Option 2</RadioButton> |
||||
|
</StackPanel> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class RadioButtonPage : UserControl |
||||
|
{ |
||||
|
public RadioButtonPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.ScreensPage"> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<Button Name="ScreenRefresh" |
||||
|
Content="Refresh" |
||||
|
Click="ScreenRefresh_Click"/> |
||||
|
<TextBox Name="ScreenName" Watermark="DisplayName" UseFloatingWatermark="true" /> |
||||
|
<TextBox Name="ScreenHandle" Watermark="Handle" UseFloatingWatermark="true" /> |
||||
|
<TextBox Name="ScreenScaling" Watermark="Scaling" UseFloatingWatermark="true" /> |
||||
|
<TextBox Name="ScreenBounds" Watermark="Bounds" UseFloatingWatermark="true" /> |
||||
|
<TextBox Name="ScreenWorkArea" Watermark="WorkArea" UseFloatingWatermark="true" /> |
||||
|
<TextBox Name="ScreenOrientation" Watermark="Orientation" UseFloatingWatermark="true" /> |
||||
|
<TextBox Name="ScreenSameReference" Watermark="Is same reference" UseFloatingWatermark="true" /> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System.Globalization; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class ScreensPage : UserControl |
||||
|
{ |
||||
|
private Screen? _lastScreen; |
||||
|
|
||||
|
public ScreensPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void ScreenRefresh_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var window = TopLevel.GetTopLevel(this) as Window ?? |
||||
|
throw new AvaloniaInternalException("ScreensPage is not attached to a Window."); |
||||
|
var lastScreen = _lastScreen; |
||||
|
var screen = _lastScreen = window.Screens.ScreenFromWindow(window); |
||||
|
ScreenName.Text = screen?.DisplayName; |
||||
|
ScreenHandle.Text = screen?.TryGetPlatformHandle()?.ToString(); |
||||
|
ScreenBounds.Text = screen?.Bounds.ToString(); |
||||
|
ScreenWorkArea.Text = screen?.WorkingArea.ToString(); |
||||
|
ScreenScaling.Text = screen?.Scaling.ToString(CultureInfo.InvariantCulture); |
||||
|
ScreenOrientation.Text = screen?.CurrentOrientation.ToString(); |
||||
|
ScreenSameReference.Text = ReferenceEquals(lastScreen, screen).ToString(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.ScrollBarPage"> |
||||
|
<ScrollBar Name="MyScrollBar" Orientation="Horizontal" AllowAutoHide="False" Width="200" Height="30" Value="20"/> |
||||
|
</UserControl> |
||||
@ -0,0 +1,11 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class ScrollBarPage : UserControl |
||||
|
{ |
||||
|
public ScrollBarPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.SliderPage"> |
||||
|
<DockPanel> |
||||
|
<DockPanel DockPanel.Dock="Top"> |
||||
|
<TextBox Name="HorizontalSliderValue" |
||||
|
DockPanel.Dock="Right" |
||||
|
Text="{Binding #HorizontalSlider.Value, Mode=OneWay, StringFormat=\{0:0\}}" |
||||
|
VerticalAlignment="Top"/> |
||||
|
<Slider Name="HorizontalSlider" Value="50"/> |
||||
|
</DockPanel> |
||||
|
<Button Name="ResetSliders" Click="ResetSliders_Click">Reset</Button> |
||||
|
</DockPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,17 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class SliderPage : UserControl |
||||
|
{ |
||||
|
public SliderPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void ResetSliders_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
HorizontalSlider.Value = 50; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,21 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.WindowDecorationsPage"> |
||||
|
<StackPanel Spacing="4"> |
||||
|
<CheckBox Name="WindowExtendClientAreaToDecorationsHint" Content="Extend Client Area to Decorations" /> |
||||
|
<CheckBox Name="WindowForceSystemChrome" Content="Force SystemChrome" /> |
||||
|
<CheckBox Name="WindowPreferSystemChrome" Content="Prefer SystemChrome" /> |
||||
|
<CheckBox Name="WindowMacThickSystemChrome" Content="Mac Thick SystemChrome" /> |
||||
|
<TextBox Name="WindowTitleBarHeightHint" Text="-1" Watermark="In dips" /> |
||||
|
<Button Name="ApplyWindowDecorations" |
||||
|
Content="Apply decorations on this Window" |
||||
|
Click="ApplyWindowDecorations_Click"/> |
||||
|
<Button Name="ShowNewWindowDecorations" |
||||
|
Content="Show new Window with decorations" |
||||
|
Click="ShowNewWindowDecorations_Click"/> |
||||
|
<TextBox Name="WindowDecorationProperties" AcceptsReturn="True" /> |
||||
|
</StackPanel> |
||||
|
</UserControl> |
||||
@ -0,0 +1,63 @@ |
|||||
|
using Avalonia; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Media; |
||||
|
using Avalonia.Platform; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class WindowDecorationsPage : UserControl |
||||
|
{ |
||||
|
public WindowDecorationsPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private void SetWindowDecorations(Window window) |
||||
|
{ |
||||
|
window.ExtendClientAreaToDecorationsHint = WindowExtendClientAreaToDecorationsHint.IsChecked!.Value; |
||||
|
window.ExtendClientAreaTitleBarHeightHint = |
||||
|
int.TryParse(WindowTitleBarHeightHint.Text, out var val) ? val / window.DesktopScaling : -1; |
||||
|
window.ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.NoChrome |
||||
|
| (WindowForceSystemChrome.IsChecked == true ? ExtendClientAreaChromeHints.SystemChrome : 0) |
||||
|
| (WindowPreferSystemChrome.IsChecked == true ? ExtendClientAreaChromeHints.PreferSystemChrome : 0) |
||||
|
| (WindowMacThickSystemChrome.IsChecked == true ? ExtendClientAreaChromeHints.OSXThickTitleBar : 0); |
||||
|
AdjustOffsets(window); |
||||
|
|
||||
|
window.Background = Brushes.Transparent; |
||||
|
window.PropertyChanged += WindowOnPropertyChanged; |
||||
|
|
||||
|
void WindowOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
var window = (Window)sender!; |
||||
|
if (e.Property == Window.OffScreenMarginProperty || e.Property == Window.WindowDecorationMarginProperty) |
||||
|
{ |
||||
|
AdjustOffsets(window); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void AdjustOffsets(Window window) |
||||
|
{ |
||||
|
var scaling = window.DesktopScaling; |
||||
|
|
||||
|
window.Padding = window.OffScreenMargin; |
||||
|
((Control)window.Content!).Margin = window.WindowDecorationMargin; |
||||
|
|
||||
|
WindowDecorationProperties.Text = |
||||
|
$"{window.OffScreenMargin.Top * scaling} {window.WindowDecorationMargin.Top * scaling} {window.IsExtendedIntoWindowDecorations}"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ApplyWindowDecorations_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) |
||||
|
{ |
||||
|
var window = TopLevel.GetTopLevel(this) as Window ?? |
||||
|
throw new AvaloniaInternalException("WindowDecorationsPage is not attached to a Window."); |
||||
|
SetWindowDecorations(window); |
||||
|
} |
||||
|
|
||||
|
private void ShowNewWindowDecorations_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e) |
||||
|
{ |
||||
|
var window = new ShowWindowTest(); |
||||
|
SetWindowDecorations(window); |
||||
|
window.Show(); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
||||
|
x:Class="IntegrationTestApp.Pages.WindowPage"> |
||||
|
<Grid ColumnDefinitions="*,8,*"> |
||||
|
<StackPanel Grid.Column="0"> |
||||
|
<TextBox Name="ShowWindowSize" Watermark="Window Size"/> |
||||
|
<ComboBox Name="ShowWindowMode" SelectedIndex="0"> |
||||
|
<ComboBoxItem>NonOwned</ComboBoxItem> |
||||
|
<ComboBoxItem>Owned</ComboBoxItem> |
||||
|
<ComboBoxItem>Modal</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
<ComboBox Name="ShowWindowLocation" SelectedIndex="0"> |
||||
|
<ComboBoxItem>Manual</ComboBoxItem> |
||||
|
<ComboBoxItem>CenterScreen</ComboBoxItem> |
||||
|
<ComboBoxItem>CenterOwner</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
<ComboBox Name="ShowWindowState" SelectedIndex="0"> |
||||
|
<ComboBoxItem Name="ShowWindowStateNormal">Normal</ComboBoxItem> |
||||
|
<ComboBoxItem Name="ShowWindowStateMinimized">Minimized</ComboBoxItem> |
||||
|
<ComboBoxItem Name="ShowWindowStateMaximized">Maximized</ComboBoxItem> |
||||
|
<ComboBoxItem Name="ShowWindowStateFullScreen">FullScreen</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
<ComboBox Name="ShowWindowSystemDecorations" SelectedIndex="2"> |
||||
|
<ComboBoxItem Name="ShowWindowSystemDecorationsNone">None</ComboBoxItem> |
||||
|
<ComboBoxItem Name="ShowWindowSystemDecorationsBorderOnly">BorderOnly</ComboBoxItem> |
||||
|
<ComboBoxItem Name="ShowWindowSystemDecorationsFull">Full</ComboBoxItem> |
||||
|
</ComboBox> |
||||
|
<CheckBox Name="ShowWindowExtendClientAreaToDecorationsHint">ExtendClientAreaToDecorationsHint</CheckBox> |
||||
|
<CheckBox Name="ShowWindowCanResize" IsChecked="True">Can Resize</CheckBox> |
||||
|
<Button Name="ShowWindow" Click="ShowWindow_Click">Show Window</Button> |
||||
|
<Button Name="SendToBack" Click="SendToBack_Click">Send to Back</Button> |
||||
|
<Button Name="EnterFullscreen" Click="EnterFullscreen_Click">Enter Fullscreen</Button> |
||||
|
<Button Name="ExitFullscreen" Click="ExitFullscreen_Click">Exit Fullscreen</Button> |
||||
|
<Button Name="RestoreAll" Click="RestoreAll_Click">Restore All</Button> |
||||
|
<Button Name="ShowTopmostWindow" Click="ShowTopmostWindow_Click">Show Topmost Window</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Column="2"> |
||||
|
<Button Name="ShowTransparentWindow" Click="ShowTransparentWindow_Click">Transparent Window</Button> |
||||
|
<Button Name="ShowTransparentPopup" Click="ShowTransparentPopup_Click">Transparent Popup</Button> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</UserControl> |
||||
@ -0,0 +1,199 @@ |
|||||
|
using System.Linq; |
||||
|
using Avalonia; |
||||
|
using Avalonia.Automation; |
||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Controls.ApplicationLifetimes; |
||||
|
using Avalonia.Controls.Primitives; |
||||
|
using Avalonia.Controls.Primitives.PopupPositioning; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Media; |
||||
|
|
||||
|
namespace IntegrationTestApp.Pages; |
||||
|
|
||||
|
public partial class WindowPage : UserControl |
||||
|
{ |
||||
|
public WindowPage() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
} |
||||
|
|
||||
|
private Window Window => TopLevel.GetTopLevel(this) as Window ?? |
||||
|
throw new AvaloniaInternalException("WindowPage is not attached to a Window."); |
||||
|
|
||||
|
private void ShowWindow_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var size = !string.IsNullOrWhiteSpace(ShowWindowSize.Text) ? Size.Parse(ShowWindowSize.Text) : (Size?)null; |
||||
|
var window = new ShowWindowTest |
||||
|
{ |
||||
|
WindowStartupLocation = (WindowStartupLocation)ShowWindowLocation.SelectedIndex, |
||||
|
CanResize = ShowWindowCanResize.IsChecked ?? false, |
||||
|
}; |
||||
|
|
||||
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime lifetime) |
||||
|
{ |
||||
|
// Make sure the windows have unique names and AutomationIds.
|
||||
|
var existing = lifetime.Windows.OfType<ShowWindowTest>().Count(); |
||||
|
if (existing > 0) |
||||
|
{ |
||||
|
AutomationProperties.SetAutomationId(window, window.Name + (existing + 1)); |
||||
|
window.Title += $" {existing + 1}"; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (size.HasValue) |
||||
|
{ |
||||
|
window.Width = size.Value.Width; |
||||
|
window.Height = size.Value.Height; |
||||
|
} |
||||
|
|
||||
|
ShowWindowSize.Text = string.Empty; |
||||
|
window.ExtendClientAreaToDecorationsHint = ShowWindowExtendClientAreaToDecorationsHint.IsChecked ?? false; |
||||
|
window.SystemDecorations = (SystemDecorations)ShowWindowSystemDecorations.SelectedIndex; |
||||
|
window.WindowState = (WindowState)ShowWindowState.SelectedIndex; |
||||
|
|
||||
|
switch (ShowWindowMode.SelectedIndex) |
||||
|
{ |
||||
|
case 0: |
||||
|
window.Show(); |
||||
|
break; |
||||
|
case 1: |
||||
|
window.Show(Window); |
||||
|
break; |
||||
|
case 2: |
||||
|
window.ShowDialog(Window); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ShowTransparentWindow_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
// Show a background window to make sure the color behind the transparent window is
|
||||
|
// a known color (green).
|
||||
|
var backgroundWindow = new Window |
||||
|
{ |
||||
|
Title = "Transparent Window Background", |
||||
|
Name = "TransparentWindowBackground", |
||||
|
Width = 300, |
||||
|
Height = 300, |
||||
|
Background = Brushes.Green, |
||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner, |
||||
|
}; |
||||
|
|
||||
|
// This is the transparent window with a red circle.
|
||||
|
var window = new Window |
||||
|
{ |
||||
|
Title = "Transparent Window", |
||||
|
Name = "TransparentWindow", |
||||
|
SystemDecorations = SystemDecorations.None, |
||||
|
Background = Brushes.Transparent, |
||||
|
TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent }, |
||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner, |
||||
|
Width = 200, |
||||
|
Height = 200, |
||||
|
Content = new Border |
||||
|
{ |
||||
|
Background = Brushes.Red, |
||||
|
CornerRadius = new CornerRadius(100), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
window.PointerPressed += (_, _) => |
||||
|
{ |
||||
|
window.Close(); |
||||
|
backgroundWindow.Close(); |
||||
|
}; |
||||
|
|
||||
|
backgroundWindow.Show(Window); |
||||
|
window.Show(backgroundWindow); |
||||
|
} |
||||
|
|
||||
|
private void ShowTransparentPopup_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var popup = new Popup |
||||
|
{ |
||||
|
WindowManagerAddShadowHint = false, |
||||
|
Placement = PlacementMode.AnchorAndGravity, |
||||
|
PlacementAnchor = PopupAnchor.Top, |
||||
|
PlacementGravity = PopupGravity.Bottom, |
||||
|
Width = 200, |
||||
|
Height = 200, |
||||
|
Child = new Border |
||||
|
{ |
||||
|
Background = Brushes.Red, |
||||
|
CornerRadius = new CornerRadius(100), |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
// Show a background window to make sure the color behind the transparent window is
|
||||
|
// a known color (green).
|
||||
|
var backgroundWindow = new Window |
||||
|
{ |
||||
|
Title = "Transparent Popup Background", |
||||
|
Name = "TransparentPopupBackground", |
||||
|
Width = 200, |
||||
|
Height = 200, |
||||
|
Background = Brushes.Green, |
||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner, |
||||
|
Content = new Border |
||||
|
{ |
||||
|
Name = "PopupContainer", |
||||
|
Child = popup, |
||||
|
[AutomationProperties.AccessibilityViewProperty] = AccessibilityView.Content, |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
backgroundWindow.PointerPressed += (_, _) => backgroundWindow.Close(); |
||||
|
backgroundWindow.Show(Window); |
||||
|
|
||||
|
popup.Open(); |
||||
|
} |
||||
|
|
||||
|
private void SendToBack_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!; |
||||
|
|
||||
|
foreach (var window in lifetime.Windows.ToArray()) |
||||
|
{ |
||||
|
window.Activate(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void EnterFullscreen_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
Window.WindowState = WindowState.FullScreen; |
||||
|
} |
||||
|
|
||||
|
private void ExitFullscreen_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
Window.WindowState = WindowState.Normal; |
||||
|
} |
||||
|
|
||||
|
private void RestoreAll_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var lifetime = (ClassicDesktopStyleApplicationLifetime)Application.Current!.ApplicationLifetime!; |
||||
|
|
||||
|
foreach (var window in lifetime.Windows.ToArray()) |
||||
|
{ |
||||
|
window.Show(); |
||||
|
if (window.WindowState == WindowState.Minimized) |
||||
|
window.WindowState = WindowState.Normal; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ShowTopmostWindow_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
var mainWindow = new TopmostWindowTest("OwnerWindow") |
||||
|
{ |
||||
|
Topmost = true, |
||||
|
Title = "Owner Window" |
||||
|
}; |
||||
|
var ownedWindow = new TopmostWindowTest("OwnedWindow") |
||||
|
{ |
||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner, |
||||
|
Title = "Owned Window" |
||||
|
}; |
||||
|
|
||||
|
mainWindow.Show(); |
||||
|
ownedWindow.Show(mainWindow); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,23 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.ObjectModel; |
||||
|
using IntegrationTestApp.Models; |
||||
|
|
||||
|
namespace IntegrationTestApp.ViewModels; |
||||
|
|
||||
|
internal class MainWindowViewModel : ViewModelBase |
||||
|
{ |
||||
|
private Page? _selectedPage; |
||||
|
|
||||
|
public MainWindowViewModel(IEnumerable<Page> pages) |
||||
|
{ |
||||
|
Pages = new(pages); |
||||
|
} |
||||
|
|
||||
|
public ObservableCollection<Page> Pages { get; } |
||||
|
|
||||
|
public Page? SelectedPage |
||||
|
{ |
||||
|
get => _selectedPage; |
||||
|
set => RaiseAndSetIfChanged(ref _selectedPage, value); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,24 @@ |
|||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
namespace IntegrationTestApp.ViewModels; |
||||
|
|
||||
|
internal class ViewModelBase : INotifyPropertyChanged |
||||
|
{ |
||||
|
public event PropertyChangedEventHandler? PropertyChanged; |
||||
|
|
||||
|
protected bool RaiseAndSetIfChanged<T>(ref T field, T value, [CallerMemberName] string? propertyName = null) |
||||
|
{ |
||||
|
if (!EqualityComparer<T>.Default.Equals(field, value)) |
||||
|
{ |
||||
|
field = value; |
||||
|
RaisePropertyChanged(propertyName); |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
protected void RaisePropertyChanged([CallerMemberName] string? propertyName = null) |
||||
|
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
using OpenQA.Selenium; |
||||
|
using System.Threading; |
||||
|
|
||||
|
namespace Avalonia.IntegrationTests.Appium; |
||||
|
|
||||
|
public class TestBase |
||||
|
{ |
||||
|
protected TestBase(DefaultAppFixture fixture, string pageName) |
||||
|
{ |
||||
|
Session = fixture.Session; |
||||
|
|
||||
|
var retry = 0; |
||||
|
|
||||
|
for (;;) |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var pager = Session.FindElementByAccessibilityId("Pager"); |
||||
|
var page = pager.FindElementByName(pageName); |
||||
|
page.Click(); |
||||
|
break; |
||||
|
} |
||||
|
catch (WebDriverException) when (retry++ < 3) |
||||
|
{ |
||||
|
// MacOS sometimes seems to need a bit of time to get itself back in order after switching out
|
||||
|
// of fullscreen.
|
||||
|
Thread.Sleep(1000); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected AppiumDriver Session { get; } |
||||
|
} |
||||
Loading…
Reference in new issue