feat: advanced dialog layout.

This commit is contained in:
rabbitism
2024-02-02 19:58:52 +08:00
parent 6e8ab8c16d
commit 75503b8055
9 changed files with 260 additions and 32 deletions

View File

@@ -119,6 +119,10 @@ public class DialogDemoViewModel: ObservableObject
Mode = SelectedMode, Mode = SelectedMode,
Buttons = SelectedButton, Buttons = SelectedButton,
CanClickOnMaskToClose = CanCloseMaskToClose, CanClickOnMaskToClose = CanCloseMaskToClose,
HorizontalAnchor = HorizontalPosition.Right,
HorizontalOffset = 50,
VerticalAnchor = VerticalPosition.Top,
VerticalOffset = 50,
} }
); );
Date = vm.Date; Date = vm.Date;

View File

@@ -93,7 +93,7 @@
<converters:ViewLocator /> <converters:ViewLocator />
</ContentControl.ContentTemplate> </ContentControl.ContentTemplate>
</ContentControl> </ContentControl>
<u:OverlayDialogHost Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2"/> <u:OverlayDialogHost Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" SnapThickness="20"/>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -46,6 +46,23 @@
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^ /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem
Command="{Binding $parent[u:DialogControl].CloseDialog}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
<Style Selector="^:not(:modal) /template/ Panel#PART_TitleArea"> <Style Selector="^:not(:modal) /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout"> <Setter Property="ContextFlyout">
<MenuFlyout> <MenuFlyout>
@@ -93,6 +110,17 @@
Data="{DynamicResource DialogArrangeSendToBackGlyph}" /> Data="{DynamicResource DialogArrangeSendToBackGlyph}" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControl].CloseDialog}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout> </MenuFlyout>
</Setter> </Setter>
</Style> </Style>
@@ -115,11 +143,13 @@
Theme="{DynamicResource CardBorder}"> Theme="{DynamicResource CardBorder}">
<Border ClipToBounds="True" CornerRadius="{TemplateBinding CornerRadius}"> <Border ClipToBounds="True" CornerRadius="{TemplateBinding CornerRadius}">
<Grid RowDefinitions="Auto, *, Auto"> <Grid RowDefinitions="Auto, *, Auto">
<ContentPresenter <ScrollViewer Grid.Row="1">
Name="PART_ContentPresenter" <ContentPresenter
Grid.Row="1" Name="PART_ContentPresenter"
Margin="24,8" Grid.Row="1"
Content="{TemplateBinding Content}" /> Margin="24,8"
Content="{TemplateBinding Content}" />
</ScrollViewer>
<Grid Grid.Row="0" ColumnDefinitions="Auto, *, Auto"> <Grid Grid.Row="0" ColumnDefinitions="Auto, *, Auto">
<Panel <Panel
Name="{x:Static u:DialogControl.PART_TitleArea}" Name="{x:Static u:DialogControl.PART_TitleArea}"
@@ -304,7 +334,23 @@
<Setter Property="theme:ClassHelper.Classes" Value="Tertiary" /> <Setter Property="theme:ClassHelper.Classes" Value="Tertiary" />
</Style> </Style>
</Style> </Style>
<Style Selector="^ /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem
Command="{Binding $parent[u:DialogControl].CloseDialog}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
<Style Selector="^:not(:modal) /template/ Panel#PART_TitleArea"> <Style Selector="^:not(:modal) /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout"> <Setter Property="ContextFlyout">
<MenuFlyout> <MenuFlyout>
@@ -352,6 +398,17 @@
Data="{DynamicResource DialogArrangeSendToBackGlyph}" /> Data="{DynamicResource DialogArrangeSendToBackGlyph}" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem
Command="{Binding $parent[u:DialogControl].CloseDialog}"
CommandParameter="{x:Static u:DialogLayerChangeType.BringForward}"
Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout> </MenuFlyout>
</Setter> </Setter>
</Style> </Style>

View File

