committed by
GitHub
125 changed files with 3065 additions and 864 deletions
@ -0,0 +1,222 @@ |
|||
<UserControl xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|||
d:DesignHeight="800" |
|||
d:DesignWidth="400" |
|||
x:Class="ControlCatalog.Pages.ScrollSnapPage" |
|||
xmlns:pages="using:ControlCatalog.Pages" |
|||
x:DataType="pages:ScrollSnapPageViewModel"> |
|||
<StackPanel Orientation="Vertical" Spacing="4"> |
|||
<TextBlock TextWrapping="Wrap" |
|||
Classes="h2">Scrollviewer can snap supported content both vertically and horizontally. Snapping occurs from scrolling with touch or pen, or using the pointer wheel.</TextBlock> |
|||
|
|||
<Grid RowDefinitions="Auto, Auto, Auto, Auto, Auto"> |
|||
<StackPanel Orientation="Horizontal" |
|||
Spacing="4"> |
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="Snap Point Type" /> |
|||
<ComboBox Items="{Binding AvailableSnapPointsType}" |
|||
SelectedItem="{Binding SnapPointsType}" /> |
|||
</StackPanel> |
|||
|
|||
<StackPanel Orientation="Vertical" |
|||
Spacing="4"> |
|||
<TextBlock Text="Snap Point Alignment" /> |
|||
<ComboBox Items="{Binding AvailableSnapPointsAlignment}" |
|||
SelectedItem="{Binding SnapPointsAlignment}" /> |
|||
</StackPanel> |
|||
|
|||
<ToggleSwitch IsChecked="{Binding AreSnapPointsRegular}" |
|||
OffContent="No" |
|||
OnContent="Yes" |
|||
Content="Are Snap Points regular?" /> |
|||
</StackPanel> |
|||
<TextBlock TextWrapping="Wrap" |
|||
Grid.Row="1" |
|||
Margin="0,10" |
|||
Classes="h2">Vertical Snapping</TextBlock> |
|||
|
|||
<Border |
|||
BorderBrush="Green" |
|||
BorderThickness="1" |
|||
Padding="0" |
|||
Grid.Row="2" |
|||
Margin="10, 5"> |
|||
<ScrollViewer x:Name="VerticalSnapsScrollViewer" |
|||
VerticalSnapPointsType="{Binding SnapPointsType}" |
|||
VerticalSnapPointsAlignment="{Binding SnapPointsAlignment}" |
|||
HorizontalAlignment="Stretch" |
|||
Height="350" |
|||
HorizontalScrollBarVisibility="Disabled"> |
|||
<StackPanel AreVerticalSnapPointsRegular="{Binding AreSnapPointsRegular}" |
|||
Orientation="Vertical" |
|||
HorizontalAlignment="Stretch"> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 1"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 2"/> |
|||
</Border> |
|||
<Border Padding="5, 20" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 3"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 4"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 5"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 6"/> |
|||
</Border> |
|||
<Border Padding="5,8" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 7"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 8"/> |
|||
</Border> |
|||
<Border Padding="5,4" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 9"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 20"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 11"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
Text="Child 12"/> |
|||
</Border> |
|||
</StackPanel> |
|||
</ScrollViewer> |
|||
</Border> |
|||
<TextBlock TextWrapping="Wrap" |
|||
Grid.Row="3" |
|||
Margin="0,10" |
|||
Classes="h2">Horizontal Snapping</TextBlock> |
|||
<Border |
|||
BorderBrush="Green" |
|||
BorderThickness="1" |
|||
Padding="0" |
|||
Grid.Row="4" |
|||
Margin="10, 10"> |
|||
<ScrollViewer x:Name="HorizontalSnapsScrollViewer" |
|||
HorizontalSnapPointsType="{Binding SnapPointsType}" |
|||
HorizontalSnapPointsAlignment="{Binding SnapPointsAlignment}" |
|||
HorizontalAlignment="Stretch" |
|||
Height="350" |
|||
HorizontalScrollBarVisibility="Auto" |
|||
VerticalScrollBarVisibility="Disabled"> |
|||
<StackPanel AreHorizontalSnapPointsRegular="{Binding AreSnapPointsRegular}" |
|||
Orientation="Horizontal" |
|||
HorizontalAlignment="Stretch"> |
|||
<Border Padding="5, 30" |
|||
Width="300" |
|||
BorderBrush="Red" |
|||
HorizontalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
VerticalAlignment="Center" |
|||
Text="Child 1"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
Width="300" |
|||
BorderBrush="Red" |
|||
VerticalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
VerticalAlignment="Center" |
|||
Text="Child 2"/> |
|||
</Border> |
|||
<Border Padding="5, 20" |
|||
Width="300" |
|||
BorderBrush="Red" |
|||
VerticalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
VerticalAlignment="Center" |
|||
Text="Child 3"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
Width="300" |
|||
BorderBrush="Red" |
|||
VerticalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
VerticalAlignment="Center" |
|||
Text="Child 4"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
Width="300" |
|||
BorderBrush="Red" |
|||
VerticalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
VerticalAlignment="Center" |
|||
Text="Child 5"/> |
|||
</Border> |
|||
<Border Padding="5, 30" |
|||
Width="300" |
|||
BorderBrush="Red" |
|||
VerticalAlignment="Stretch" |
|||
BorderThickness="1"> |
|||
<TextBlock FontWeight="Bold" |
|||
VerticalAlignment="Center" |
|||
Text="Child 6"/> |
|||
</Border> |
|||
|
|||
</StackPanel> |
|||
</ScrollViewer> |
|||
</Border> |
|||
</Grid> |
|||
</StackPanel> |
|||
</UserControl> |
|||
@ -0,0 +1,68 @@ |
|||
using System.Collections.Generic; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Primitives; |
|||
using Avalonia.Markup.Xaml; |
|||
using MiniMvvm; |
|||
|
|||
namespace ControlCatalog.Pages |
|||
{ |
|||
public class ScrollSnapPageViewModel : ViewModelBase |
|||
{ |
|||
private SnapPointsType _snapPointsType; |
|||
private SnapPointsAlignment _snapPointsAlignment; |
|||
private bool _areSnapPointsRegular; |
|||
|
|||
public ScrollSnapPageViewModel() |
|||
{ |
|||
|
|||
AvailableSnapPointsType = new List<SnapPointsType>() |
|||
{ |
|||
SnapPointsType.None, |
|||
SnapPointsType.Mandatory, |
|||
SnapPointsType.MandatorySingle |
|||
}; |
|||
|
|||
AvailableSnapPointsAlignment = new List<SnapPointsAlignment>() |
|||
{ |
|||
SnapPointsAlignment.Near, |
|||
SnapPointsAlignment.Center, |
|||
SnapPointsAlignment.Far, |
|||
}; |
|||
} |
|||
|
|||
public bool AreSnapPointsRegular |
|||
{ |
|||
get => _areSnapPointsRegular; |
|||
set => this.RaiseAndSetIfChanged(ref _areSnapPointsRegular, value); |
|||
} |
|||
|
|||
public SnapPointsType SnapPointsType |
|||
{ |
|||
get => _snapPointsType; |
|||
set => this.RaiseAndSetIfChanged(ref _snapPointsType, value); |
|||
} |
|||
|
|||
public SnapPointsAlignment SnapPointsAlignment |
|||
{ |
|||
get => _snapPointsAlignment; |
|||
set => this.RaiseAndSetIfChanged(ref _snapPointsAlignment, value); |
|||
} |
|||
public List<SnapPointsType> AvailableSnapPointsType { get; } |
|||
public List<SnapPointsAlignment> AvailableSnapPointsAlignment { get; } |
|||
} |
|||
|
|||
public class ScrollSnapPage : UserControl |
|||
{ |
|||
public ScrollSnapPage() |
|||
{ |
|||
this.InitializeComponent(); |
|||
|
|||
DataContext = new ScrollSnapPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
} |
|||
@ -1,11 +1,14 @@ |
|||
using System; |
|||
using Android.App; |
|||
using Android.Content; |
|||
using Android.Content.PM; |
|||
|
|||
namespace Avalonia.Android |
|||
{ |
|||
public interface IActivityResultHandler |
|||
{ |
|||
public Action<int, Result, Intent> ActivityResult { get; set; } |
|||
|
|||
public Action<int, string[], Permission[]> RequestPermissionsResult { get; set; } |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,52 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Android.App; |
|||
using Android.Content; |
|||
using Android.Content.PM; |
|||
|
|||
namespace Avalonia.Android.Platform; |
|||
|
|||
internal static class PlatformSupport |
|||
{ |
|||
private static int s_lastRequestCode = 20000; |
|||
|
|||
public static int GetNextRequestCode() => s_lastRequestCode++; |
|||
|
|||
public static async Task<bool> CheckPermission(this Activity activity, string permission) |
|||
{ |
|||
if (activity is not IActivityResultHandler mainActivity) |
|||
{ |
|||
throw new InvalidOperationException("Main activity must implement IActivityResultHandler interface."); |
|||
} |
|||
|
|||
if (!OperatingSystem.IsAndroidVersionAtLeast(23)) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
if (activity.CheckSelfPermission(permission) == Permission.Granted) |
|||
{ |
|||
return true; |
|||
} |
|||
|
|||
var currentRequestCode = GetNextRequestCode(); |
|||
var tcs = new TaskCompletionSource<bool>(); |
|||
mainActivity.RequestPermissionsResult += RequestPermissionsResult; |
|||
activity.RequestPermissions(new [] { permission }, currentRequestCode); |
|||
|
|||
return await tcs.Task; |
|||
|
|||
void RequestPermissionsResult(int requestCode, string[] arg2, Permission[] arg3) |
|||
{ |
|||
if (currentRequestCode != requestCode) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
mainActivity.RequestPermissionsResult -= RequestPermissionsResult; |
|||
|
|||
_ = tcs.TrySetResult(arg3.All(p => p == Permission.Granted)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,6 @@ |
|||
namespace Avalonia.Platform.Storage; |
|||
|
|||
public class NameCollisionOption |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
using System.Threading.Tasks; |
|||
using Avalonia.Platform.Storage.FileIO; |
|||
|
|||
namespace Avalonia.Platform.Storage; |
|||
|
|||
/// <summary>
|
|||
/// Group of public extensions for <see cref="IStorageProvider"/> class.
|
|||
/// </summary>
|
|||
public static class StorageProviderExtensions |
|||
{ |
|||
/// <inheritdoc cref="IStorageProvider.TryGetFileFromPath"/>
|
|||
public static Task<IStorageFile?> TryGetFileFromPath(this IStorageProvider provider, string filePath) |
|||
{ |
|||
return provider.TryGetFileFromPath(StorageProviderHelpers.FilePathToUri(filePath)); |
|||
} |
|||
|
|||
/// <inheritdoc cref="IStorageProvider.TryGetFolderFromPath"/>
|
|||
public static Task<IStorageFolder?> TryGetFolderFromPath(this IStorageProvider provider, string folderPath) |
|||
{ |
|||
return provider.TryGetFolderFromPath(StorageProviderHelpers.FilePathToUri(folderPath)); |
|||
} |
|||
|
|||
internal static string? TryGetFullPath(this IStorageFolder folder) |
|||
{ |
|||
// We can avoid double escaping of the path by checking for BclStorageFolder.
|
|||
// Ideally, `folder.Path.LocalPath` should also work, as that's only available way for the users.
|
|||
if (folder is BclStorageFolder storageFolder) |
|||
{ |
|||
return storageFolder.DirectoryInfo.FullName; |
|||
} |
|||
|
|||
if (folder.Path is { IsAbsoluteUri: true, Scheme: "file" } absolutePath) |
|||
{ |
|||
return absolutePath.LocalPath; |
|||
} |
|||
|
|||
// android "content:", browser and ios relative links go here.
|
|||
return null; |
|||
} |
|||
|
|||
internal static string? TryGetFullPath(this IStorageFile file) |
|||
{ |
|||
if (file is BclStorageFile storageFolder) |
|||
{ |
|||
return storageFolder.FileInfo.FullName; |
|||
} |
|||
|
|||
if (file.Path is { IsAbsoluteUri: true, Scheme: "file" } absolutePath) |
|||
{ |
|||
return absolutePath.LocalPath; |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
@ -0,0 +1,37 @@ |
|||
namespace Avalonia.Platform.Storage; |
|||
|
|||
/// <summary>
|
|||
/// Specifies enumerated constants used to retrieve directory paths to system well known folders.
|
|||
/// </summary>
|
|||
public enum WellKnownFolder |
|||
{ |
|||
/// <summary>
|
|||
/// Current user desktop folder.
|
|||
/// </summary>
|
|||
Desktop, |
|||
|
|||
/// <summary>
|
|||
/// Current user documents folder.
|
|||
/// </summary>
|
|||
Documents, |
|||
|
|||
/// <summary>
|
|||
/// Current user downloads folder.
|
|||
/// </summary>
|
|||
Downloads, |
|||
|
|||
/// <summary>
|
|||
/// Current user music folder
|
|||
/// </summary>
|
|||
Music, |
|||
|
|||
/// <summary>
|
|||
/// Current user pictures folder
|
|||
/// </summary>
|
|||
Pictures, |
|||
|
|||
/// <summary>
|
|||
/// Current user videos folder
|
|||
/// </summary>
|
|||
Videos, |
|||
} |
|||
@ -1,250 +0,0 @@ |
|||
using System; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using System.Reflection; |
|||
using Avalonia.Data; |
|||
using Avalonia.PropertyStore; |
|||
using Avalonia.Reactive; |
|||
using Avalonia.Styling; |
|||
using Avalonia.Utilities; |
|||
|
|||
namespace Avalonia |
|||
{ |
|||
/// <summary>
|
|||
/// Base class for styled properties.
|
|||
/// </summary>
|
|||
public abstract class StyledPropertyBase<TValue> : AvaloniaProperty<TValue>, IStyledPropertyAccessor |
|||
{ |
|||
private readonly bool _inherits; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="StyledPropertyBase{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="name">The name of the property.</param>
|
|||
/// <param name="ownerType">The type of the class that registers the property.</param>
|
|||
/// <param name="metadata">The property metadata.</param>
|
|||
/// <param name="inherits">Whether the property inherits its value.</param>
|
|||
/// <param name="validate">A value validation callback.</param>
|
|||
/// <param name="notifying">A <see cref="AvaloniaProperty.Notifying"/> callback.</param>
|
|||
protected StyledPropertyBase( |
|||
string name, |
|||
Type ownerType, |
|||
StyledPropertyMetadata<TValue> metadata, |
|||
bool inherits = false, |
|||
Func<TValue, bool>? validate = null, |
|||
Action<AvaloniaObject, bool>? notifying = null) |
|||
: base(name, ownerType, metadata, notifying) |
|||
{ |
|||
_inherits = inherits; |
|||
ValidateValue = validate; |
|||
HasCoercion |= metadata.CoerceValue != null; |
|||
|
|||
if (validate?.Invoke(metadata.DefaultValue) == false) |
|||
{ |
|||
throw new ArgumentException( |
|||
$"'{metadata.DefaultValue}' is not a valid default value for '{name}'."); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="StyledPropertyBase{T}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="source">The property to add the owner to.</param>
|
|||
/// <param name="ownerType">The type of the class that registers the property.</param>
|
|||
protected StyledPropertyBase(StyledPropertyBase<TValue> source, Type ownerType) |
|||
: base(source, ownerType, null) |
|||
{ |
|||
_inherits = source.Inherits; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether the property inherits its value.
|
|||
/// </summary>
|
|||
/// <value>
|
|||
/// A value indicating whether the property inherits its value.
|
|||
/// </value>
|
|||
public override bool Inherits => _inherits; |
|||
|
|||
/// <summary>
|
|||
/// Gets the value validation callback for the property.
|
|||
/// </summary>
|
|||
public Func<TValue, bool>? ValidateValue { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets a value indicating whether this property has any value coercion callbacks defined
|
|||
/// in its metadata.
|
|||
/// </summary>
|
|||
internal bool HasCoercion { get; private set; } |
|||
|
|||
public TValue CoerceValue(AvaloniaObject instance, TValue baseValue) |
|||
{ |
|||
var metadata = GetMetadata(instance.GetType()); |
|||
|
|||
if (metadata.CoerceValue != null) |
|||
{ |
|||
return metadata.CoerceValue.Invoke(instance, baseValue); |
|||
} |
|||
|
|||
return baseValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the default value for the property on the specified type.
|
|||
/// </summary>
|
|||
/// <param name="type">The type.</param>
|
|||
/// <returns>The default value.</returns>
|
|||
public TValue GetDefaultValue(Type type) |
|||
{ |
|||
return GetMetadata(type).DefaultValue; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the property metadata for the specified type.
|
|||
/// </summary>
|
|||
/// <param name="type">The type.</param>
|
|||
/// <returns>
|
|||
/// The property metadata.
|
|||
/// </returns>
|
|||
public new StyledPropertyMetadata<TValue> GetMetadata(Type type) |
|||
{ |
|||
_ = type ?? throw new ArgumentNullException(nameof(type)); |
|||
return (StyledPropertyMetadata<TValue>)base.GetMetadata(type); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overrides the default value for the property on the specified type.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type.</typeparam>
|
|||
/// <param name="defaultValue">The default value.</param>
|
|||
public void OverrideDefaultValue<T>(TValue defaultValue) where T : AvaloniaObject |
|||
{ |
|||
OverrideDefaultValue(typeof(T), defaultValue); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overrides the default value for the property on the specified type.
|
|||
/// </summary>
|
|||
/// <param name="type">The type.</param>
|
|||
/// <param name="defaultValue">The default value.</param>
|
|||
public void OverrideDefaultValue(Type type, TValue defaultValue) |
|||
{ |
|||
OverrideMetadata(type, new StyledPropertyMetadata<TValue>(defaultValue)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overrides the metadata for the property on the specified type.
|
|||
/// </summary>
|
|||
/// <typeparam name="T">The type.</typeparam>
|
|||
/// <param name="metadata">The metadata.</param>
|
|||
public void OverrideMetadata<T>(StyledPropertyMetadata<TValue> metadata) where T : AvaloniaObject |
|||
{ |
|||
base.OverrideMetadata(typeof(T), metadata); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Overrides the metadata for the property on the specified type.
|
|||
/// </summary>
|
|||
/// <param name="type">The type.</param>
|
|||
/// <param name="metadata">The metadata.</param>
|
|||
public void OverrideMetadata(Type type, StyledPropertyMetadata<TValue> metadata) |
|||
{ |
|||
if (ValidateValue != null) |
|||
{ |
|||
if (!ValidateValue(metadata.DefaultValue)) |
|||
{ |
|||
throw new ArgumentException( |
|||
$"'{metadata.DefaultValue}' is not a valid default value for '{Name}'."); |
|||
} |
|||
} |
|||
|
|||
HasCoercion |= metadata.CoerceValue != null; |
|||
|
|||
base.OverrideMetadata(type, metadata); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the string representation of the property.
|
|||
/// </summary>
|
|||
/// <returns>The property's string representation.</returns>
|
|||
public override string ToString() |
|||
{ |
|||
return Name; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
object? IStyledPropertyAccessor.GetDefaultValue(Type type) => GetDefaultBoxedValue(type); |
|||
|
|||
bool IStyledPropertyAccessor.ValidateValue(object? value) |
|||
{ |
|||
if (value is null && !typeof(TValue).IsValueType) |
|||
return ValidateValue?.Invoke(default!) ?? true; |
|||
if (value is TValue typed) |
|||
return ValidateValue?.Invoke(typed) ?? true; |
|||
return false; |
|||
} |
|||
|
|||
internal override EffectiveValue CreateEffectiveValue(AvaloniaObject o) |
|||
{ |
|||
return new EffectiveValue<TValue>(o, this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
internal override void RouteClearValue(AvaloniaObject o) |
|||
{ |
|||
o.ClearValue<TValue>(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
internal override object? RouteGetValue(AvaloniaObject o) |
|||
{ |
|||
return o.GetValue<TValue>(this); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
internal override object? RouteGetBaseValue(AvaloniaObject o) |
|||
{ |
|||
var value = o.GetBaseValue<TValue>(this); |
|||
return value.HasValue ? value.Value : AvaloniaProperty.UnsetValue; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[UnconditionalSuppressMessage("Trimming", "IL2026", Justification = TrimmingMessages.ImplicitTypeConvertionSupressWarningMessage)] |
|||
internal override IDisposable? RouteSetValue( |
|||
AvaloniaObject target, |
|||
object? value, |
|||
BindingPriority priority) |
|||
{ |
|||
if (value == BindingOperations.DoNothing) |
|||
{ |
|||
return null; |
|||
} |
|||
else if (value == UnsetValue) |
|||
{ |
|||
target.ClearValue(this); |
|||
return null; |
|||
} |
|||
else if (TypeUtilities.TryConvertImplicit(PropertyType, value, out var converted)) |
|||
{ |
|||
return target.SetValue<TValue>(this, (TValue)converted!, priority); |
|||
} |
|||
else |
|||
{ |
|||
var type = value?.GetType().FullName ?? "(null)"; |
|||
throw new ArgumentException($"Invalid value for Property '{Name}': '{value}' ({type})"); |
|||
} |
|||
} |
|||
|
|||
internal override IDisposable RouteBind( |
|||
AvaloniaObject target, |
|||
IObservable<object?> source, |
|||
BindingPriority priority) |
|||
{ |
|||
return target.Bind<TValue>(this, source, priority); |
|||
} |
|||
|
|||
private object? GetDefaultBoxedValue(Type type) |
|||
{ |
|||
_ = type ?? throw new ArgumentNullException(nameof(type)); |
|||
return GetMetadata(type).DefaultValue; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Avalonia.Interactivity; |
|||
using Avalonia.Layout; |
|||
|
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
/// <summary>
|
|||
/// Describes snap point behavior for objects that contain and present items.
|
|||
/// </summary>
|
|||
public interface IScrollSnapPointsInfo |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets a value that indicates whether the horizontal snap points for the container are equidistant from each other.
|
|||
/// </summary>
|
|||
bool AreHorizontalSnapPointsRegular { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value that indicates whether the vertical snap points for the container are equidistant from each other.
|
|||
/// </summary>
|
|||
bool AreVerticalSnapPointsRegular { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Returns the set of distances between irregular snap points for a specified orientation and alignment.
|
|||
/// </summary>
|
|||
/// <param name="orientation">The orientation for the desired snap point set.</param>
|
|||
/// <param name="snapPointsAlignment">The alignment to use when applying the snap points.</param>
|
|||
/// <returns>The read-only collection of snap point distances. Returns an empty collection when no snap points are present.</returns>
|
|||
IReadOnlyList<double> GetIrregularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment); |
|||
|
|||
/// <summary>
|
|||
/// Gets the distance between regular snap points for a specified orientation and alignment.
|
|||
/// </summary>
|
|||
/// <param name="orientation">The orientation for the desired snap point set.</param>
|
|||
/// <param name="snapPointsAlignment">The alignment to use when applying the snap points.</param>
|
|||
/// <param name="offset">Out parameter. The offset of the first snap point.</param>
|
|||
/// <returns>The distance between the equidistant snap points. Returns 0 when no snap points are present.</returns>
|
|||
double GetRegularSnapPoints(Orientation orientation, SnapPointsAlignment snapPointsAlignment, out double offset); |
|||
|
|||
/// <summary>
|
|||
/// Occurs when the measurements for horizontal snap points change.
|
|||
/// </summary>
|
|||
event EventHandler<RoutedEventArgs> HorizontalSnapPointsChanged; |
|||
|
|||
/// <summary>
|
|||
/// Occurs when the measurements for vertical snap points change.
|
|||
/// </summary>
|
|||
event EventHandler<RoutedEventArgs> VerticalSnapPointsChanged; |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
/// <summary>
|
|||
/// Specify options for snap point alignment relative to an edge. Which edge depends on the orientation of the object where the alignment is applied
|
|||
/// </summary>
|
|||
public enum SnapPointsAlignment |
|||
{ |
|||
/// <summary>
|
|||
/// Use snap points grouped closer to the orientation edge.
|
|||
/// </summary>
|
|||
Near, |
|||
|
|||
/// <summary>
|
|||
/// Use snap points that are centered in the orientation.
|
|||
/// </summary>
|
|||
Center, |
|||
|
|||
/// <summary>
|
|||
/// Use snap points grouped farther from the orientation edge.
|
|||
/// </summary>
|
|||
Far |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
/// <summary>
|
|||
/// Specify how panning snap points are processed for gesture input.
|
|||
/// </summary>
|
|||
public enum SnapPointsType |
|||
{ |
|||
/// <summary>
|
|||
/// No snapping behavior.
|
|||
/// </summary>
|
|||
None, |
|||
|
|||
/// <summary>
|
|||
/// Content always stops at the snap point closest to where inertia would naturally stop along the direction of inertia.
|
|||
/// </summary>
|
|||
Mandatory, |
|||
|
|||
/// <summary>
|
|||
/// Content always stops at the snap point closest to the release point along the direction of inertia.
|
|||
/// </summary>
|
|||
MandatorySingle |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue