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 System; |
||||
using Android.App; |
using Android.App; |
||||
using Android.Content; |
using Android.Content; |
||||
|
using Android.Content.PM; |
||||
|
|
||||
namespace Avalonia.Android |
namespace Avalonia.Android |
||||
{ |
{ |
||||
public interface IActivityResultHandler |
public interface IActivityResultHandler |
||||
{ |
{ |
||||
public Action<int, Result, Intent> ActivityResult { get; set; } |
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