@@ -81,7 +81,7 @@
</Grid> </Grid>
<StackPanel <StackPanel
Grid.Row="2" Grid.Row="2"
Margin="0,0,24,24" Margin="24,0,24,24"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Orientation="Horizontal"> Orientation="Horizontal">
<Button <Button
@@ -244,6 +244,20 @@
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^ /template/ Panel#PART_TitleArea">
<Setter Property="ContextFlyout">
<MenuFlyout>
<MenuItem Command="{Binding $parent[u:DialogControl].CloseDialog}" Header="{DynamicResource STRING_MENU_DIALOG_CLOSE}">
<MenuItem.Icon>
<PathIcon
Width="12"
Height="12"
Data="{DynamicResource WindowCloseIconGlyph}" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</Setter>
</Style>
<Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon"> <Style Selector="^[MessageIcon=None] /template/ PathIcon#PART_Icon">
<Setter Property="IsVisible" Value="False" /> <Setter Property="IsVisible" Value="False" />
</Style> </Style>

View File

@@ -9,4 +9,5 @@
<x:String x:Key="STRING_MENU_DIALOG_CANCEL">Cancel</x:String> <x:String x:Key="STRING_MENU_DIALOG_CANCEL">Cancel</x:String>
<x:String x:Key="STRING_MENU_DIALOG_YES">Yes</x:String> <x:String x:Key="STRING_MENU_DIALOG_YES">Yes</x:String>
<x:String x:Key="STRING_MENU_DIALOG_NO">No</x:String> <x:String x:Key="STRING_MENU_DIALOG_NO">No</x:String>
<x:String x:Key="STRING_MENU_DIALOG_CLOSE">Close</x:String>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -9,4 +9,5 @@
<x:String x:Key="STRING_MENU_DIALOG_CANCEL">取消</x:String> <x:String x:Key="STRING_MENU_DIALOG_CANCEL">取消</x:String>
<x:String x:Key="STRING_MENU_DIALOG_YES">是</x:String> <x:String x:Key="STRING_MENU_DIALOG_YES">是</x:String>
<x:String x:Key="STRING_MENU_DIALOG_NO">否</x:String> <x:String x:Key="STRING_MENU_DIALOG_NO">否</x:String>
<x:String x:Key="STRING_MENU_DIALOG_CLOSE">关闭</x:String>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -3,6 +3,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.GestureRecognizers;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Ursa.Common; using Ursa.Common;
@@ -22,8 +23,12 @@ public class DialogControl: ContentControl
internal HorizontalPosition HorizontalAnchor { get; set; } internal HorizontalPosition HorizontalAnchor { get; set; }
internal VerticalPosition VerticalAnchor { get; set; } internal VerticalPosition VerticalAnchor { get; set; }
internal double? InitialHorizontalOffset { get; set; } internal HorizontalPosition ActualHorizontalAnchor { get; set; }
internal double? InitialVerticalOffset { get; set; } internal VerticalPosition ActualVerticalAnchor { get; set; }
internal double? HorizontalOffset { get; set; }
internal double? VerticalOffset { get; set; }
internal double? HorizontalOffsetRatio { get; set; }
internal double? VerticalOffsetRatio { get; set; }
internal bool CanClickOnMaskToClose { get; set; } internal bool CanClickOnMaskToClose { get; set; }
public event EventHandler<DialogLayerChangeEventArgs>? LayerChanged; public event EventHandler<DialogLayerChangeEventArgs>? LayerChanged;
@@ -55,6 +60,7 @@ public class DialogControl: ContentControl
_titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove); _titleArea?.RemoveHandler(PointerMovedEvent, OnTitlePointerMove);
_titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed); _titleArea?.RemoveHandler(PointerPressedEvent, OnTitlePointerPressed);
_titleArea?.RemoveHandler(PointerReleasedEvent, OnTitlePointerRelease);
_closeButton = e.NameScope.Find<Button>(PART_CloseButton); _closeButton = e.NameScope.Find<Button>(PART_CloseButton);
_titleArea = e.NameScope.Find<Panel>(PART_TitleArea); _titleArea = e.NameScope.Find<Panel>(PART_TitleArea);
@@ -62,6 +68,7 @@ public class DialogControl: ContentControl
_titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble); _titleArea?.AddHandler(PointerMovedEvent, OnTitlePointerMove, RoutingStrategies.Bubble);
_titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble); _titleArea?.AddHandler(PointerPressedEvent, OnTitlePointerPressed, RoutingStrategies.Bubble);
_titleArea?.AddHandler(PointerReleasedEvent, OnTitlePointerRelease, RoutingStrategies.Bubble);
EventHelper.RegisterClickEvent(Close, _closeButton); EventHelper.RegisterClickEvent(Close, _closeButton);
} }
@@ -75,11 +82,16 @@ public class DialogControl: ContentControl
e.Source = this; e.Source = this;
} }
private void OnTitlePointerRelease(object sender, PointerReleasedEventArgs e)
{
e.Source = this;
}
public Task<T?> ShowAsync<T>(CancellationToken? token = default) public Task<T?> ShowAsync<T>(CancellationToken? token = default)
{ {
var tcs = new TaskCompletionSource<T?>(); var tcs = new TaskCompletionSource<T?>();
token?.Register(Close); token?.Register(CloseDialog);
void OnCloseHandler(object sender, object? args) void OnCloseHandler(object sender, object? args)
{ {
if (args is T result) if (args is T result)
@@ -137,7 +149,7 @@ public class DialogControl: ContentControl
PseudoClasses.Set(PC_Modal, modal); PseudoClasses.Set(PC_Modal, modal);
} }
public void Close() public void CloseDialog()
{ {
if (this.DataContext is IDialogContext context) if (this.DataContext is IDialogContext context)
{ {

View File

@@ -183,9 +183,11 @@ public static class OverlayDialog
if (options is null) options = new OverlayDialogOptions(); if (options is null) options = new OverlayDialogOptions();
control.HorizontalAnchor = options.HorizontalAnchor; control.HorizontalAnchor = options.HorizontalAnchor;
control.VerticalAnchor = options.VerticalAnchor; control.VerticalAnchor = options.VerticalAnchor;
control.InitialHorizontalOffset = control.ActualHorizontalAnchor = options.HorizontalAnchor;
control.ActualVerticalAnchor = options.VerticalAnchor;
control.HorizontalOffset =
control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset; control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset;
control.InitialVerticalOffset = control.VerticalOffset =
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset; options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose; control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
} }
@@ -195,9 +197,11 @@ public static class OverlayDialog
if (options is null) options = new OverlayDialogOptions(); if (options is null) options = new OverlayDialogOptions();
control.HorizontalAnchor = options.HorizontalAnchor; control.HorizontalAnchor = options.HorizontalAnchor;
control.VerticalAnchor = options.VerticalAnchor; control.VerticalAnchor = options.VerticalAnchor;
control.InitialHorizontalOffset = control.ActualHorizontalAnchor = options.HorizontalAnchor;
control.ActualVerticalAnchor = options.VerticalAnchor;
control.HorizontalOffset =
control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset; control.HorizontalAnchor == HorizontalPosition.Center ? null : options.HorizontalOffset;
control.InitialVerticalOffset = control.VerticalOffset =
options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset; options.VerticalAnchor == VerticalPosition.Center ? null : options.VerticalOffset;
control.CanClickOnMaskToClose = options.CanClickOnMaskToClose; control.CanClickOnMaskToClose = options.CanClickOnMaskToClose;
control.Mode = options.Mode; control.Mode = options.Mode;

View File

@@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Animation;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
@@ -21,6 +22,7 @@ public class OverlayDialogHost : Canvas
public DataTemplates DialogDataTemplates { get; set; } = new DataTemplates(); public DataTemplates DialogDataTemplates { get; set; } = new DataTemplates();
public Thickness SnapThickness { get; set; } = new Thickness(0);
public static readonly StyledProperty<IBrush?> OverlayMaskBrushProperty = public static readonly StyledProperty<IBrush?> OverlayMaskBrushProperty =
AvaloniaProperty.Register<OverlayDialogHost, IBrush?>( AvaloniaProperty.Register<OverlayDialogHost, IBrush?>(
@@ -56,7 +58,7 @@ public class OverlayDialogHost : Canvas
{ {
int i = _masks.IndexOf(border); int i = _masks.IndexOf(border);
DialogControl dialog = _modalDialogs[i]; DialogControl dialog = _modalDialogs[i];
dialog.Close(); dialog.CloseDialog();
border.RemoveHandler(PointerReleasedEvent, ClickBorderToCloseDialog); border.RemoveHandler(PointerReleasedEvent, ClickBorderToCloseDialog);
} }
} }
@@ -75,6 +77,44 @@ public class OverlayDialogHost : Canvas
_masks[i].Width = this.Bounds.Width; _masks[i].Width = this.Bounds.Width;
_masks[i].Height = this.Bounds.Height; _masks[i].Height = this.Bounds.Height;
} }
var oldSize = e.PreviousSize;
var newSize = e.NewSize;
foreach (var dialog in _dialogs)
{
ResetDialogPosition(dialog, oldSize, newSize);
}
foreach (var modalDialog in _modalDialogs)
{
ResetDialogPosition(modalDialog, oldSize, newSize);
}
}
private void ResetDialogPosition(DialogControl control, Size oldSize, Size newSize)
{
var width = newSize.Width - control.Bounds.Width;
var height = newSize.Height - control.Bounds.Height;
var newLeft = width * control.HorizontalOffsetRatio??0;
var newTop = height * control.VerticalOffsetRatio??0;
if(control.ActualHorizontalAnchor == HorizontalPosition.Left)
{
newLeft = 0;
}
if (control.ActualHorizontalAnchor == HorizontalPosition.Right)
{
newLeft = newSize.Width - control.Bounds.Width;
}
if (control.ActualVerticalAnchor == VerticalPosition.Top)
{
newTop = 0;
}
if (control.ActualVerticalAnchor == VerticalPosition.Bottom)
{
newTop = newSize.Height - control.Bounds.Height;
}
SetLeft(control, Math.Max(0.0, newLeft));
SetTop(control, Math.Max(0.0, newTop));
} }
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
@@ -85,7 +125,6 @@ public class OverlayDialogHost : Canvas
protected override void OnPointerMoved(PointerEventArgs e) protected override void OnPointerMoved(PointerEventArgs e)
{ {
base.OnPointerMoved(e);
if (e.Source is DialogControl item) if (e.Source is DialogControl item)
{ {
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
@@ -95,28 +134,35 @@ public class OverlayDialogHost : Canvas
var top = p.Y - _lastPoint.Y; var top = p.Y - _lastPoint.Y;
left = MathUtilities.Clamp(left, 0, Bounds.Width - item.Bounds.Width); left = MathUtilities.Clamp(left, 0, Bounds.Width - item.Bounds.Width);
top = MathUtilities.Clamp(top, 0, Bounds.Height - item.Bounds.Height); top = MathUtilities.Clamp(top, 0, Bounds.Height - item.Bounds.Height);
Canvas.SetLeft(item, left); SetLeft(item, left);
Canvas.SetTop(item, top); SetTop(item, top);
} }
} }
} }
protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerPressed(PointerPressedEventArgs e)
{ {
// base.OnPointerPressed(e);
if (e.Source is DialogControl item) if (e.Source is DialogControl item)
{ {
_lastPoint = e.GetPosition(item); _lastPoint = e.GetPosition(item);
} }
} }
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (e.Source is DialogControl item)
{
AnchorDialog(item);
}
}
internal void AddDialog(DialogControl control) internal void AddDialog(DialogControl control)
{ {
this.Children.Add(control); this.Children.Add(control);
_dialogs.Add(control); _dialogs.Add(control);
control.Measure(this.Bounds.Size); control.Measure(this.Bounds.Size);
control.Arrange(new Rect(control.DesiredSize)); control.Arrange(new Rect(control.DesiredSize));
SetToCenter(control); SetToPosition(control);
control.DialogControlClosing += OnDialogControlClosing; control.DialogControlClosing += OnDialogControlClosing;
control.LayerChanged += OnDialogLayerChanged; control.LayerChanged += OnDialogLayerChanged;
ResetZIndices(); ResetZIndices();
@@ -126,7 +172,7 @@ public class OverlayDialogHost : Canvas
{ {
if (sender is DialogControl control) if (sender is DialogControl control)
{ {
this.Children.Remove(control); Children.Remove(control);
control.DialogControlClosing -= OnDialogControlClosing; control.DialogControlClosing -= OnDialogControlClosing;
control.LayerChanged -= OnDialogLayerChanged; control.LayerChanged -= OnDialogLayerChanged;
if (_dialogs.Contains(control)) if (_dialogs.Contains(control))
@@ -170,7 +216,7 @@ public class OverlayDialogHost : Canvas
this.Children.Add(control); this.Children.Add(control);
control.Measure(this.Bounds.Size); control.Measure(this.Bounds.Size);
control.Arrange(new Rect(control.DesiredSize)); control.Arrange(new Rect(control.DesiredSize));
SetToCenter(control); SetToPosition(control);
control.DialogControlClosing += OnDialogControlClosing; control.DialogControlClosing += OnDialogControlClosing;
control.LayerChanged += OnDialogLayerChanged; control.LayerChanged += OnDialogLayerChanged;
} }
@@ -232,16 +278,105 @@ public class OverlayDialogHost : Canvas
} }
} }
private void SetToCenter(DialogControl? control) private void SetToPosition(DialogControl? control)
{ {
// return;
if (control is null) return; if (control is null) return;
double left = (this.Bounds.Width - control.Bounds.Width) / 2; double left = GetLeftPosition(control);
double top = (this.Bounds.Height - control.Bounds.Height) / 2; double top = GetTopPosition(control);
left = MathUtilities.Clamp(left, 0, Bounds.Width); SetLeft(control, left);
top = MathUtilities.Clamp(top, 0, Bounds.Height); SetTop(control, top);
Canvas.SetLeft(control, left); AnchorDialog(control);
Canvas.SetTop(control, top); }
private void AnchorDialog(DialogControl control)
{
control.ActualHorizontalAnchor = HorizontalPosition.Center;
control.ActualVerticalAnchor = VerticalPosition.Center;
double left = GetLeft(control);
double top = GetTop(control);
double right = Bounds.Width - left - control.Bounds.Width;
double bottom = Bounds.Height - top - control.Bounds.Height;
if(top < SnapThickness.Top)
{
SetTop(control, 0);
control.ActualVerticalAnchor = VerticalPosition.Top;
control.VerticalOffsetRatio = 0;
}
if(bottom > Bounds.Height - SnapThickness.Bottom)
{
SetTop(control, Bounds.Height - control.Bounds.Height);
control.ActualVerticalAnchor = VerticalPosition.Bottom;
control.VerticalOffsetRatio = 1;
}
if(left < SnapThickness.Left)
{
SetLeft(control, 0);
control.ActualHorizontalAnchor = HorizontalPosition.Left;
control.HorizontalOffsetRatio = 0;
}
if(right > Bounds.Width - SnapThickness.Right)
{
SetLeft(control, Bounds.Width - control.Bounds.Width);
control.ActualHorizontalAnchor = HorizontalPosition.Right;
control.HorizontalOffsetRatio = 1;
}
left = GetLeft(control);
top = GetTop(control);
right = Bounds.Width - left - control.Bounds.Width;
bottom = Bounds.Height - top - control.Bounds.Height;
control.HorizontalOffsetRatio = left / (left + right);
control.VerticalOffsetRatio = top / (top + bottom);
}
private double GetLeftPosition(DialogControl control)
{
double left = 0;
double offset = Math.Max(0, control.HorizontalOffset ?? 0);
left = this.Bounds.Width - control.Bounds.Width;
if (control.HorizontalAnchor == HorizontalPosition.Center)
{
left *= 0.5;
(double min, double max) = MathUtilities.GetMinMax(0, Bounds.Width * 0.5);
left = MathUtilities.Clamp(left, min, max);
}
else if (control.HorizontalAnchor == HorizontalPosition.Left)
{
(double min, double max) = MathUtilities.GetMinMax(0, offset);
left = MathUtilities.Clamp(left, min, max);
}
else if (control.HorizontalAnchor == HorizontalPosition.Right)
{
double leftOffset = Bounds.Width - control.Bounds.Width - offset;
leftOffset = Math.Max(0, leftOffset);
if(control.HorizontalOffset.HasValue)
{
left = MathUtilities.Clamp(left, 0, leftOffset);
}
}
return left;
}
private double GetTopPosition(DialogControl control)
{
double top = 0;
double offset = Math.Max(0, control.VerticalOffset ?? 0);
top = this.Bounds.Height - control.Bounds.Height;
if (control.VerticalAnchor == VerticalPosition.Center)
{
top *= 0.5;
(double min, double max) = MathUtilities.GetMinMax(0, Bounds.Height * 0.5);
top = MathUtilities.Clamp(top, min, max);
}
else if (control.VerticalAnchor == VerticalPosition.Top)
{
top = MathUtilities.Clamp(top, 0, offset);
}
else if (control.VerticalAnchor == VerticalPosition.Bottom)
{
var topOffset = Math.Max(0, Bounds.Height - control.Bounds.Height - offset);
top = MathUtilities.Clamp(top, 0, topOffset);
}
return top;
} }
internal IDataTemplate? GetDataTemplate(object? o) internal IDataTemplate? GetDataTemplate(object? o)