Browse Source
Add ContextRequest event, use it to show ContextFlyout/ContextMenu, allow to open context using keyboard # Conflicts: # samples/ControlCatalog/Pages/ContextFlyoutPage.axaml # samples/ControlCatalog/Pages/ContextMenuPage.xaml # tests/Avalonia.Controls.UnitTests/ContextMenuTests.csrelease/0.10.7
committed by
Dan Walmsley
21 changed files with 1058 additions and 395 deletions
@ -1,102 +0,0 @@ |
|||
<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="ControlCatalog.Pages.ContextFlyoutPage"> |
|||
<UserControl.Styles> |
|||
<Style Selector="FlyoutPresenter.NoPadding"> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
</UserControl.Styles> |
|||
|
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h1">Context Flyout</TextBlock> |
|||
<TextBlock Classes="h2">A right click Flyout that can be applied to any control.</TextBlock> |
|||
|
|||
<StackPanel Orientation="Horizontal" |
|||
Margin="0,16,0,0" |
|||
HorizontalAlignment="Center" |
|||
Spacing="16"> |
|||
<Border Background="{DynamicResource SystemAccentColor}" |
|||
Margin="16" |
|||
Padding="48,48,48,48"> |
|||
<Border.ContextFlyout> |
|||
<MenuFlyout> |
|||
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" /> |
|||
<MenuItem Header="_Disabled Menu Item" IsEnabled="False" InputGesture="Ctrl+D" /> |
|||
<Separator/> |
|||
<MenuItem Header="Menu with _Submenu"> |
|||
<MenuItem Header="Submenu _1"/> |
|||
<MenuItem Header="Submenu _2"/> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B"> |
|||
<MenuItem.Icon> |
|||
<Image Source="/Assets/github_icon.png"/> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Checkbox"> |
|||
<MenuItem.Icon> |
|||
<CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
</MenuFlyout> |
|||
</Border.ContextFlyout> |
|||
<TextBlock Text="Defined in XAML"/> |
|||
</Border> |
|||
<Border Background="{DynamicResource SystemAccentColor}" |
|||
Margin="16" |
|||
Padding="48,48,48,48"> |
|||
<Border.ContextMenu> |
|||
<ContextMenu Items="{Binding MenuItems}"> |
|||
<ContextMenu.Styles> |
|||
<Style Selector="MenuItem"> |
|||
<Setter Property="Header" Value="{Binding Header}"/> |
|||
<Setter Property="Items" Value="{Binding Items}"/> |
|||
<Setter Property="Command" Value="{Binding Command}"/> |
|||
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> |
|||
</Style> |
|||
</ContextMenu.Styles> |
|||
</ContextMenu> |
|||
</Border.ContextMenu> |
|||
<TextBlock Text="Dynamically Generated"/> |
|||
</Border> |
|||
</StackPanel> |
|||
|
|||
<TextBlock Text="Custom ContextFlyout for TextBox" /> |
|||
|
|||
<TextBox Name="TextBox" Width="150" HorizontalAlignment="Center" ContextMenu="{x:Null}"> |
|||
<TextBox.ContextFlyout> |
|||
<Flyout FlyoutPresenterClasses="NoPadding"> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<StackPanel.Styles> |
|||
<Style Selector="Button"> |
|||
<Setter Property="Background" Value="Transparent" /> |
|||
<Setter Property="Height" Value="40" /> |
|||
<Setter Property="Width" Value="40" /> |
|||
<Setter Property="VerticalContentAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="Button:disabled /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="Transparent" /> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
</Style> |
|||
</StackPanel.Styles> |
|||
<Button Name="CutButton" Command="{Binding $parent[TextBox].Cut}" IsEnabled="{Binding $parent[TextBox].CanCut}"> |
|||
<PathIcon Width="14" Height="14" Data="M5.22774,2.08072 C5.43359778,1.94704 5.7011484,1.98419259 5.86368634,2.15675215 L5.91939,2.22774 L12.5191,12.3904 C12.956,12.1419 13.4614,12.0000019 14,12.0000019 C15.6569,12.0000019 17,13.3431 17,15.0000019 C17,16.6569 15.6569,18.0000019 14,18.0000019 C12.3431,18.0000019 11,16.6569 11,15.0000019 C11,14.3201402 11.226152,13.693011 11.6073785,13.1899092 L11.7401,13.0269 L10,10.3474 L8.25991,13.0269 C8.72078,13.5543 9,14.2446 9,15.0000019 C9,16.6569 7.65685,18.0000019 6,18.0000019 C4.34315,18.0000019 3,16.6569 3,15.0000019 C3,13.3431 4.34315,12.0000019 6,12.0000019 C6.46163143,12.0000019 6.89890041,12.1042536 7.28955831,12.2905296 L7.4809,12.3904 L9.40382,9.42936 L5.08072,2.77238 C4.93033,2.54079 4.99615,2.23112 5.22774,2.08072 Z M14,13 C12.8954,13 12,13.8954 12,15 C12,16.1046 12.8954,17 14,17 C15.1046,17 16,16.1046 16,15 C16,13.8954 15.1046,13 14,13 Z M6,13 C4.89543,13 4,13.8954 4,15 C4,16.1046 4.89543,17 6,17 C7.10457,17 8,16.1046 8,15 C8,13.8954 7.10457,13 6,13 Z M14.7723,2.08072 C15.0039,2.23112 15.0697,2.54079 14.9193,2.77238 L11.1924,8.51133 L10.5962,7.59329 L14.0806,2.22774 C14.231,1.99615 14.5407,1.93033 14.7723,2.08072 Z" /> |
|||
</Button> |
|||
<Button Name="CopyButton" Content="Copy" Command="{Binding $parent[TextBox].Copy}" IsEnabled="{Binding $parent[TextBox].CanCopy}"> |
|||
<PathIcon Width="14" Height="14" Data="M5.50280381,4.62704038 L5.5,6.75 L5.5,17.2542087 C5.5,19.0491342 6.95507456,20.5042087 8.75,20.5042087 L17.3662868,20.5044622 C17.057338,21.3782241 16.2239751,22.0042087 15.2444057,22.0042087 L8.75,22.0042087 C6.12664744,22.0042087 4,19.8775613 4,17.2542087 L4,6.75 C4,5.76928848 4.62744523,4.93512464 5.50280381,4.62704038 Z M17.75,2 C18.9926407,2 20,3.00735931 20,4.25 L20,17.25 C20,18.4926407 18.9926407,19.5 17.75,19.5 L8.75,19.5 C7.50735931,19.5 6.5,18.4926407 6.5,17.25 L6.5,4.25 C6.5,3.00735931 7.50735931,2 8.75,2 L17.75,2 Z M17.75,3.5 L8.75,3.5 C8.33578644,3.5 8,3.83578644 8,4.25 L8,17.25 C8,17.6642136 8.33578644,18 8.75,18 L17.75,18 C18.1642136,18 18.5,17.6642136 18.5,17.25 L18.5,4.25 C18.5,3.83578644 18.1642136,3.5 17.75,3.5 Z" /> |
|||
</Button> |
|||
<Button Name="PasteButton" Content="Paste" Command="{Binding $parent[TextBox].Paste}" IsEnabled="{Binding $parent[TextBox].CanPaste}"> |
|||
<PathIcon Width="14" Height="14" Data="M13.75,2 C14.940864,2 15.9156449,2.92516159 15.9948092,4.09595119 L16,4.25 L16,4.25 C16,4.16530567 15.9953205,4.0817043 15.9862059,3.99944035 L17.75,4 C18.9926407,4 20,5.00735931 20,6.25 L20,19.75 C20,20.9926407 18.9926407,22 17.75,22 L6.25,22 C5.00735931,22 4,20.9926407 4,19.75 L4,6.25 C4,5.00735931 5.00735931,4 6.25,4 L8.01379413,3.99944035 C8.00733496,4.05773764 8.00310309,4.11670658 8.00118552,4.17626017 L8,4.25 C8,3.00735931 9.00735931,2 10.25,2 L13.75,2 Z M13.75,6.5 L10.25,6.5 C9.45594921,6.5 8.75796956,6.08867052 8.357512,5.4674625 L8.37902077,5.50019943 L8.37902077,5.50019943 L6.25,5.5 C5.83578644,5.5 5.5,5.83578644 5.5,6.25 L5.5,19.75 C5.5,20.1642136 5.83578644,20.5 6.25,20.5 L17.75,20.5 C18.1642136,20.5 18.5,20.1642136 18.5,19.75 L18.5,6.25 C18.5,5.83578644 18.1642136,5.5 17.75,5.5 L15.6209792,5.50019943 L15.642488,5.4674625 C15.2420304,6.08867052 14.5440508,6.5 13.75,6.5 Z M13.75,3.5 L10.25,3.5 C9.83578644,3.5 9.5,3.83578644 9.5,4.25 C9.5,4.66421356 9.83578644,5 10.25,5 L13.75,5 C14.1642136,5 14.5,4.66421356 14.5,4.25 C14.5,3.83578644 14.1642136,3.5 13.75,3.5 Z" /> |
|||
</Button> |
|||
<Button Name="ClearButton" Content="Clear" Command="{Binding $parent[TextBox].Clear}"> |
|||
<PathIcon Width="14" Height="14" Data="M3.52499419,3.71761187 L3.61611652,3.61611652 C4.0717282,3.16050485 4.79154862,3.13013074 5.28238813,3.52499419 L5.38388348,3.61611652 L14,12.233 L22.6161165,3.61611652 C23.1042719,3.12796116 23.8957281,3.12796116 24.3838835,3.61611652 C24.8720388,4.10427189 24.8720388,4.89572811 24.3838835,5.38388348 L15.767,14 L24.3838835,22.6161165 C24.8394952,23.0717282 24.8698693,23.7915486 24.4750058,24.2823881 L24.3838835,24.3838835 C23.9282718,24.8394952 23.2084514,24.8698693 22.7176119,24.4750058 L22.6161165,24.3838835 L14,15.767 L5.38388348,24.3838835 C4.89572811,24.8720388 4.10427189,24.8720388 3.61611652,24.3838835 C3.12796116,23.8957281 3.12796116,23.1042719 3.61611652,22.6161165 L12.233,14 L3.61611652,5.38388348 C3.16050485,4.9282718 3.13013074,4.20845138 3.52499419,3.71761187 L3.61611652,3.61611652 L3.52499419,3.71761187 Z" /> |
|||
</Button> |
|||
</StackPanel> |
|||
</Flyout> |
|||
</TextBox.ContextFlyout> |
|||
</TextBox> |
|||
|
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -1,45 +0,0 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
using Avalonia.Interactivity; |
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ContextFlyoutPage : UserControl |
|||
{ |
|||
private TextBox _textBox; |
|||
|
|||
public ContextFlyoutPage() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
var vm = new ContextFlyoutPageViewModel(); |
|||
vm.View = this; |
|||
DataContext = vm; |
|||
|
|||
_textBox = this.FindControl<TextBox>("TextBox"); |
|||
|
|||
var cutButton = this.FindControl<Button>("CutButton"); |
|||
cutButton.Click += CloseFlyout; |
|||
|
|||
var copyButton = this.FindControl<Button>("CopyButton"); |
|||
copyButton.Click += CloseFlyout; |
|||
|
|||
var pasteButton = this.FindControl<Button>("PasteButton"); |
|||
pasteButton.Click += CloseFlyout; |
|||
|
|||
var clearButton = this.FindControl<Button>("ClearButton"); |
|||
clearButton.Click += CloseFlyout; |
|||
} |
|||
|
|||
private void CloseFlyout(object sender, RoutedEventArgs e) |
|||
{ |
|||
_textBox.ContextFlyout.Hide(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,157 @@ |
|||
<UserControl x:Class="ControlCatalog.Pages.ContextFlyoutPage" |
|||
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" |
|||
d:DesignHeight="450" |
|||
d:DesignWidth="800" |
|||
mc:Ignorable="d"> |
|||
<UserControl.Styles> |
|||
<Style Selector="FlyoutPresenter.NoPadding"> |
|||
<Setter Property="Padding" Value="0" /> |
|||
</Style> |
|||
</UserControl.Styles> |
|||
|
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<StackPanel.Styles> |
|||
<Style Selector="Border.context-target"> |
|||
<Setter Property="Padding" Value="48,20" /> |
|||
<Setter Property="Margin" Value="8" /> |
|||
<Setter Property="Focusable" Value="True" /> |
|||
<Setter Property="Background" Value="{DynamicResource SystemAccentColor}" /> |
|||
</Style> |
|||
<Style Selector="Border.context-target > :is(Control)"> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
</StackPanel.Styles> |
|||
<TextBlock Classes="h1">Context Flyout</TextBlock> |
|||
<TextBlock Classes="h2">A right click Flyout that can be applied to any control.</TextBlock> |
|||
|
|||
<UniformGrid HorizontalAlignment="Center" Rows="2"> |
|||
<Border Classes="context-target"> |
|||
<Border.ContextFlyout> |
|||
<MenuFlyout> |
|||
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" /> |
|||
<MenuItem Header="_Disabled Menu Item" |
|||
InputGesture="Ctrl+D" |
|||
IsEnabled="False" /> |
|||
<Separator /> |
|||
<MenuItem Header="Menu with _Submenu"> |
|||
<MenuItem Header="Submenu _1" /> |
|||
<MenuItem Header="Submenu _2" /> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B"> |
|||
<MenuItem.Icon> |
|||
<Image Source="/Assets/github_icon.png" /> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Checkbox"> |
|||
<MenuItem.Icon> |
|||
<CheckBox BorderThickness="0" |
|||
IsChecked="True" |
|||
IsHitTestVisible="False" /> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
</MenuFlyout> |
|||
</Border.ContextFlyout> |
|||
<TextBlock Text="Defined in XAML" /> |
|||
</Border> |
|||
<Border Classes="context-target"> |
|||
<Border.Styles> |
|||
<Style Selector="MenuFlyoutPresenter MenuItem"> |
|||
<Setter Property="Header" Value="{Binding Header}"/> |
|||
<Setter Property="Items" Value="{Binding Items}"/> |
|||
<Setter Property="Command" Value="{Binding Command}"/> |
|||
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> |
|||
</Style> |
|||
</Border.Styles> |
|||
<Border.ContextFlyout> |
|||
<MenuFlyout Items="{Binding MenuItems}" /> |
|||
</Border.ContextFlyout> |
|||
<TextBlock Text="Dynamically Generated"/> |
|||
</Border> |
|||
<Border x:Name="CustomContextRequestedBorder" |
|||
Classes="context-target"> |
|||
<Border.ContextFlyout> |
|||
<Flyout Content="Should never be visible" /> |
|||
</Border.ContextFlyout> |
|||
<TextBlock Text="Custom ContextRequested handler" TextWrapping="Wrap" /> |
|||
</Border> |
|||
<Border x:Name="CancellableContextBorder" |
|||
Classes="context-target"> |
|||
<Border.ContextFlyout> |
|||
<Flyout> |
|||
<CheckBox x:Name="CancelCloseCheckBox" Content="Cancel close" /> |
|||
</Flyout> |
|||
</Border.ContextFlyout> |
|||
<StackPanel> |
|||
<TextBlock Text="Cancellable" /> |
|||
<CheckBox x:Name="CancelOpenCheckBox" Content="Cancel open" /> |
|||
</StackPanel> |
|||
</Border> |
|||
</UniformGrid> |
|||
|
|||
<TextBlock Text="Custom ContextFlyout for TextBox" /> |
|||
|
|||
<TextBox Name="TextBox" |
|||
Width="150" |
|||
HorizontalAlignment="Center" |
|||
ContextMenu="{x:Null}"> |
|||
<TextBox.ContextFlyout> |
|||
<Flyout FlyoutPresenterClasses="NoPadding"> |
|||
<StackPanel> |
|||
<StackPanel Orientation="Horizontal"> |
|||
<StackPanel.Styles> |
|||
<Style Selector="Button"> |
|||
<Setter Property="Background" Value="Transparent" /> |
|||
<Setter Property="Height" Value="40" /> |
|||
<Setter Property="Width" Value="40" /> |
|||
<Setter Property="VerticalContentAlignment" Value="Center" /> |
|||
</Style> |
|||
<Style Selector="Button:disabled /template/ ContentPresenter#PART_ContentPresenter"> |
|||
<Setter Property="Background" Value="Transparent" /> |
|||
<Setter Property="Opacity" Value="0.5" /> |
|||
</Style> |
|||
</StackPanel.Styles> |
|||
<Button Name="CutButton" |
|||
Command="{Binding $parent[TextBox].Cut}" |
|||
IsEnabled="{Binding $parent[TextBox].CanCut}"> |
|||
<PathIcon Width="14" |
|||
Height="14" |
|||
Data="M5.22774,2.08072 C5.43359778,1.94704 5.7011484,1.98419259 5.86368634,2.15675215 L5.91939,2.22774 L12.5191,12.3904 C12.956,12.1419 13.4614,12.0000019 14,12.0000019 C15.6569,12.0000019 17,13.3431 17,15.0000019 C17,16.6569 15.6569,18.0000019 14,18.0000019 C12.3431,18.0000019 11,16.6569 11,15.0000019 C11,14.3201402 11.226152,13.693011 11.6073785,13.1899092 L11.7401,13.0269 L10,10.3474 L8.25991,13.0269 C8.72078,13.5543 9,14.2446 9,15.0000019 C9,16.6569 7.65685,18.0000019 6,18.0000019 C4.34315,18.0000019 3,16.6569 3,15.0000019 C3,13.3431 4.34315,12.0000019 6,12.0000019 C6.46163143,12.0000019 6.89890041,12.1042536 7.28955831,12.2905296 L7.4809,12.3904 L9.40382,9.42936 L5.08072,2.77238 C4.93033,2.54079 4.99615,2.23112 5.22774,2.08072 Z M14,13 C12.8954,13 12,13.8954 12,15 C12,16.1046 12.8954,17 14,17 C15.1046,17 16,16.1046 16,15 C16,13.8954 15.1046,13 14,13 Z M6,13 C4.89543,13 4,13.8954 4,15 C4,16.1046 4.89543,17 6,17 C7.10457,17 8,16.1046 8,15 C8,13.8954 7.10457,13 6,13 Z M14.7723,2.08072 C15.0039,2.23112 15.0697,2.54079 14.9193,2.77238 L11.1924,8.51133 L10.5962,7.59329 L14.0806,2.22774 C14.231,1.99615 14.5407,1.93033 14.7723,2.08072 Z" /> |
|||
</Button> |
|||
<Button Name="CopyButton" |
|||
Command="{Binding $parent[TextBox].Copy}" |
|||
IsEnabled="{Binding $parent[TextBox].CanCopy}"> |
|||
<PathIcon Width="14" |
|||
Height="14" |
|||
Data="M5.50280381,4.62704038 L5.5,6.75 L5.5,17.2542087 C5.5,19.0491342 6.95507456,20.5042087 8.75,20.5042087 L17.3662868,20.5044622 C17.057338,21.3782241 16.2239751,22.0042087 15.2444057,22.0042087 L8.75,22.0042087 C6.12664744,22.0042087 4,19.8775613 4,17.2542087 L4,6.75 C4,5.76928848 4.62744523,4.93512464 5.50280381,4.62704038 Z M17.75,2 C18.9926407,2 20,3.00735931 20,4.25 L20,17.25 C20,18.4926407 18.9926407,19.5 17.75,19.5 L8.75,19.5 C7.50735931,19.5 6.5,18.4926407 6.5,17.25 L6.5,4.25 C6.5,3.00735931 7.50735931,2 8.75,2 L17.75,2 Z M17.75,3.5 L8.75,3.5 C8.33578644,3.5 8,3.83578644 8,4.25 L8,17.25 C8,17.6642136 8.33578644,18 8.75,18 L17.75,18 C18.1642136,18 18.5,17.6642136 18.5,17.25 L18.5,4.25 C18.5,3.83578644 18.1642136,3.5 17.75,3.5 Z" /> |
|||
</Button> |
|||
<Button Name="PasteButton" |
|||
Command="{Binding $parent[TextBox].Paste}" |
|||
IsEnabled="{Binding $parent[TextBox].CanPaste}"> |
|||
<PathIcon Width="14" |
|||
Height="14" |
|||
Data="M13.75,2 C14.940864,2 15.9156449,2.92516159 15.9948092,4.09595119 L16,4.25 L16,4.25 C16,4.16530567 15.9953205,4.0817043 15.9862059,3.99944035 L17.75,4 C18.9926407,4 20,5.00735931 20,6.25 L20,19.75 C20,20.9926407 18.9926407,22 17.75,22 L6.25,22 C5.00735931,22 4,20.9926407 4,19.75 L4,6.25 C4,5.00735931 5.00735931,4 6.25,4 L8.01379413,3.99944035 C8.00733496,4.05773764 8.00310309,4.11670658 8.00118552,4.17626017 L8,4.25 C8,3.00735931 9.00735931,2 10.25,2 L13.75,2 Z M13.75,6.5 L10.25,6.5 C9.45594921,6.5 8.75796956,6.08867052 8.357512,5.4674625 L8.37902077,5.50019943 L8.37902077,5.50019943 L6.25,5.5 C5.83578644,5.5 5.5,5.83578644 5.5,6.25 L5.5,19.75 C5.5,20.1642136 5.83578644,20.5 6.25,20.5 L17.75,20.5 C18.1642136,20.5 18.5,20.1642136 18.5,19.75 L18.5,6.25 C18.5,5.83578644 18.1642136,5.5 17.75,5.5 L15.6209792,5.50019943 L15.642488,5.4674625 C15.2420304,6.08867052 14.5440508,6.5 13.75,6.5 Z M13.75,3.5 L10.25,3.5 C9.83578644,3.5 9.5,3.83578644 9.5,4.25 C9.5,4.66421356 9.83578644,5 10.25,5 L13.75,5 C14.1642136,5 14.5,4.66421356 14.5,4.25 C14.5,3.83578644 14.1642136,3.5 13.75,3.5 Z" /> |
|||
</Button> |
|||
<Button Name="ClearButton" Command="{Binding $parent[TextBox].Clear}"> |
|||
<PathIcon Width="14" |
|||
Height="14" |
|||
Data="M3.52499419,3.71761187 L3.61611652,3.61611652 C4.0717282,3.16050485 4.79154862,3.13013074 5.28238813,3.52499419 L5.38388348,3.61611652 L14,12.233 L22.6161165,3.61611652 C23.1042719,3.12796116 23.8957281,3.12796116 24.3838835,3.61611652 C24.8720388,4.10427189 24.8720388,4.89572811 24.3838835,5.38388348 L15.767,14 L24.3838835,22.6161165 C24.8394952,23.0717282 24.8698693,23.7915486 24.4750058,24.2823881 L24.3838835,24.3838835 C23.9282718,24.8394952 23.2084514,24.8698693 22.7176119,24.4750058 L22.6161165,24.3838835 L14,15.767 L5.38388348,24.3838835 C4.89572811,24.8720388 4.10427189,24.8720388 3.61611652,24.3838835 C3.12796116,23.8957281 3.12796116,23.1042719 3.61611652,22.6161165 L12.233,14 L3.61611652,5.38388348 C3.16050485,4.9282718 3.13013074,4.20845138 3.52499419,3.71761187 L3.61611652,3.61611652 L3.52499419,3.71761187 Z" /> |
|||
</Button> |
|||
</StackPanel> |
|||
<Border Classes="context-target" |
|||
Padding="4, 20"> |
|||
<Border.ContextFlyout> |
|||
<Flyout> |
|||
<TextBlock>Hello world</TextBlock> |
|||
</Flyout> |
|||
</Border.ContextFlyout> |
|||
<TextBlock>Inner context flyout</TextBlock> |
|||
</Border> |
|||
</StackPanel> |
|||
</Flyout> |
|||
</TextBox.ContextFlyout> |
|||
</TextBox> |
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,91 @@ |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Markup.Xaml; |
|||
using ControlCatalog.ViewModels; |
|||
using Avalonia.Interactivity; |
|||
using System; |
|||
using System.ComponentModel; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ContextFlyoutPage : UserControl |
|||
{ |
|||
private TextBox _textBox; |
|||
|
|||
public ContextFlyoutPage() |
|||
{ |
|||
InitializeComponent(); |
|||
|
|||
DataContext = new ContextPageViewModel(); |
|||
|
|||
_textBox = this.FindControl<TextBox>("TextBox"); |
|||
|
|||
var cutButton = this.FindControl<Button>("CutButton"); |
|||
cutButton.Click += CloseFlyout; |
|||
|
|||
var copyButton = this.FindControl<Button>("CopyButton"); |
|||
copyButton.Click += CloseFlyout; |
|||
|
|||
var pasteButton = this.FindControl<Button>("PasteButton"); |
|||
pasteButton.Click += CloseFlyout; |
|||
|
|||
var clearButton = this.FindControl<Button>("ClearButton"); |
|||
clearButton.Click += CloseFlyout; |
|||
|
|||
var customContextRequestedBorder = this.FindControl<Border>("CustomContextRequestedBorder"); |
|||
customContextRequestedBorder.AddHandler(ContextRequestedEvent, CustomContextRequested, RoutingStrategies.Tunnel); |
|||
|
|||
var cancellableContextBorder = this.FindControl<Border>("CancellableContextBorder"); |
|||
cancellableContextBorder.ContextFlyout!.Closing += ContextFlyoutPage_Closing; |
|||
cancellableContextBorder.ContextFlyout!.Opening += ContextFlyoutPage_Opening; |
|||
} |
|||
|
|||
private ContextPageViewModel _model; |
|||
protected override void OnDataContextChanged(EventArgs e) |
|||
{ |
|||
if (_model != null) |
|||
_model.View = null; |
|||
_model = DataContext as ContextPageViewModel; |
|||
if (_model != null) |
|||
_model.View = this; |
|||
|
|||
base.OnDataContextChanged(e); |
|||
} |
|||
|
|||
private void ContextFlyoutPage_Closing(object sender, CancelEventArgs e) |
|||
{ |
|||
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelCloseCheckBox"); |
|||
e.Cancel = cancelCloseCheckBox.IsChecked ?? false; |
|||
} |
|||
|
|||
private void ContextFlyoutPage_Opening(object sender, EventArgs e) |
|||
{ |
|||
if (e is CancelEventArgs cancelArgs) |
|||
{ |
|||
var cancelCloseCheckBox = this.FindControl<CheckBox>("CancelOpenCheckBox"); |
|||
cancelArgs.Cancel = cancelCloseCheckBox.IsChecked ?? false; |
|||
} |
|||
} |
|||
|
|||
private void CloseFlyout(object sender, RoutedEventArgs e) |
|||
{ |
|||
_textBox.ContextFlyout.Hide(); |
|||
} |
|||
|
|||
public void CustomContextRequested(object sender, ContextRequestedEventArgs e) |
|||
{ |
|||
var border = (Border)sender; |
|||
var textBlock = (TextBlock)border.Child; |
|||
|
|||
textBlock.Text = e.TryGetPosition(border, out var point) |
|||
? $"Context was requested with pointer at: {point.X:N0}, {point.Y:N0}" |
|||
: "Context was requested without pointer"; |
|||
e.Handled = true; |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -1,57 +1,88 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
x:Class="ControlCatalog.Pages.ContextMenuPage"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h1">Context Menu</TextBlock> |
|||
<TextBlock Classes="h2">A right click menu that can be applied to any control.</TextBlock> |
|||
<UserControl x:Class="ControlCatalog.Pages.ContextMenuPage" |
|||
xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock Classes="h1">Context Menu</TextBlock> |
|||
<TextBlock Classes="h2">A right click menu that can be applied to any control.</TextBlock> |
|||
|
|||
<StackPanel Orientation="Horizontal" |
|||
Margin="0,16,0,0" |
|||
HorizontalAlignment="Center" |
|||
Spacing="16"> |
|||
<Border Background="{DynamicResource SystemAccentColor}" |
|||
Margin="16" |
|||
Padding="48,48,48,48"> |
|||
<Border.ContextMenu> |
|||
<ContextMenu> |
|||
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" /> |
|||
<MenuItem Header="_Disabled Menu Item" IsEnabled="False" InputGesture="Ctrl+D" /> |
|||
<Separator/> |
|||
<MenuItem Header="Menu with _Submenu"> |
|||
<MenuItem Header="Submenu _1"/> |
|||
<MenuItem Header="Submenu _2"/> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B"> |
|||
<MenuItem.Icon> |
|||
<Image Source="/Assets/github_icon.png"/> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Checkbox"> |
|||
<MenuItem.Icon> |
|||
<CheckBox BorderThickness="0" IsHitTestVisible="False" IsChecked="True"/> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
</ContextMenu> |
|||
</Border.ContextMenu> |
|||
<TextBlock Text="Defined in XAML"/> |
|||
</Border> |
|||
<Border Background="{DynamicResource SystemAccentColor}" |
|||
Margin="16" |
|||
Padding="48,48,48,48"> |
|||
<Border.ContextMenu> |
|||
<ContextMenu Items="{Binding MenuItems}"> |
|||
<ContextMenu.Styles> |
|||
<Style Selector="MenuItem"> |
|||
<Setter Property="Header" Value="{Binding Header}"/> |
|||
<Setter Property="Items" Value="{Binding Items}"/> |
|||
<Setter Property="Command" Value="{Binding Command}"/> |
|||
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> |
|||
</Style> |
|||
</ContextMenu.Styles> |
|||
</ContextMenu> |
|||
</Border.ContextMenu> |
|||
<TextBlock Text="Dynamically Generated"/> |
|||
</Border> |
|||
<UniformGrid HorizontalAlignment="Center" Rows="2"> |
|||
<UniformGrid.Styles> |
|||
<Style Selector="UniformGrid > Border"> |
|||
<Setter Property="Padding" Value="48,20" /> |
|||
<Setter Property="Margin" Value="8" /> |
|||
<Setter Property="Focusable" Value="True" /> |
|||
<Setter Property="Background" Value="{DynamicResource SystemAccentColor}" /> |
|||
</Style> |
|||
<Style Selector="UniformGrid > Border > :is(Control)"> |
|||
<Setter Property="VerticalAlignment" Value="Center" /> |
|||
</Style> |
|||
</UniformGrid.Styles> |
|||
<Border> |
|||
<Border.ContextMenu> |
|||
<ContextMenu> |
|||
<MenuItem Header="Standard _Menu Item" InputGesture="Ctrl+A" /> |
|||
<MenuItem Header="_Disabled Menu Item" |
|||
InputGesture="Ctrl+D" |
|||
IsEnabled="False" /> |
|||
<Separator /> |
|||
<MenuItem Header="Menu with _Submenu"> |
|||
<MenuItem Header="Submenu _1" /> |
|||
<MenuItem Header="Submenu _2" /> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Icon" InputGesture="Ctrl+Shift+B"> |
|||
<MenuItem.Icon> |
|||
<Image Source="/Assets/github_icon.png" /> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item with _Checkbox"> |
|||
<MenuItem.Icon> |
|||
<CheckBox BorderThickness="0" |
|||
IsChecked="True" |
|||
IsHitTestVisible="False" /> |
|||
</MenuItem.Icon> |
|||
</MenuItem> |
|||
<MenuItem Header="Menu Item that won't close on click" StaysOpenOnClick="True" /> |
|||
</ContextMenu> |
|||
</Border.ContextMenu> |
|||
<TextBlock Text="Defined in XAML" /> |
|||
</Border> |
|||
<Border> |
|||
<Border.Styles> |
|||
<Style Selector="ContextMenu MenuItem"> |
|||
<Setter Property="Header" Value="{Binding Header}"/> |
|||
<Setter Property="Items" Value="{Binding Items}"/> |
|||
<Setter Property="Command" Value="{Binding Command}"/> |
|||
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/> |
|||
</Style> |
|||
</Border.Styles> |
|||
<Border.ContextMenu> |
|||
<ContextMenu Items="{Binding MenuItems}" /> |
|||
</Border.ContextMenu> |
|||
<TextBlock Text="Dynamically Generated"/> |
|||
</Border> |
|||
<Border x:Name="CustomContextRequestedBorder"> |
|||
<Border.ContextMenu> |
|||
<ContextMenu> |
|||
<MenuItem Header="Should never be visible" /> |
|||
</ContextMenu> |
|||
</Border.ContextMenu> |
|||
<TextBlock Text="Custom ContextRequested handler" TextWrapping="Wrap" /> |
|||
</Border> |
|||
<Border x:Name="CancellableContextBorder"> |
|||
<Border.ContextMenu> |
|||
<ContextMenu> |
|||
<MenuItem> |
|||
<MenuItem.Header> |
|||
<CheckBox x:Name="CancelCloseCheckBox" Content="Cancel close" /> |
|||
</MenuItem.Header> |
|||
</MenuItem> |
|||
</ContextMenu> |
|||
</Border.ContextMenu> |
|||
<StackPanel> |
|||
<TextBlock Text="Cancellable" /> |
|||
<CheckBox x:Name="CancelOpenCheckBox" Content="Cancel open" /> |
|||
</StackPanel> |
|||
</StackPanel> |
|||
</Border> |
|||
</UniformGrid> |
|||
</StackPanel> |
|||
</UserControl> |
|||
|
|||
@ -1,78 +0,0 @@ |
|||
using System.Collections.Generic; |
|||
using System.Reactive; |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Controls; |
|||
using Avalonia.VisualTree; |
|||
using MiniMvvm; |
|||
|
|||
namespace ControlCatalog.ViewModels |
|||
{ |
|||
public class ContextFlyoutPageViewModel |
|||
{ |
|||
public Control View { get; set; } |
|||
public ContextFlyoutPageViewModel() |
|||
{ |
|||
OpenCommand = MiniCommand.CreateFromTask(Open); |
|||
SaveCommand = MiniCommand.Create(Save); |
|||
OpenRecentCommand = MiniCommand.Create<string>(OpenRecent); |
|||
|
|||
MenuItems = new[] |
|||
{ |
|||
new MenuItemViewModel { Header = "_Open...", Command = OpenCommand }, |
|||
new MenuItemViewModel { Header = "Save", Command = SaveCommand }, |
|||
new MenuItemViewModel { Header = "-" }, |
|||
new MenuItemViewModel |
|||
{ |
|||
Header = "Recent", |
|||
Items = new[] |
|||
{ |
|||
new MenuItemViewModel |
|||
{ |
|||
Header = "File1.txt", |
|||
Command = OpenRecentCommand, |
|||
CommandParameter = @"c:\foo\File1.txt" |
|||
}, |
|||
new MenuItemViewModel |
|||
{ |
|||
Header = "File2.txt", |
|||
Command = OpenRecentCommand, |
|||
CommandParameter = @"c:\foo\File2.txt" |
|||
}, |
|||
} |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; } |
|||
public MiniCommand OpenCommand { get; } |
|||
public MiniCommand SaveCommand { get; } |
|||
public MiniCommand OpenRecentCommand { get; } |
|||
|
|||
public async Task Open() |
|||
{ |
|||
var window = View?.GetVisualRoot() as Window; |
|||
if (window == null) |
|||
return; |
|||
var dialog = new OpenFileDialog(); |
|||
var result = await dialog.ShowAsync(window); |
|||
|
|||
if (result != null) |
|||
{ |
|||
foreach (var path in result) |
|||
{ |
|||
System.Diagnostics.Debug.WriteLine($"Opened: {path}"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
public void Save() |
|||
{ |
|||
System.Diagnostics.Debug.WriteLine("Save"); |
|||
} |
|||
|
|||
public void OpenRecent(string path) |
|||
{ |
|||
System.Diagnostics.Debug.WriteLine($"Open recent: {path}"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,58 @@ |
|||
using Avalonia.Input; |
|||
using Avalonia.Interactivity; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls |
|||
{ |
|||
/// <summary>
|
|||
/// Provides event data for the ContextRequested event.
|
|||
/// </summary>
|
|||
public class ContextRequestedEventArgs : RoutedEventArgs |
|||
{ |
|||
private readonly PointerEventArgs? _pointerEventArgs; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the ContextRequestedEventArgs class.
|
|||
/// </summary>
|
|||
public ContextRequestedEventArgs() |
|||
: base(Control.ContextRequestedEvent) |
|||
{ |
|||
|
|||
} |
|||
|
|||
/// <inheritdoc cref="ContextRequestedEventArgs()" />
|
|||
public ContextRequestedEventArgs(PointerEventArgs pointerEventArgs) |
|||
: this() |
|||
{ |
|||
_pointerEventArgs = pointerEventArgs; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the x- and y-coordinates of the pointer position, optionally evaluated against a coordinate origin of a supplied <see cref="Control"/>.
|
|||
/// </summary>
|
|||
/// <param name="relativeTo">
|
|||
/// Any <see cref="Control"/>-derived object that is connected to the same object tree.
|
|||
/// To specify the object relative to the overall coordinate system, use a relativeTo value of null.
|
|||
/// </param>
|
|||
/// <param name="point">
|
|||
/// A <see cref="Point"/> that represents the current x- and y-coordinates of the mouse pointer position.
|
|||
/// If null was passed as relativeTo, this coordinate is for the overall window.
|
|||
/// If a relativeTo value other than null was passed, this coordinate is relative to the object referenced by relativeTo.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// true if the context request was initiated by a pointer device; otherwise, false.
|
|||
/// </returns>
|
|||
public bool TryGetPosition(Control? relativeTo, out Point point) |
|||
{ |
|||
if (_pointerEventArgs is null) |
|||
{ |
|||
point = default; |
|||
return false; |
|||
} |
|||
|
|||
point = _pointerEventArgs.GetPosition(relativeTo); |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue