Add project files.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>TheXamlGuy.UI.Avalonia.Controls</RootNamespace>
|
||||
<AssemblyName>TheXamlGuy.UI.Avalonia.Controls</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.0-preview3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UI\UI.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,66 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Platform.Storage;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia.Controls
|
||||
{
|
||||
public class FilePickerFilePickedEventArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
public class FilePicker : TemplatedControl
|
||||
{
|
||||
public static readonly StyledProperty<bool> AllowMultipleProperty =
|
||||
AvaloniaProperty.Register<FilePicker, bool>(nameof(AllowMultiple));
|
||||
|
||||
public static readonly StyledProperty<IReadOnlyList<FilePickerFileType>?> FileTypeFilterProperty =
|
||||
AvaloniaProperty.Register<FilePicker, IReadOnlyList<FilePickerFileType>?>(nameof(FileTypeFilter));
|
||||
|
||||
public static readonly StyledProperty<IStorageFolder?> SuggestedStartLocationProperty =
|
||||
AvaloniaProperty.Register<FilePicker, IStorageFolder?>(nameof(SuggestedStartLocation));
|
||||
|
||||
public static readonly StyledProperty<string?> TitleProperty =
|
||||
AvaloniaProperty.Register<FilePicker, string?>(nameof(Title));
|
||||
|
||||
public bool AllowMultiple
|
||||
{
|
||||
get { return GetValue(AllowMultipleProperty); }
|
||||
set { SetValue(AllowMultipleProperty, value); }
|
||||
}
|
||||
|
||||
public IReadOnlyList<FilePickerFileType>? FileTypeFilter
|
||||
{
|
||||
get { return GetValue(FileTypeFilterProperty); }
|
||||
set { SetValue(FileTypeFilterProperty, value); }
|
||||
}
|
||||
|
||||
public IStorageFolder? SuggestedStartLocation
|
||||
{
|
||||
get { return GetValue(SuggestedStartLocationProperty); }
|
||||
set { SetValue(SuggestedStartLocationProperty, value); }
|
||||
}
|
||||
|
||||
public string? Title
|
||||
{
|
||||
get { return GetValue(TitleProperty); }
|
||||
set { SetValue(TitleProperty, value); }
|
||||
}
|
||||
|
||||
public event TypedEventHandler<FilePicker, FilePickerFilePickedEventArgs>? FilePicked;
|
||||
|
||||
public async void Open()
|
||||
{
|
||||
if (VisualRoot is Window window)
|
||||
{
|
||||
IReadOnlyList<IStorageFile> files = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
AllowMultiple = AllowMultiple,
|
||||
FileTypeFilter = FileTypeFilter,
|
||||
SuggestedStartLocation = SuggestedStartLocation,
|
||||
Title = Title
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>TheXamlGuy.UI.Avalonia</RootNamespace>
|
||||
<AssemblyName>TheXamlGuy.UI.Avalonia</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="11.0.0-preview3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UI\UI.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="FluentAvalonia">
|
||||
<HintPath>References\FluentAvalonia.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,11 @@
|
||||
using Avalonia.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia;
|
||||
|
||||
public static class MarkupExtensions
|
||||
{
|
||||
public static Binding ToBinding(this object value)
|
||||
{
|
||||
return value is Binding binding ? binding : new Binding() { Mode = BindingMode.OneWay, Source = value };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Data;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia;
|
||||
|
||||
public class ChangePropertyExtension : TriggerExtension
|
||||
{
|
||||
private static readonly AvaloniaProperty PropertyTargetProperty =
|
||||
AvaloniaProperty.RegisterAttached<ChangePropertyExtension, Control, object>("PropertyTarget");
|
||||
|
||||
private static readonly AvaloniaProperty PropertyValueProperty =
|
||||
AvaloniaProperty.RegisterAttached<ChangePropertyExtension, Control, object>("PropertyValue");
|
||||
|
||||
private readonly string name;
|
||||
|
||||
private readonly BindingBase targetBinding;
|
||||
private readonly BindingBase valueBinding;
|
||||
|
||||
public ChangePropertyExtension(object target, string name, object value)
|
||||
{
|
||||
this.targetBinding = target is BindingBase targetBinding ? targetBinding : target.ToBinding();
|
||||
this.valueBinding = value is BindingBase valueBinding ? valueBinding : value.ToBinding();
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
TargetObject?.Bind(PropertyTargetProperty, targetBinding);
|
||||
if (TargetObject?.GetValue(PropertyTargetProperty) is { } target)
|
||||
{
|
||||
Type? targetType = target.GetType();
|
||||
|
||||
if (targetType.GetProperty(name) is PropertyInfo propertyInfo)
|
||||
{
|
||||
TargetObject?.Bind(PropertyValueProperty, valueBinding);
|
||||
object? value = TargetObject?.GetValue(PropertyValueProperty);
|
||||
|
||||
TypeConverter? converter = TypeConverterHelper.GetTypeConverter(propertyInfo.PropertyType);
|
||||
object? newValue = value;
|
||||
|
||||
if (value is not null)
|
||||
{
|
||||
if (converter?.CanConvertFrom(value.GetType()) == true)
|
||||
{
|
||||
newValue = converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (converter?.CanConvertTo(propertyInfo.PropertyType) == true)
|
||||
{
|
||||
newValue = converter.ConvertTo(null, CultureInfo.InvariantCulture, value, propertyInfo.PropertyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target is TemplatedControl control )
|
||||
{
|
||||
if (AvaloniaPropertyRegistry.Instance.FindRegistered(targetType, name) is AvaloniaProperty property)
|
||||
{
|
||||
control.SetValue(property, newValue);
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType == typeof(Classes))
|
||||
{
|
||||
control.Classes.Clear();
|
||||
control.Classes.Add($"{newValue}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyInfo?.SetValue(target, newValue, Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,320 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia;
|
||||
|
||||
public class CompositeExtension : TriggerExtension
|
||||
{
|
||||
[ConstructorArgument(nameof(Triggers))]
|
||||
public TriggerCollection Triggers { get; } = new TriggerCollection();
|
||||
|
||||
public CompositeExtension(object args0)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0, object args1, object args2, object args3, object args4,
|
||||
object args5, object args6, object args7, object args8, object args9, object args10)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0, object args1, object args2, object args3, object args4,
|
||||
object args5, object args6, object args7, object args8, object args9, object args10, object args11)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
Triggers.Add(args13);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
Triggers.Add(args13);
|
||||
Triggers.Add(args14);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14,
|
||||
object args15)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
Triggers.Add(args13);
|
||||
Triggers.Add(args14);
|
||||
Triggers.Add(args15);
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
foreach (Delegate? trigger in Triggers)
|
||||
{
|
||||
trigger.Method.Invoke(trigger.Target, new object[] { sender, args });
|
||||
}
|
||||
|
||||
base.OnInvoked(sender, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia;
|
||||
|
||||
[ConstructorArgument(nameof(name))]
|
||||
public class InvokeExtension : TriggerExtension
|
||||
{
|
||||
private static readonly AvaloniaProperty TargetProperty =
|
||||
AvaloniaProperty.RegisterAttached<InvokeExtension, Control, object>("Target");
|
||||
|
||||
private readonly object name;
|
||||
private readonly List<object> parameters = new();
|
||||
|
||||
public InvokeExtension(object name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
|
||||
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14,
|
||||
object args15)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
|
||||
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
|
||||
parameters.Add(args15 is MarkupExtension ? args15 : args15.ToBinding());
|
||||
}
|
||||
|
||||
// KEEP THIS
|
||||
//protected override void OnAttached(IServiceProvider serviceProvider)
|
||||
//{
|
||||
// if (name.StartsWith("$"))
|
||||
// {
|
||||
// if (serviceProvider is ITypeDescriptorContext typeDescriptorContext)
|
||||
// {
|
||||
// targetBinding = new(name) { DefaultAnchor = new WeakReference(TargetObject) };
|
||||
// if (serviceProvider.GetService(typeof(INameScope)) is INameScope nameScope)
|
||||
// {
|
||||
// targetBinding.NameScope = new WeakReference<INameScope>(nameScope);
|
||||
// }
|
||||
|
||||
// if (typeDescriptorContext.GetService(typeof(IXamlTypeResolver)) is IXamlTypeResolver xamlTypeResolver)
|
||||
// {
|
||||
// targetBinding.TypeResolver = (prefix, type) =>
|
||||
// {
|
||||
// string name = string.IsNullOrEmpty(prefix) ? type : $"{prefix}:{type}";
|
||||
// return xamlTypeResolver.Resolve(name);
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// base.OnAttached(serviceProvider);
|
||||
//}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
if (sender is AvaloniaObject avaloniaObject)
|
||||
{
|
||||
CreaterHandler(avaloniaObject, args);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreaterHandler(AvaloniaObject sender, EventArgs args)
|
||||
{
|
||||
if (TryGetInvoke(sender, out (object? Target, MethodInfo? MethodInfo) invoker))
|
||||
{
|
||||
if (invoker.Target is object target)
|
||||
{
|
||||
if (invoker.MethodInfo is MethodInfo methodInfo)
|
||||
{
|
||||
ParameterInfo[] parameterInfo = methodInfo.GetParameters();
|
||||
List<object> parameters = new();
|
||||
|
||||
//foreach (object? parameter in this.parameters)
|
||||
//{
|
||||
// switch (parameter)
|
||||
// {
|
||||
// case IParameter keyedParameter:
|
||||
// BindingOperations.SetBinding(sender, ParameterProperty, parameter.ToBinding());
|
||||
// parameters.Add(new KeyValuePair<string, object>(keyedParameter.Key, (dynamic)sender.GetValue(ParameterProperty)));
|
||||
// break;
|
||||
// case IEventParameter eventParameter:
|
||||
// parameters.AddRange(eventParameter.GetParameters(args));
|
||||
// break;
|
||||
// default:
|
||||
// BindingOperations.SetBinding(sender, ParameterProperty, parameter.ToBinding());
|
||||
// parameters.Add((dynamic)sender.GetValue(ParameterProperty));
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
methodInfo.Invoke(target is Action action ? action.Target : target, parameters.Any() ? parameters.ToArray() : parameterInfo.Length > 0 ? new object?[] { null } : Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetInvoke(AvaloniaObject sender, [AllowNull] out (object?, MethodInfo?) invoker)
|
||||
{
|
||||
if (name is Binding binding)
|
||||
{
|
||||
sender.Bind(TargetProperty, binding);
|
||||
if (sender.GetValue(TargetProperty) is Action action)
|
||||
{
|
||||
invoker = new(action.Target, action.Method);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (name is string)
|
||||
{
|
||||
if (sender.GetValue(StyledElement.DataContextProperty) is object dataContext)
|
||||
{
|
||||
if (dataContext.GetType().GetMethod((string)name, BindingFlags.Public | BindingFlags.Instance) is MethodInfo methodInfo)
|
||||
{
|
||||
invoker = new(dataContext, methodInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
invoker = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia;
|
||||
|
||||
public class TriggerCollection : Collection<Delegate>
|
||||
{
|
||||
public void Add(object item)
|
||||
{
|
||||
if (item is Delegate trigger)
|
||||
{
|
||||
base.Add(trigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using System.Reflection;
|
||||
|
||||
namespace TheXamlGuy.UI.Avalonia;
|
||||
|
||||
public class TriggerExtension : MarkupExtension
|
||||
{
|
||||
public AvaloniaObject? TargetObject { get; protected set; }
|
||||
|
||||
protected object? TargetInvoke { get; private set; }
|
||||
|
||||
public void Invoke(object sender, EventArgs args)
|
||||
{
|
||||
OnInvoked(sender, args);
|
||||
}
|
||||
|
||||
public override object? ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget target)
|
||||
{
|
||||
if (target.TargetObject is AvaloniaObject avaloniaObject)
|
||||
{
|
||||
TargetObject = avaloniaObject;
|
||||
}
|
||||
else if (serviceProvider.GetService(typeof(IRootObjectProvider)) is IRootObjectProvider root)
|
||||
{
|
||||
TargetObject = (AvaloniaObject)root.RootObject;
|
||||
}
|
||||
|
||||
if (TargetObject is not null)
|
||||
{
|
||||
string? targetName = target.TargetProperty as string;
|
||||
|
||||
TargetInvoke = target.TargetProperty;
|
||||
OnAttached(serviceProvider);
|
||||
|
||||
EventInfo? eventInfo = target.TargetProperty as EventInfo ?? (targetName is not null ? TargetObject.GetType().GetEvent(targetName) : null);
|
||||
MethodInfo? methodInfo = eventInfo is not null ? null : target.TargetProperty as MethodInfo ?? (targetName is not null ? TargetObject.GetType().GetMethod(targetName) : null);
|
||||
|
||||
MethodInfo invokeMethod = GetType().GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public)!;
|
||||
if (invokeMethod is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (eventInfo is not null)
|
||||
{
|
||||
return Delegate.CreateDelegate(eventInfo.EventHandlerType!, this, invokeMethod);
|
||||
}
|
||||
|
||||
if (methodInfo is not null)
|
||||
{
|
||||
if (methodInfo.GetParameters() is ParameterInfo[] methodParameters && methodParameters is { Length: 2 })
|
||||
{
|
||||
return Delegate.CreateDelegate(methodParameters[1].ParameterType, this, invokeMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual void OnAttached(IServiceProvider serviceProvider)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
using Avalonia.Metadata;
|
||||
|
||||
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "FluentAvalonia.UI.Controls")]
|
||||
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "TheXamlGuy.UI.Avalonia")]
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace TheXamlGuy.UI;
|
||||
|
||||
public interface IEventParameter
|
||||
{
|
||||
List<object> GetParameters(EventArgs args);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace TheXamlGuy.UI;
|
||||
|
||||
public interface IParameter
|
||||
{
|
||||
string? Key { get; }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
|
||||
namespace TheXamlGuy.UI;
|
||||
|
||||
public static class TypeConverterHelper
|
||||
{
|
||||
public static object? DoConversionFrom(TypeConverter converter, object value)
|
||||
{
|
||||
object? returnValue = value;
|
||||
|
||||
try
|
||||
{
|
||||
if (converter != null && value != null && converter.CanConvertFrom(value.GetType()))
|
||||
{
|
||||
returnValue = converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
|
||||
}
|
||||
}
|
||||
catch (Exception exception) when (ShouldEatException(exception))
|
||||
{
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
private static bool ShouldEatException(Exception exception)
|
||||
{
|
||||
bool shouldEat = false;
|
||||
if (exception.InnerException != null)
|
||||
{
|
||||
shouldEat |= ShouldEatException(exception.InnerException);
|
||||
}
|
||||
|
||||
shouldEat |= exception is FormatException;
|
||||
return shouldEat;
|
||||
}
|
||||
|
||||
public static TypeConverter GetTypeConverter(Type type)
|
||||
{
|
||||
return TypeDescriptor.GetConverter(type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace TheXamlGuy.UI;
|
||||
|
||||
public delegate void TypedEventHandler<TSender, TResult>(TSender sender, TResult args);
|
||||
@@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>TheXamlGuy.UI</RootNamespace>
|
||||
<AssemblyName>TheXamlGuy.UI</AssemblyName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class AnimatedScrollViewer : ScrollViewer
|
||||
{
|
||||
public static readonly DependencyProperty CanMouseWheelProperty =
|
||||
DependencyProperty.Register("CanMouseWheel",
|
||||
typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.TrueBox));
|
||||
|
||||
public static readonly DependencyProperty IsInertiaEnabledProperty =
|
||||
DependencyProperty.RegisterAttached("IsInertiaEnabled",
|
||||
typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
|
||||
public static readonly DependencyProperty IsPenetratingProperty =
|
||||
DependencyProperty.RegisterAttached("IsPenetrating",
|
||||
typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));
|
||||
|
||||
|
||||
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty =
|
||||
DependencyProperty.Register("CurrentHorizontalOffset",
|
||||
typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentHorizontalOffsetChanged));
|
||||
|
||||
|
||||
internal static readonly DependencyProperty CurrentVerticalOffsetProperty =
|
||||
DependencyProperty.Register("CurrentVerticalOffset",
|
||||
typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentVerticalOffsetChanged));
|
||||
|
||||
public bool CanMouseWheel
|
||||
{
|
||||
get => (bool)GetValue(CanMouseWheelProperty);
|
||||
set => SetValue(CanMouseWheelProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public bool IsInertiaEnabled
|
||||
{
|
||||
get => (bool)GetValue(IsInertiaEnabledProperty);
|
||||
set => SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
public bool IsPenetrating
|
||||
{
|
||||
get => (bool)GetValue(IsPenetratingProperty);
|
||||
set => SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
|
||||
}
|
||||
|
||||
|
||||
internal double CurrentHorizontalOffset
|
||||
{
|
||||
get => (double)GetValue(CurrentHorizontalOffsetProperty);
|
||||
set => SetValue(CurrentHorizontalOffsetProperty, value);
|
||||
}
|
||||
|
||||
internal double CurrentVerticalOffset
|
||||
{
|
||||
get => (double)GetValue(CurrentVerticalOffsetProperty);
|
||||
set => SetValue(CurrentVerticalOffsetProperty, value);
|
||||
}
|
||||
|
||||
public static bool GetIsInertiaEnabled(DependencyObject element) => (bool)element.GetValue(IsInertiaEnabledProperty);
|
||||
|
||||
public static bool GetIsPenetrating(DependencyObject element) => (bool)element.GetValue(IsPenetratingProperty);
|
||||
|
||||
public static void SetIsInertiaEnabled(DependencyObject element, bool value) => element.SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public static void SetIsPenetrating(DependencyObject element, bool value) => element.SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
|
||||
|
||||
public void ScrollToHorizontalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
var animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentHorizontalOffset = offset;
|
||||
};
|
||||
|
||||
BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
public void ScrollToVerticalOffsetWithAnimation(double offset, double milliseconds = 500)
|
||||
{
|
||||
DoubleAnimation animation = AnimationHelper.CreateAnimation(offset, milliseconds);
|
||||
animation.EasingFunction = new CubicEase
|
||||
{
|
||||
EasingMode = EasingMode.EaseOut
|
||||
};
|
||||
animation.FillBehavior = FillBehavior.Stop;
|
||||
animation.Completed += (s, e1) =>
|
||||
{
|
||||
CurrentVerticalOffset = offset;
|
||||
};
|
||||
|
||||
BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
|
||||
}
|
||||
|
||||
protected override HitTestResult? HitTestCore(PointHitTestParameters hitTestParameters) => IsPenetrating ? null : base.HitTestCore(hitTestParameters);
|
||||
|
||||
private static void OnCurrentHorizontalOffsetChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as AnimatedScrollViewer)?.ScrollToHorizontalOffset((double)args.NewValue);
|
||||
}
|
||||
|
||||
private static void OnCurrentVerticalOffsetChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as AnimatedScrollViewer)?.ScrollToVerticalOffset((double)args.NewValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Threading;
|
||||
using TheXamlGuy.Media.Capture;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Windows.Interop;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class CameraPreview : Control
|
||||
{
|
||||
private Image? image;
|
||||
|
||||
public CameraPreview()
|
||||
{
|
||||
DefaultStyleKey = typeof(CameraPreview);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
image = GetTemplateChild("Image") as Image;
|
||||
}
|
||||
|
||||
public async Task StartAsync(IMediaFrameSource source)
|
||||
{
|
||||
MediaCaptureInitializationSettings settings = new()
|
||||
{
|
||||
Source = source
|
||||
};
|
||||
|
||||
MediaCapture mediaCapture = new();
|
||||
mediaCapture.Initialize(settings);
|
||||
|
||||
if (await mediaCapture.CreateFrameReaderAsync() is IMediaFrameReader frameReader)
|
||||
{
|
||||
frameReader.FrameArrived += OnFrameArrived;
|
||||
await frameReader.StartAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task StartAsync()
|
||||
{
|
||||
if (image is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IReadOnlyList<IMediaFrameSource> sourceGroups = await MediaFrameSource.FindAllAsync();
|
||||
if (sourceGroups.FirstOrDefault(x => x.DisplayName.Contains("USB", System.StringComparison.InvariantCultureIgnoreCase)) is IMediaFrameSource source)
|
||||
{
|
||||
if (source.SupportedFormats.OrderByDescending(x => x.Size.Width & x.Size.Height).FirstOrDefault() is MediaFrameFormat bestSupportedFormat)
|
||||
{
|
||||
source.SetFormat(bestSupportedFormat);
|
||||
}
|
||||
|
||||
await StartAsync(source);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
private async void OnFrameArrived(IMediaFrameReader sender, MediaFrameArrivedEventArgs args)
|
||||
{
|
||||
if (image is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (await sender.TryAcquireLatestFrameAsync() is MediaFrame frame)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
IntPtr handle = frame.Bitmap.GetHbitmap();
|
||||
image.Source = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(frame.Width, frame.Height));
|
||||
DeleteObject(handle);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:TheXamlGuy.UI.WPF.Controls">
|
||||
<Style TargetType="controls:CameraPreview">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:CameraPreview">
|
||||
<Grid Background="{TemplateBinding Background}">
|
||||
<Image x:Name="Image" />
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class Countdown : Control
|
||||
{
|
||||
public static readonly DependencyProperty CountdownIdentifierProperty =
|
||||
DependencyProperty.Register(nameof(CountdownIdentifier),
|
||||
typeof(CountdownIdentifier), typeof(Countdown));
|
||||
|
||||
private Storyboard? completingTransition;
|
||||
private VisualStateGroup? countdownGroup;
|
||||
private bool isTransitioning;
|
||||
|
||||
public Countdown()
|
||||
{
|
||||
DefaultStyleKey = typeof(Countdown);
|
||||
}
|
||||
|
||||
public event TypedEventHandler<Countdown, CountdownCompletedEventArgs>? Completed;
|
||||
|
||||
public event TypedEventHandler<Countdown, CountdownStartedEventArgs>? Started;
|
||||
|
||||
public CountdownIdentifier CountdownIdentifier
|
||||
{
|
||||
get => (CountdownIdentifier)GetValue(CountdownIdentifierProperty);
|
||||
set => SetValue(CountdownIdentifierProperty, value);
|
||||
}
|
||||
|
||||
private Storyboard? CompletingTransition
|
||||
{
|
||||
get => completingTransition;
|
||||
set
|
||||
{
|
||||
if (completingTransition is not null)
|
||||
{
|
||||
CompletingTransition!.Completed -= OnTransitionCompleted;
|
||||
}
|
||||
|
||||
completingTransition = value;
|
||||
|
||||
if (completingTransition is not null)
|
||||
{
|
||||
CompletingTransition!.Completed += OnTransitionCompleted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
if (GetTemplateChild("Container") is Grid container)
|
||||
{
|
||||
countdownGroup = ((IEnumerable<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(container))!.FirstOrDefault(x => x.Name == "CountdownStates");
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (isTransitioning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Started?.Invoke(this, new CountdownStartedEventArgs());
|
||||
|
||||
isTransitioning = true;
|
||||
CompletingTransition = GetTransitionStoryboardByName($"{CountdownIdentifier}");
|
||||
VisualStateManager.GoToState(this, $"{CountdownIdentifier}", true);
|
||||
}
|
||||
|
||||
private Storyboard GetTransitionStoryboardByName(string transitionName)
|
||||
{
|
||||
if (countdownGroup is not null)
|
||||
{
|
||||
if (((IEnumerable<VisualState>)countdownGroup.States).Where(x => x.Name == transitionName).Select(x => x.Storyboard).FirstOrDefault() is Storyboard transition)
|
||||
{
|
||||
return transition;
|
||||
}
|
||||
}
|
||||
|
||||
return new Storyboard();
|
||||
}
|
||||
|
||||
private void OnTransitionCompleted(object? sender, EventArgs args)
|
||||
{
|
||||
CompletingTransition!.Completed -= OnTransitionCompleted;
|
||||
VisualStateManager.GoToState(this, "Pending", false);
|
||||
|
||||
isTransitioning = false;
|
||||
|
||||
Completed?.Invoke(this, new CountdownCompletedEventArgs());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:TheXamlGuy.UI.WPF.Controls">
|
||||
<Style TargetType="controls:Countdown">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:Countdown">
|
||||
<Grid x:Name="Container">
|
||||
<Grid
|
||||
x:Name="TextRoot"
|
||||
Opacity="0"
|
||||
RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock x:Name="TextBlock" />
|
||||
<Grid.RenderTransform>
|
||||
<ScaleTransform x:Name="ScaleTransform" />
|
||||
</Grid.RenderTransform>
|
||||
</Grid>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CountdownStates">
|
||||
<VisualState x:Name="Pending" />
|
||||
<VisualState x:Name="TenSecond">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(TextBlock.Text)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="10" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="9" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="8" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:03" Value="7" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:04" Value="6" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:05" Value="5" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:06" Value="4" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:07" Value="3" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:08" Value="2" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:09" Value="1" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:10" Value="1" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="10x"
|
||||
Storyboard.TargetName="TextRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<LinearDoubleKeyFrame KeyTime="0" Value="0.0" />
|
||||
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="10x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="10x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="FiveSecond">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(TextBlock.Text)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="5" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="4" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:02" Value="3" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:03" Value="2" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:04" Value="1" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="5x"
|
||||
Storyboard.TargetName="TextRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<LinearDoubleKeyFrame KeyTime="0" Value="0.0" />
|
||||
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="5x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="5x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="TwoSecond">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(TextBlock.Text)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="2" />
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:01" Value="1" />
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="2x"
|
||||
Storyboard.TargetName="TextRoot"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<LinearDoubleKeyFrame KeyTime="0" Value="0.0" />
|
||||
<LinearDoubleKeyFrame KeyTime="00:00:00.167" Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="2x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleX">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="2x"
|
||||
Storyboard.TargetName="ScaleTransform"
|
||||
Storyboard.TargetProperty="ScaleY">
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="1.5" />
|
||||
<SplineDoubleKeyFrame
|
||||
KeySpline="0,0,0,1"
|
||||
KeyTime="00:00:00.250"
|
||||
Value="1.0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="0:0:01" Value="1.0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,7 @@
|
||||
using System;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
public class CountdownCompletedEventArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public enum CountdownIdentifier
|
||||
{
|
||||
TenSecond,
|
||||
FiveSecond,
|
||||
TwoSecond
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class CountdownStartedEventArgs : EventArgs
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class FlipView : ListBox
|
||||
{
|
||||
public static readonly DependencyProperty ItemContainerTemplateSelectorProperty =
|
||||
DependencyProperty.Register(nameof(ItemContainerTemplateSelector),
|
||||
typeof(DataTemplateSelector), typeof(FlipView), new PropertyMetadata(new DefaultItemContainerTemplateSelector()));
|
||||
|
||||
public static readonly DependencyProperty UsesItemContainerTemplateSelectorProperty =
|
||||
DependencyProperty.Register(nameof(UsesItemContainerTemplateSelector),
|
||||
typeof(bool), typeof(FlipView));
|
||||
|
||||
private object? current;
|
||||
|
||||
private AnimatedScrollViewer? scrollViewer;
|
||||
|
||||
public FlipView()
|
||||
{
|
||||
DefaultStyleKey = typeof(FlipView);
|
||||
}
|
||||
|
||||
public DataTemplateSelector ItemContainerTemplateSelector
|
||||
{
|
||||
get => (DataTemplateSelector)GetValue(ItemContainerTemplateSelectorProperty);
|
||||
set => SetValue(ItemContainerTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
public bool UsesItemContainerTemplateSelector
|
||||
{
|
||||
get => (bool)GetValue(UsesItemContainerTemplateSelectorProperty);
|
||||
set => SetValue(UsesItemContainerTemplateSelectorProperty, value);
|
||||
}
|
||||
|
||||
public void Next()
|
||||
{
|
||||
if (SelectedIndex < Items.Count - 1)
|
||||
{
|
||||
SelectedIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedIndex = 0;
|
||||
}
|
||||
|
||||
if (scrollViewer is not null)
|
||||
{
|
||||
double scrollOffset = Math.Min(scrollViewer.CurrentHorizontalOffset + GetDesiredItemWidth(), scrollViewer.ScrollableWidth);
|
||||
scrollViewer.ScrollToHorizontalOffsetWithAnimation(scrollOffset);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
scrollViewer = GetTemplateChild("ScrollingHost") as AnimatedScrollViewer;
|
||||
if (scrollViewer is not null)
|
||||
{
|
||||
scrollViewer.SizeChanged += OnScrollViewerSizeChanged;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
public void Previous()
|
||||
{
|
||||
if (SelectedIndex > 0)
|
||||
{
|
||||
SelectedIndex--;
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedIndex = Items.Count - 1;
|
||||
}
|
||||
|
||||
if (scrollViewer is not null)
|
||||
{
|
||||
double scrollOffset = Math.Min(scrollViewer.CurrentHorizontalOffset - GetDesiredItemWidth(), scrollViewer.ScrollableWidth);
|
||||
scrollViewer.ScrollToHorizontalOffsetWithAnimation(scrollOffset);
|
||||
}
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
object? current = this.current;
|
||||
this.current = null;
|
||||
|
||||
if (current is not null)
|
||||
{
|
||||
FlipViewItem? item = null;
|
||||
|
||||
if (UsesItemContainerTemplateSelector)
|
||||
{
|
||||
if (ItemContainerTemplateSelector.SelectTemplate(current, this) is DataTemplate dataTemplate)
|
||||
{
|
||||
DependencyObject container = dataTemplate.LoadContent();
|
||||
|
||||
switch (container)
|
||||
{
|
||||
case FlipViewItem:
|
||||
item = container as FlipViewItem;
|
||||
break;
|
||||
case TemplateGeneratorControl template:
|
||||
item = template.Content is FlipViewItem ? template.Content as FlipViewItem : new FlipViewItem { Content = template.Content };
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
item ??= new FlipViewItem();
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return new FlipViewItem();
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
if (item is not FlipViewItem)
|
||||
{
|
||||
current = item;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
|
||||
{
|
||||
base.PrepareContainerForItemOverride(element, item);
|
||||
|
||||
if (element is FlipViewItem flipViewItem)
|
||||
{
|
||||
Thickness flipViewItemMargin = flipViewItem.Margin;
|
||||
|
||||
double value = GetDesiredItemWidth();
|
||||
|
||||
value -= (flipViewItemMargin.Left + flipViewItemMargin.Right);
|
||||
flipViewItem.Width = value;
|
||||
|
||||
value = GetDesiredItemHeight();
|
||||
|
||||
value -= (flipViewItemMargin.Top + flipViewItemMargin.Bottom);
|
||||
flipViewItem.Height = value;
|
||||
}
|
||||
}
|
||||
|
||||
private double GetDesiredItemHeight()
|
||||
{
|
||||
double height = scrollViewer is not null ? scrollViewer.ActualHeight : ActualHeight;
|
||||
|
||||
if (height <= 0)
|
||||
{
|
||||
height = Height;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
private double GetDesiredItemWidth()
|
||||
{
|
||||
double width = scrollViewer is not null ? scrollViewer.ActualWidth : ActualWidth;
|
||||
|
||||
if (width <= 0)
|
||||
{
|
||||
width = Width;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
private void OnScrollViewerSizeChanged(object sender, SizeChangedEventArgs args)
|
||||
{
|
||||
double width = GetDesiredItemWidth();
|
||||
double height = GetDesiredItemHeight();
|
||||
for (int i = 0; i < Items.Count; i++)
|
||||
{
|
||||
if (ItemContainerGenerator.ContainerFromIndex(i) is FlipViewItem container)
|
||||
{
|
||||
Thickness margin = container.Margin;
|
||||
|
||||
double value = width - (margin.Left + margin.Right);
|
||||
container.Width = value;
|
||||
|
||||
value = height - (margin.Top + margin.Bottom);
|
||||
container.Height = value;
|
||||
|
||||
ScrollIntoView(SelectedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:TheXamlGuy.UI.WPF.Controls">
|
||||
<Style TargetType="controls:FlipView">
|
||||
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Hidden" />
|
||||
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden" />
|
||||
<Setter Property="ItemsPanel">
|
||||
<Setter.Value>
|
||||
<ItemsPanelTemplate>
|
||||
<VirtualizingStackPanel Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:FlipView">
|
||||
<controls:AnimatedScrollViewer
|
||||
x:Name="ScrollingHost"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
|
||||
IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
|
||||
IsInertiaEnabled="True"
|
||||
IsTabStop="False"
|
||||
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
|
||||
<ItemsPresenter />
|
||||
</controls:AnimatedScrollViewer>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
<Style TargetType="controls:FlipViewItem">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:FlipViewItem">
|
||||
<ContentPresenter Margin="{TemplateBinding Padding}" />
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class FlipViewItem : ContentControl
|
||||
{
|
||||
public FlipViewItem()
|
||||
{
|
||||
DefaultStyleKey = typeof(FlipViewItem);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class Arc : Shape
|
||||
{
|
||||
public static readonly DependencyProperty DirectionProperty =
|
||||
DependencyProperty.Register(nameof(Direction),
|
||||
typeof(SweepDirection), typeof(Arc), new PropertyMetadata(SweepDirection.Clockwise));
|
||||
|
||||
public static readonly DependencyProperty EndAngleProperty =
|
||||
DependencyProperty.Register(nameof(EndAngle),
|
||||
typeof(double), typeof(Arc), new PropertyMetadata(0.0d, OnEndAnglePropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty OriginRotationDegreesProperty =
|
||||
DependencyProperty.Register(nameof(OriginRotationDegrees),
|
||||
typeof(double), typeof(Arc), new PropertyMetadata(270.0, new PropertyChangedCallback(OnOriginRotationDegreesPropertyChanged)));
|
||||
|
||||
public static readonly DependencyProperty StartAngleProperty =
|
||||
DependencyProperty.Register(nameof(StartAngle),
|
||||
typeof(double), typeof(Arc), new PropertyMetadata(0.0d, OnStartAnglePropertyChanged));
|
||||
|
||||
public SweepDirection Direction
|
||||
{
|
||||
get => (SweepDirection)GetValue(DirectionProperty);
|
||||
set => SetValue(DirectionProperty, value);
|
||||
}
|
||||
|
||||
public double EndAngle
|
||||
{
|
||||
get => (double)GetValue(EndAngleProperty);
|
||||
set => SetValue(EndAngleProperty, value);
|
||||
}
|
||||
|
||||
public double OriginRotationDegrees
|
||||
{
|
||||
get => (double)GetValue(OriginRotationDegreesProperty);
|
||||
set => SetValue(OriginRotationDegreesProperty, value);
|
||||
}
|
||||
|
||||
public double StartAngle
|
||||
{
|
||||
get => (double)GetValue(StartAngleProperty);
|
||||
set => SetValue(StartAngleProperty, value);
|
||||
}
|
||||
|
||||
protected override Geometry DefiningGeometry => GetDefiningGeometry();
|
||||
|
||||
protected override Size MeasureOverride(Size constraint)
|
||||
{
|
||||
return constraint;
|
||||
}
|
||||
|
||||
private static void OnEndAnglePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as Arc)?.OnEndAnglePropertyChanged();
|
||||
}
|
||||
|
||||
private static void OnOriginRotationDegreesPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as Arc)?.OnOriginRotationDegreesPropertyChanged();
|
||||
}
|
||||
|
||||
private static void OnStartAnglePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as Arc)?.OnStartAnglePropertyChanged();
|
||||
}
|
||||
|
||||
private Geometry GetDefiningGeometry()
|
||||
{
|
||||
Point startPoint = PointAtAngle(Math.Min(StartAngle, EndAngle), Direction);
|
||||
Point endPoint = PointAtAngle(Math.Max(StartAngle, EndAngle), Direction);
|
||||
|
||||
Size arcSize = new(Math.Max(0, (ActualWidth - StrokeThickness) / 2), Math.Max(0, (ActualHeight - StrokeThickness) / 2));
|
||||
bool isLargeArc = Math.Abs(EndAngle - StartAngle) > 180;
|
||||
|
||||
StreamGeometry streamGeometry = new();
|
||||
using (StreamGeometryContext context = streamGeometry.Open())
|
||||
{
|
||||
context.BeginFigure(startPoint, false, false);
|
||||
context.ArcTo(endPoint, arcSize, 0, isLargeArc, Direction, true, false);
|
||||
}
|
||||
|
||||
streamGeometry.Transform = new TranslateTransform(StrokeThickness / 2, StrokeThickness / 2);
|
||||
return streamGeometry;
|
||||
}
|
||||
|
||||
private void OnEndAnglePropertyChanged()
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private void OnOriginRotationDegreesPropertyChanged()
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
private void OnStartAnglePropertyChanged()
|
||||
{
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
|
||||
private Point PointAtAngle(double angle, SweepDirection sweep)
|
||||
{
|
||||
double translatedAngle = angle + OriginRotationDegrees;
|
||||
double radAngle = translatedAngle * (Math.PI / 180);
|
||||
double xr = (RenderSize.Width - StrokeThickness) / 2;
|
||||
double yr = (RenderSize.Height - StrokeThickness) / 2;
|
||||
|
||||
double x = xr + xr * Math.Cos(radAngle);
|
||||
double y = yr * Math.Sin(radAngle);
|
||||
|
||||
y = sweep == SweepDirection.Counterclockwise ? yr - y : yr + y;
|
||||
return new Point(x, y);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class DefaultItemContainerTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
||||
{
|
||||
if (container is ItemsControl itemsControl)
|
||||
{
|
||||
Type itemType = item.GetType();
|
||||
DataTemplateKey key = new(itemType);
|
||||
|
||||
if (itemsControl.TryFindResource(key) is DataTemplate template)
|
||||
{
|
||||
return template;
|
||||
}
|
||||
}
|
||||
|
||||
return base.SelectTemplate(item, container);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class ProgressRing : RangeBase
|
||||
{
|
||||
public static readonly DependencyProperty IsActiveProperty =
|
||||
DependencyProperty.Register(nameof(IsActive),
|
||||
typeof(bool), typeof(ProgressRing), new PropertyMetadata(true, OnIsActivePropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty IsIndeterminateProperty =
|
||||
DependencyProperty.Register(nameof(IsIndeterminate),
|
||||
typeof(bool), typeof(ProgressRing), new PropertyMetadata(false, OnIsIndeterminatePropertyChanged));
|
||||
|
||||
public static readonly DependencyProperty ThicknessProperty =
|
||||
DependencyProperty.Register(nameof(Thickness),
|
||||
typeof(double), typeof(ProgressRing));
|
||||
|
||||
public static DependencyProperty TemplateSettingsProperty =
|
||||
DependencyProperty.Register(nameof(TemplateSettings),
|
||||
typeof(ProgressRingTemplateSettings), typeof(ProgressRing));
|
||||
|
||||
public ProgressRing()
|
||||
{
|
||||
DefaultStyleKey = typeof(ProgressRing);
|
||||
SetValue(TemplateSettingsProperty, new ProgressRingTemplateSettings());
|
||||
}
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => (bool)GetValue(IsActiveProperty);
|
||||
set => SetValue(IsActiveProperty, value);
|
||||
}
|
||||
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get => (bool)GetValue(IsIndeterminateProperty);
|
||||
set => SetValue(IsIndeterminateProperty, value);
|
||||
}
|
||||
|
||||
public double Thickness
|
||||
{
|
||||
get => (double)GetValue(ThicknessProperty);
|
||||
set => SetValue(ThicknessProperty, value);
|
||||
}
|
||||
|
||||
public ProgressRingTemplateSettings TemplateSettings
|
||||
{
|
||||
get => (ProgressRingTemplateSettings)GetValue(TemplateSettingsProperty);
|
||||
set => SetValue(TemplateSettingsProperty, value);
|
||||
}
|
||||
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
UpdateValue();
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
protected override void OnValueChanged(double oldValue, double newValue)
|
||||
{
|
||||
UpdateValue();
|
||||
base.OnValueChanged(oldValue, newValue);
|
||||
}
|
||||
|
||||
private void UpdateValue()
|
||||
{
|
||||
TemplateSettings.EndAngle = Value == Maximum ? 359.999 : 359.999 * (Value / (Maximum - Minimum));
|
||||
}
|
||||
|
||||
private static void OnIsActivePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as ProgressRing)?.OnIsActivePropertyChanged();
|
||||
}
|
||||
|
||||
private static void OnIsIndeterminatePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as ProgressRing)?.OnIsIndeterminatePropertyChanged();
|
||||
}
|
||||
|
||||
private void OnIsActivePropertyChanged()
|
||||
{
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
private void OnIsIndeterminatePropertyChanged()
|
||||
{
|
||||
UpdateVisualState();
|
||||
}
|
||||
|
||||
private void UpdateVisualState()
|
||||
{
|
||||
VisualStateManager.GoToState(this, IsActive ? IsIndeterminate ? "IndeterminateActive" : "Active" : "Inactive", true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:TheXamlGuy.UI.WPF.Controls"
|
||||
xmlns:system="clr-namespace:System;assembly=mscorlib">
|
||||
<SolidColorBrush x:Key="ProgressRingForeground" Color="White" />
|
||||
<SolidColorBrush x:Key="ProgressRingBackground" Color="Transparent" />
|
||||
<system:Double x:Key="ProgressRingStrokeThickness">4</system:Double>
|
||||
<Style TargetType="controls:ProgressRing">
|
||||
<Setter Property="Foreground" Value="{StaticResource ProgressRingForeground}" />
|
||||
<Setter Property="Background" Value="{StaticResource ProgressRingBackground}" />
|
||||
<Setter Property="Thickness" Value="{StaticResource ProgressRingStrokeThickness}" />
|
||||
<Setter Property="IsHitTestVisible" Value="False" />
|
||||
<Setter Property="HorizontalAlignment" Value="Center" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="MinHeight" Value="16" />
|
||||
<Setter Property="MinWidth" Value="16" />
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="Width" Value="32" />
|
||||
<Setter Property="Height" Value="32" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:ProgressRing">
|
||||
<Grid x:Name="LayoutRoot">
|
||||
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
|
||||
<controls:Arc
|
||||
Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
EndAngle="359"
|
||||
StartAngle="0"
|
||||
Stroke="{TemplateBinding Background}"
|
||||
StrokeThickness="{TemplateBinding Thickness}" />
|
||||
<controls:Arc
|
||||
x:Name="ForegroundArc"
|
||||
Width="{TemplateBinding Width}"
|
||||
Height="{TemplateBinding Height}"
|
||||
EndAngle="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EndAngle}"
|
||||
RenderTransformOrigin="0.5,0.5"
|
||||
StartAngle="0"
|
||||
Stroke="{TemplateBinding Foreground}"
|
||||
StrokeEndLineCap="Round"
|
||||
StrokeStartLineCap="Round"
|
||||
StrokeThickness="{TemplateBinding Thickness}">
|
||||
<controls:Arc.RenderTransform>
|
||||
<TransformGroup>
|
||||
<RotateTransform x:Name="RotateTransform" />
|
||||
</TransformGroup>
|
||||
</controls:Arc.RenderTransform>
|
||||
</controls:Arc>
|
||||
</Grid>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Inactive">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
Storyboard.TargetName="ForegroundArc"
|
||||
Storyboard.TargetProperty="Opacity"
|
||||
To="0"
|
||||
Duration="0" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="IndeterminateActive">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames
|
||||
RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="ForegroundArc"
|
||||
Storyboard.TargetProperty="EndAngle">
|
||||
<SplineDoubleKeyFrame KeyTime="0" Value="0" />
|
||||
<SplineDoubleKeyFrame KeyTime="0:0:1" Value="179" />
|
||||
<SplineDoubleKeyFrame KeyTime="0:0:2" Value="0" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimation
|
||||
RepeatBehavior="Forever"
|
||||
Storyboard.TargetName="RotateTransform"
|
||||
Storyboard.TargetProperty="Angle"
|
||||
From="00"
|
||||
To="359"
|
||||
Duration="0:0:0.65" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Active" />
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class ProgressRingTemplateSettings : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty EndAngleProperty =
|
||||
DependencyProperty.Register(nameof(EndAngle),
|
||||
typeof(double), typeof(ProgressRingTemplateSettings));
|
||||
|
||||
public double EndAngle
|
||||
{
|
||||
get => (double)GetValue(EndAngleProperty);
|
||||
set => SetValue(EndAngleProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "TheXamlGuy.UI.WPF.Controls")]
|
||||
@@ -0,0 +1,9 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/TheXamlGuy.UI.WPF.Controls;component/CameraPreview/CameraPreview.xaml" />
|
||||
<ResourceDictionary Source="/TheXamlGuy.UI.WPF.Controls;component/Countdown/Countdown.xaml" />
|
||||
<ResourceDictionary Source="/TheXamlGuy.UI.WPF.Controls;component/FlipView/FlipView.xaml" />
|
||||
<ResourceDictionary Source="/TheXamlGuy.UI.WPF.Controls;component/TransitioningContentControl/TransitioningContentControl.xaml" />
|
||||
<ResourceDictionary Source="/TheXamlGuy.UI.WPF.Controls;component/ProgressRing/ProgressRing.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,359 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Animation;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public class TransitioningContentControl : ContentControl
|
||||
{
|
||||
public static readonly DependencyProperty TransitionDirectionProperty =
|
||||
DependencyProperty.RegisterAttached(nameof(TransitioningContentControlTransitionDirection),
|
||||
typeof(TransitioningContentControlTransitionDirection), typeof(TransitioningContentControl), new PropertyMetadata(TransitioningContentControlTransitionDirection.Left));
|
||||
|
||||
public static readonly DependencyProperty TransitionDurationProperty =
|
||||
DependencyProperty.RegisterAttached(nameof(Duration),
|
||||
typeof(TimeSpan), typeof(TransitioningContentControl), new PropertyMetadata(TimeSpan.FromSeconds(0.3)));
|
||||
|
||||
public static readonly DependencyProperty TransitionProperty =
|
||||
DependencyProperty.RegisterAttached(nameof(Transition),
|
||||
typeof(TransitioningContentControlTransitionType), typeof(TransitioningContentControl), new PropertyMetadata(TransitioningContentControlTransitionType.Fade));
|
||||
|
||||
private Storyboard? completingTransition;
|
||||
private Grid? container;
|
||||
private ContentPresenter? currentContentPresentationSite;
|
||||
private bool isTransitioning;
|
||||
private VisualStateGroup? presentationGroup;
|
||||
private Image? previousImageSite;
|
||||
private Storyboard? startingTransition;
|
||||
|
||||
public TransitioningContentControl()
|
||||
{
|
||||
DefaultStyleKey = typeof(TransitioningContentControl);
|
||||
}
|
||||
|
||||
public event RoutedEventHandler? TransitionCompleted;
|
||||
|
||||
public event RoutedEventHandler? TransitionStarted;
|
||||
|
||||
public TransitioningContentControlTransitionDirection Direction
|
||||
{
|
||||
get => (TransitioningContentControlTransitionDirection)GetValue(TransitionDirectionProperty);
|
||||
set => SetValue(TransitionDirectionProperty, value);
|
||||
}
|
||||
|
||||
public TimeSpan Duration
|
||||
{
|
||||
get => (TimeSpan)GetValue(TransitionDurationProperty);
|
||||
set => SetValue(TransitionDurationProperty, value);
|
||||
}
|
||||
|
||||
public TransitioningContentControlTransitionType Transition
|
||||
{
|
||||
get => (TransitioningContentControlTransitionType)GetValue(TransitionProperty);
|
||||
set => SetValue(TransitionProperty, value);
|
||||
}
|
||||
|
||||
private Storyboard? CompletingTransition
|
||||
{
|
||||
get => completingTransition;
|
||||
set
|
||||
{
|
||||
if (completingTransition is not null)
|
||||
{
|
||||
CompletingTransition!.Completed -= OnTransitionCompleted;
|
||||
}
|
||||
|
||||
completingTransition = value;
|
||||
|
||||
if (completingTransition is not null)
|
||||
{
|
||||
CompletingTransition!.Completed += OnTransitionCompleted;
|
||||
SetTransitionDefaultValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Storyboard? StartingTransition
|
||||
{
|
||||
get => startingTransition;
|
||||
set
|
||||
{
|
||||
startingTransition = value;
|
||||
if (startingTransition is not null)
|
||||
{
|
||||
SetTransitionDefaultValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void OnApplyTemplate()
|
||||
{
|
||||
container = GetTemplateChild("Container") as Grid;
|
||||
if (container is not null)
|
||||
{
|
||||
presentationGroup = ((IEnumerable<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(container))!.FirstOrDefault(x => x.Name == "PresentationStates");
|
||||
}
|
||||
|
||||
currentContentPresentationSite = GetTemplateChild("CurrentContentPresentationSite") as ContentPresenter;
|
||||
previousImageSite = GetTemplateChild("PreviousImageSite") as Image;
|
||||
|
||||
if (currentContentPresentationSite is not null)
|
||||
{
|
||||
currentContentPresentationSite.Content = Content;
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(this, "Normal", false);
|
||||
}
|
||||
|
||||
protected override void OnContentChanged(object oldContent, object newContent)
|
||||
{
|
||||
QueueTransition(newContent);
|
||||
base.OnContentChanged(oldContent, newContent);
|
||||
}
|
||||
|
||||
private static RenderTargetBitmap GetRenderTargetBitmapFromUiElement(UIElement uiElement)
|
||||
{
|
||||
if (uiElement.RenderSize.Height == 0 || uiElement.RenderSize.Width == 0)
|
||||
{
|
||||
return default!;
|
||||
}
|
||||
|
||||
DpiScale dpiScale = VisualTreeHelper.GetDpi(uiElement);
|
||||
|
||||
double pixelWidth = Math.Max(1.0, uiElement.RenderSize.Width * dpiScale.DpiScaleX);
|
||||
double pixelHeight = Math.Max(1.0, uiElement.RenderSize.Height * dpiScale.DpiScaleY);
|
||||
|
||||
RenderTargetBitmap renderTargetBitmap = new(Convert.ToInt32(pixelWidth), Convert.ToInt32(pixelHeight), dpiScale.PixelsPerInchX, dpiScale.PixelsPerInchY, PixelFormats.Pbgra32);
|
||||
|
||||
renderTargetBitmap.Render(uiElement);
|
||||
renderTargetBitmap.Freeze();
|
||||
|
||||
return renderTargetBitmap;
|
||||
}
|
||||
|
||||
private void AbortTransition()
|
||||
{
|
||||
VisualStateManager.GoToState(this, "Normal", false);
|
||||
isTransitioning = false;
|
||||
|
||||
if (previousImageSite is not null)
|
||||
{
|
||||
if (previousImageSite.Source is RenderTargetBitmap renderTargetBitmap)
|
||||
{
|
||||
renderTargetBitmap.Clear();
|
||||
}
|
||||
|
||||
previousImageSite.Source = null;
|
||||
previousImageSite.UpdateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private Storyboard GetTransitionStoryboardByName(string transitionName)
|
||||
{
|
||||
if (presentationGroup is not null)
|
||||
{
|
||||
if (((IEnumerable<VisualState>)presentationGroup.States).Where(x => x.Name == transitionName).Select(x => x.Storyboard).FirstOrDefault() is Storyboard transition)
|
||||
{
|
||||
return transition;
|
||||
}
|
||||
}
|
||||
|
||||
return new Storyboard();
|
||||
}
|
||||
|
||||
private void OnTransitionCompleted(object? sender, EventArgs args)
|
||||
{
|
||||
AbortTransition();
|
||||
TransitionCompleted?.Invoke(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
private void QueueTransition(object newContent)
|
||||
{
|
||||
if (currentContentPresentationSite is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTransitioning || previousImageSite is null)
|
||||
{
|
||||
currentContentPresentationSite.Content = newContent;
|
||||
return;
|
||||
}
|
||||
|
||||
previousImageSite.Source = GetRenderTargetBitmapFromUiElement(currentContentPresentationSite);
|
||||
currentContentPresentationSite.Content = newContent;
|
||||
|
||||
string transitionInName = string.Empty;
|
||||
int statesRemaining = 0;
|
||||
string startingTransitionName = string.Empty;
|
||||
|
||||
if (Transition == TransitioningContentControlTransitionType.Bounce)
|
||||
{
|
||||
transitionInName = $"{Transition}{Direction}In";
|
||||
CompletingTransition = GetTransitionStoryboardByName(transitionInName);
|
||||
|
||||
startingTransitionName = $"{Transition}{Direction}Out";
|
||||
StartingTransition = (Storyboard?)GetTransitionStoryboardByName(startingTransitionName);
|
||||
statesRemaining = 2;
|
||||
|
||||
StartingTransition!.Completed += NextState;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (StartingTransition is not null)
|
||||
{
|
||||
StartingTransition!.Completed -= NextState;
|
||||
}
|
||||
|
||||
StartingTransition = null;
|
||||
startingTransitionName = Transition == TransitioningContentControlTransitionType.Fade ? "Fade" : $"{Transition}{Direction}";
|
||||
|
||||
CompletingTransition = GetTransitionStoryboardByName(startingTransitionName);
|
||||
statesRemaining = 1;
|
||||
}
|
||||
|
||||
isTransitioning = true;
|
||||
RaiseTransitionStarted();
|
||||
|
||||
statesRemaining--;
|
||||
VisualStateManager.GoToState(this, startingTransitionName, false);
|
||||
|
||||
void NextState(object? sender, EventArgs args)
|
||||
{
|
||||
StartingTransition!.Completed -= NextState;
|
||||
if (statesRemaining == 1)
|
||||
{
|
||||
statesRemaining--;
|
||||
VisualStateManager.GoToState(this, transitionInName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseTransitionStarted()
|
||||
{
|
||||
TransitionStarted?.Invoke(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
private void SetTransitionDefaultValues()
|
||||
{
|
||||
switch (Transition)
|
||||
{
|
||||
case TransitioningContentControlTransitionType.Fade:
|
||||
{
|
||||
if (CompletingTransition is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoubleAnimation completingDoubleAnimation = (DoubleAnimation)CompletingTransition.Children[0];
|
||||
completingDoubleAnimation.Duration = Duration;
|
||||
|
||||
DoubleAnimation startingDoubleAnimation = (DoubleAnimation)CompletingTransition.Children[1];
|
||||
startingDoubleAnimation.Duration = Duration;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TransitioningContentControlTransitionType.Slide:
|
||||
{
|
||||
if (CompletingTransition is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoubleAnimation startingDoubleAnimation = (DoubleAnimation)CompletingTransition.Children[0];
|
||||
startingDoubleAnimation.Duration = Duration;
|
||||
|
||||
startingDoubleAnimation.From = Direction switch
|
||||
{
|
||||
TransitioningContentControlTransitionDirection.Down => -ActualHeight,
|
||||
TransitioningContentControlTransitionDirection.Up => ActualHeight,
|
||||
TransitioningContentControlTransitionDirection.Right => -ActualWidth,
|
||||
TransitioningContentControlTransitionDirection.Left => ActualWidth,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(TransitioningContentControlTransitionDirection))
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TransitioningContentControlTransitionType.Move:
|
||||
{
|
||||
if (CompletingTransition is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoubleAnimation completingDoubleAnimation = (DoubleAnimation)CompletingTransition.Children[0];
|
||||
DoubleAnimation startingDoubleAnimation = (DoubleAnimation)CompletingTransition.Children[1];
|
||||
|
||||
startingDoubleAnimation.Duration = Duration;
|
||||
completingDoubleAnimation.Duration = Duration;
|
||||
|
||||
switch (Direction)
|
||||
{
|
||||
case TransitioningContentControlTransitionDirection.Down:
|
||||
startingDoubleAnimation.To = ActualHeight;
|
||||
completingDoubleAnimation.From = -ActualHeight;
|
||||
|
||||
break;
|
||||
|
||||
case TransitioningContentControlTransitionDirection.Up:
|
||||
startingDoubleAnimation.To = -ActualHeight;
|
||||
completingDoubleAnimation.From = ActualHeight;
|
||||
|
||||
break;
|
||||
|
||||
case TransitioningContentControlTransitionDirection.Right:
|
||||
startingDoubleAnimation.To = ActualWidth;
|
||||
completingDoubleAnimation.From = -ActualWidth;
|
||||
|
||||
break;
|
||||
|
||||
case TransitioningContentControlTransitionDirection.Left:
|
||||
startingDoubleAnimation.To = -ActualWidth;
|
||||
completingDoubleAnimation.From = ActualWidth;
|
||||
|
||||
break;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(TransitioningContentControlTransitionDirection));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TransitioningContentControlTransitionType.Bounce:
|
||||
{
|
||||
if (CompletingTransition is not null)
|
||||
{
|
||||
DoubleAnimationUsingKeyFrames completingDoubleAnimation = (DoubleAnimationUsingKeyFrames)CompletingTransition.Children[0];
|
||||
completingDoubleAnimation.KeyFrames[1].Value = ActualHeight;
|
||||
}
|
||||
|
||||
if (StartingTransition is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
DoubleAnimation startingDoubleAnimation = (DoubleAnimation)StartingTransition.Children[0];
|
||||
|
||||
startingDoubleAnimation.To = Direction switch
|
||||
{
|
||||
TransitioningContentControlTransitionDirection.Down => ActualHeight,
|
||||
TransitioningContentControlTransitionDirection.Up => -ActualHeight,
|
||||
TransitioningContentControlTransitionDirection.Right => ActualWidth,
|
||||
TransitioningContentControlTransitionDirection.Left => -ActualWidth,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(TransitioningContentControlTransitionDirection))
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case TransitioningContentControlTransitionType.Drop: break;
|
||||
default: throw new ArgumentOutOfRangeException(nameof(TransitioningContentControlTransitionDirection));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,496 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:TheXamlGuy.UI.WPF.Controls">
|
||||
<Style TargetType="controls:TransitioningContentControl">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:TransitioningContentControl">
|
||||
<Grid
|
||||
x:Name="Container"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalAlignment}">
|
||||
<Image
|
||||
x:Name="PreviousImageSite"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Source="{x:Null}">
|
||||
<Image.RenderTransform>
|
||||
<TransformGroup>
|
||||
<TransformGroup.Children>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1" />
|
||||
<TranslateTransform X="0" Y="0" />
|
||||
</TransformGroup.Children>
|
||||
</TransformGroup>
|
||||
</Image.RenderTransform>
|
||||
</Image>
|
||||
<ContentPresenter
|
||||
x:Name="CurrentContentPresentationSite"
|
||||
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{x:Null}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}">
|
||||
<ContentPresenter.RenderTransform>
|
||||
<TransformGroup>
|
||||
<TransformGroup.Children>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1" />
|
||||
<TranslateTransform X="0" Y="0" />
|
||||
</TransformGroup.Children>
|
||||
</TransformGroup>
|
||||
</ContentPresenter.RenderTransform>
|
||||
</ContentPresenter>
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="PresentationStates">
|
||||
<VisualState x:Name="Normal">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Fade">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SlideLeft">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SlideRight">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SlideDown">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SlideUp">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MoveLeft">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MoveRight">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MoveDown">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="MoveUp">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DropDown">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DropUp">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DropRight">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="DropLeft">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="-30"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0"
|
||||
To="30"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="CurrentContentPresentationSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="0"
|
||||
To="1"
|
||||
Duration="00:00:00.3" />
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.Opacity)"
|
||||
From="1"
|
||||
To="0"
|
||||
Duration="00:00:00.3" />
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceLeftIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)">
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.4" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.7" Value="0">
|
||||
<EasingDoubleKeyFrame.EasingFunction>
|
||||
<CircleEase EasingMode="EaseOut" />
|
||||
</EasingDoubleKeyFrame.EasingFunction>
|
||||
</EasingDoubleKeyFrame>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00.4" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousImageSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceLeftOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0"
|
||||
To="-90"
|
||||
Duration="00:00:00.2" />
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceRightIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)">
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.4" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.7" Value="0">
|
||||
<EasingDoubleKeyFrame.EasingFunction>
|
||||
<CircleEase EasingMode="EaseOut" />
|
||||
</EasingDoubleKeyFrame.EasingFunction>
|
||||
</EasingDoubleKeyFrame>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00.4" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousImageSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceRightOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.X)"
|
||||
From="0"
|
||||
To="-90"
|
||||
Duration="00:00:00.2" />
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceUpIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)">
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.4" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.7" Value="0">
|
||||
<EasingDoubleKeyFrame.EasingFunction>
|
||||
<CircleEase EasingMode="EaseOut" />
|
||||
</EasingDoubleKeyFrame.EasingFunction>
|
||||
</EasingDoubleKeyFrame>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00.4" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousImageSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceUpOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0"
|
||||
To="-90"
|
||||
Duration="00:00:00.2" />
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceDownIn">
|
||||
<Storyboard>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)">
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.4" Value="-90" />
|
||||
<EasingDoubleKeyFrame KeyTime="00:00:00.7" Value="0">
|
||||
<EasingDoubleKeyFrame.EasingFunction>
|
||||
<CircleEase EasingMode="EaseOut" />
|
||||
</EasingDoubleKeyFrame.EasingFunction>
|
||||
</EasingDoubleKeyFrame>
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Opacity)">
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00" Value="0" />
|
||||
<DiscreteDoubleKeyFrame KeyTime="00:00:00.4" Value="1" />
|
||||
</DoubleAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="PreviousImageSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="BounceDownOut">
|
||||
<Storyboard>
|
||||
<DoubleAnimation
|
||||
BeginTime="00:00:00"
|
||||
Storyboard.TargetName="PreviousImageSite"
|
||||
Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(TranslateTransform.Y)"
|
||||
From="0"
|
||||
To="-90"
|
||||
Duration="00:00:00.2" />
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="CurrentContentPresentationSite" Storyboard.TargetProperty="(UIElement.Visibility)">
|
||||
<DiscreteObjectKeyFrame KeyTime="00:00:00">
|
||||
<DiscreteObjectKeyFrame.Value>
|
||||
<Visibility>Collapsed</Visibility>
|
||||
</DiscreteObjectKeyFrame.Value>
|
||||
</DiscreteObjectKeyFrame>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public enum TransitioningContentControlTransitionDirection
|
||||
{
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
namespace TheXamlGuy.UI.WPF.Controls;
|
||||
|
||||
public enum TransitioningContentControlTransitionType
|
||||
{
|
||||
Fade,
|
||||
Move,
|
||||
Slide,
|
||||
Drop,
|
||||
Bounce
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
<RootNamespace>TheXamlGuy.UI.WPF.Controls</RootNamespace>
|
||||
<AssemblyName>TheXamlGuy.UI.WPF.Controls</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Media\Capture\Capture.csproj" />
|
||||
<ProjectReference Include="..\WPF\WPF.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF
|
||||
{
|
||||
public abstract class ValueConverter<TSource, TTarget> : MarkupExtension, IValueConverter
|
||||
{
|
||||
public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ConvertTo((TSource)value, targetType, parameter, culture);
|
||||
}
|
||||
|
||||
public object? ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return ConvertBackTo((TTarget)value, targetType, parameter, culture);
|
||||
}
|
||||
|
||||
public TTarget? Convert(TSource value)
|
||||
{
|
||||
return ConvertTo(value, null, null, null);
|
||||
}
|
||||
|
||||
public TSource? ConvertBack(TTarget value)
|
||||
{
|
||||
return ConvertBackTo(value, null, null, null);
|
||||
}
|
||||
|
||||
protected virtual TTarget? ConvertTo(TSource value, Type? targetType, object? parameter, CultureInfo? culture)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
protected virtual TSource? ConvertBackTo(TTarget value, Type? targetType, object? parameter, CultureInfo? culture)
|
||||
{
|
||||
return default;
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF
|
||||
{
|
||||
public class ValueConverterGroup : List<IValueConverter>, IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return this.Aggregate(value,
|
||||
(current, converter) => converter.Convert(current, targetType, parameter, culture));
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
internal static class ValueBoxes
|
||||
{
|
||||
internal static object CollapsedBox = Visibility.Collapsed;
|
||||
internal static object Double01Box = .1;
|
||||
internal static object Double0Box = .0;
|
||||
internal static object Double100Box = 100.0;
|
||||
internal static object Double10Box = 10.0;
|
||||
internal static object Double1Box = 1.0;
|
||||
internal static object Double200Box = 200.0;
|
||||
internal static object Double20Box = 20.0;
|
||||
internal static object Double300Box = 300.0;
|
||||
internal static object DoubleNeg1Box = -1.0;
|
||||
internal static object FalseBox = false;
|
||||
internal static object HiddenBox = Visibility.Hidden;
|
||||
internal static object HorizontalBox = Orientation.Horizontal;
|
||||
internal static object Int0Box = 0;
|
||||
internal static object Int1Box = 1;
|
||||
internal static object Int2Box = 2;
|
||||
internal static object Int5Box = 5;
|
||||
internal static object Int99Box = 99;
|
||||
internal static object TrueBox = true;
|
||||
internal static object VerticalBox = Orientation.Vertical;
|
||||
internal static object VisibleBox = Visibility.Visible;
|
||||
|
||||
internal static object BooleanBox(bool value) => value ? TrueBox : FalseBox;
|
||||
|
||||
internal static object OrientationBox(Orientation value) =>
|
||||
value == Orientation.Horizontal ? HorizontalBox : VerticalBox;
|
||||
|
||||
internal static object VisibilityBox(Visibility value)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
Visibility.Visible => VisibleBox,
|
||||
Visibility.Hidden => HiddenBox,
|
||||
Visibility.Collapsed => CollapsedBox,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public static class EventArgsExtensions
|
||||
{
|
||||
public static dynamic? GetEventArguments(this EventArgs args, string? path, IValueConverter? converter, object? converterParameter)
|
||||
{
|
||||
if (path is { Length: > 0 })
|
||||
{
|
||||
if (GetEventArgsPropertyPathValue(args, path) is object value)
|
||||
{
|
||||
if (converter is not null)
|
||||
{
|
||||
return converter.Convert(value, typeof(object), converterParameter, CultureInfo.CurrentCulture);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
private static object GetEventArgsPropertyPathValue(object args, string path)
|
||||
{
|
||||
object? value = args;
|
||||
if (path is { })
|
||||
{
|
||||
value = PropertyPathHelper.GetValue(args, path);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public static class FrameworkElementExtensions
|
||||
{
|
||||
|
||||
public static Rect? BoundsRelativeTo(this FrameworkElement source, Visual parent)
|
||||
{
|
||||
try
|
||||
{
|
||||
GeneralTransform generalTransform = source.TransformToAncestor(parent);
|
||||
return generalTransform.TransformBounds(new Rect(0, 0, source.ActualWidth, source.ActualHeight));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return Rect.Empty;
|
||||
}
|
||||
|
||||
public static bool IsTemplateParent(this FrameworkElement source, FrameworkElement target)
|
||||
{
|
||||
if (source is null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(source, target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(source?.Parent, target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
FrameworkElement? parent = source?.Parent as FrameworkElement;
|
||||
while (true)
|
||||
{
|
||||
if (parent is null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(parent, target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
parent = parent.Parent as FrameworkElement;
|
||||
}
|
||||
|
||||
FrameworkElement? templateParent = source?.TemplatedParent as FrameworkElement;
|
||||
while (true)
|
||||
{
|
||||
if (templateParent is null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ReferenceEquals(templateParent, target))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
templateParent = templateParent.TemplatedParent as FrameworkElement;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsPointerWithin(this FrameworkElement frameworkElement)
|
||||
{
|
||||
Point position = Mouse.PrimaryDevice.GetPosition(frameworkElement);
|
||||
return position.X >= 0 && position.X <= frameworkElement.ActualWidth && position.Y >= 0 &&
|
||||
position.Y <= frameworkElement.ActualHeight;
|
||||
}
|
||||
|
||||
public static IEnumerable<VisualStateGroup> FindVisualStateGroups(this FrameworkElement frameworkElement)
|
||||
{
|
||||
IEnumerable<VisualStateGroup> visualStateGroups = (IEnumerable<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(frameworkElement);
|
||||
return visualStateGroups ?? Enumerable.Empty<VisualStateGroup>();
|
||||
}
|
||||
|
||||
public static VisualStateGroup? FindVisualGroup(this FrameworkElement frameworkElement, string name)
|
||||
{
|
||||
IEnumerable<VisualStateGroup> visualStateGroups = (IEnumerable<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(frameworkElement);
|
||||
return visualStateGroups?.FirstOrDefault(x => x.Name == name);
|
||||
}
|
||||
|
||||
public static VisualState? FindVisualState(this FrameworkElement frameworkElement, string name)
|
||||
{
|
||||
Collection<VisualStateGroup> visualStateGroups = (Collection<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(frameworkElement);
|
||||
return visualStateGroups
|
||||
?.SelectMany(visualStateGroup => visualStateGroup.States.Cast<VisualState>())
|
||||
.FirstOrDefault(visualState => visualState.Name == name);
|
||||
}
|
||||
|
||||
public static VisualTransition? FindVisualTransition(this FrameworkElement frameworkElement, string name)
|
||||
{
|
||||
Collection<VisualStateGroup> visualStateGroups = (Collection<VisualStateGroup>)VisualStateManager.GetVisualStateGroups(frameworkElement);
|
||||
return visualStateGroups
|
||||
?.SelectMany(visualStateGroup => visualStateGroup.Transitions.Cast<VisualTransition>())
|
||||
.FirstOrDefault(visualTransition => visualTransition.To == name);
|
||||
}
|
||||
|
||||
public static bool IsElementFullyVisibleInContainer(this FrameworkElement frameworkElement, UIElement element)
|
||||
{
|
||||
Rect panelRect = element.TransformToAncestor(frameworkElement)
|
||||
.TransformBounds(new Rect(0.0, 0.0, element.DesiredSize.Width, element.DesiredSize.Height));
|
||||
|
||||
double roundedActualHeight = Math.Round(frameworkElement.ActualHeight, 2);
|
||||
double roundedActualWidth = Math.Round(frameworkElement.ActualWidth, 2);
|
||||
|
||||
Rect containerRect = new(0.0, 0.0, roundedActualWidth, roundedActualHeight);
|
||||
|
||||
Point topLeftPointRounded = new(Math.Round(panelRect.TopLeft.X, 2), Math.Round(panelRect.TopLeft.Y, 2));
|
||||
Point topRightPointRounded = new(Math.Round(panelRect.TopRight.X, 2), Math.Round(panelRect.TopRight.Y, 2));
|
||||
Point bottomLeftPointRounded = new(Math.Round(panelRect.BottomLeft.X, 2), Math.Round(panelRect.BottomLeft.Y, 2));
|
||||
Point bottomRightPointRounded = new(Math.Round(panelRect.BottomRight.X, 2), Math.Round(panelRect.BottomRight.Y, 2));
|
||||
|
||||
return containerRect.Contains(topLeftPointRounded) && containerRect.Contains(topRightPointRounded) &&
|
||||
containerRect.Contains(bottomLeftPointRounded) && containerRect.Contains(bottomRightPointRounded);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF
|
||||
{
|
||||
public static class MarkupExtensions
|
||||
{
|
||||
public static Binding ToBinding(this object value)
|
||||
{
|
||||
return value is Binding binding ? binding : new Binding() { Mode = BindingMode.OneWay, Source = value };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class AnimationHelper
|
||||
{
|
||||
public static ThicknessAnimation CreateAnimation(Thickness thickness = default, double milliseconds = 200)
|
||||
{
|
||||
return new(thickness, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
|
||||
{
|
||||
return new(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
|
||||
{
|
||||
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF
|
||||
{
|
||||
public static class PropertyPathHelper
|
||||
{
|
||||
private static readonly Dummy dummy = new();
|
||||
|
||||
public static object GetValue(object args, string path)
|
||||
{
|
||||
Binding binding = new(path)
|
||||
{
|
||||
Mode = BindingMode.OneTime,
|
||||
Source = args
|
||||
};
|
||||
|
||||
BindingOperations.SetBinding(dummy, Dummy.ValueProperty, binding);
|
||||
return dummy.GetValue(Dummy.ValueProperty);
|
||||
}
|
||||
|
||||
private class Dummy : DependencyObject
|
||||
{
|
||||
public static readonly DependencyProperty ValueProperty =
|
||||
DependencyProperty.Register("Value", typeof(object), typeof(Dummy),
|
||||
new UIPropertyMetadata(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class BindingProxy : Freezable
|
||||
{
|
||||
public static readonly DependencyProperty DataContextProperty =
|
||||
DependencyProperty.Register(nameof(DataContext),
|
||||
typeof(object), typeof(BindingProxy));
|
||||
|
||||
public object DataContext
|
||||
{
|
||||
get => GetValue(DataContextProperty);
|
||||
set => SetValue(DataContextProperty, value);
|
||||
}
|
||||
|
||||
protected override Freezable CreateInstanceCore()
|
||||
{
|
||||
return new BindingProxy();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class ChangePropertyExtension : TriggerExtension
|
||||
{
|
||||
private static readonly DependencyProperty PropertyTargetProperty =
|
||||
DependencyProperty.RegisterAttached("PropertyTarget",
|
||||
typeof(object), typeof(ChangePropertyExtension));
|
||||
|
||||
private static readonly DependencyProperty PropertyValueProperty =
|
||||
DependencyProperty.RegisterAttached("PropertyValue",
|
||||
typeof(object), typeof(ChangePropertyExtension));
|
||||
|
||||
private readonly string propertyName;
|
||||
|
||||
private readonly BindingBase targetBinding;
|
||||
|
||||
private readonly BindingBase valueBinding;
|
||||
|
||||
public ChangePropertyExtension(object target, string propertyName, object value)
|
||||
{
|
||||
this.targetBinding = target is BindingBase targetBinding ? targetBinding : target.ToBinding();
|
||||
this.valueBinding = value is BindingBase valueBinding ? valueBinding : value.ToBinding();
|
||||
|
||||
this.propertyName = propertyName;
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
BindingOperations.SetBinding(TargetObject, PropertyTargetProperty, targetBinding);
|
||||
if (TargetObject?.GetValue(PropertyTargetProperty) is { } target)
|
||||
{
|
||||
Type? targetType = target.GetType();
|
||||
if (targetType.GetProperty(propertyName) is PropertyInfo propertyInfo)
|
||||
{
|
||||
BindingOperations.SetBinding(TargetObject, PropertyValueProperty, valueBinding);
|
||||
object? value = TargetObject?.GetValue(PropertyValueProperty);
|
||||
|
||||
TypeConverter? converter = TypeConverterHelper.GetTypeConverter(propertyInfo.PropertyType);
|
||||
object? newValue = value;
|
||||
|
||||
if (value is not null)
|
||||
{
|
||||
if (converter?.CanConvertFrom(value.GetType()) == true)
|
||||
{
|
||||
newValue = converter.ConvertFrom(null, CultureInfo.InvariantCulture, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (converter?.CanConvertTo(propertyInfo.PropertyType) == true)
|
||||
{
|
||||
newValue = converter.ConvertTo(null, CultureInfo.InvariantCulture, value, propertyInfo.PropertyType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newValue is IEventParameter eventParameter)
|
||||
{
|
||||
newValue = eventParameter.GetParameters(args)[0];
|
||||
}
|
||||
|
||||
propertyInfo?.SetValue(target, newValue, Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,321 @@
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
[ContentProperty(nameof(Triggers))]
|
||||
public class CompositeExtension : TriggerExtension
|
||||
{
|
||||
[ConstructorArgument(nameof(Triggers))]
|
||||
public TriggerCollection Triggers { get; } = new TriggerCollection();
|
||||
|
||||
public CompositeExtension(object args0)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0, object args1, object args2, object args3, object args4,
|
||||
object args5, object args6, object args7, object args8, object args9, object args10)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0, object args1, object args2, object args3, object args4,
|
||||
object args5, object args6, object args7, object args8, object args9, object args10, object args11)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
Triggers.Add(args13);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
Triggers.Add(args13);
|
||||
Triggers.Add(args14);
|
||||
}
|
||||
|
||||
public CompositeExtension(object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14,
|
||||
object args15)
|
||||
{
|
||||
Triggers.Add(args0);
|
||||
Triggers.Add(args1);
|
||||
Triggers.Add(args2);
|
||||
Triggers.Add(args3);
|
||||
Triggers.Add(args4);
|
||||
Triggers.Add(args5);
|
||||
Triggers.Add(args6);
|
||||
Triggers.Add(args7);
|
||||
Triggers.Add(args8);
|
||||
Triggers.Add(args9);
|
||||
Triggers.Add(args10);
|
||||
Triggers.Add(args11);
|
||||
Triggers.Add(args12);
|
||||
Triggers.Add(args13);
|
||||
Triggers.Add(args14);
|
||||
Triggers.Add(args15);
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
foreach (TriggerExtension? trigger in Triggers)
|
||||
{
|
||||
trigger.Invoke(sender, args);
|
||||
}
|
||||
|
||||
base.OnInvoked(sender, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class ConditionExtension : CompositeExtension
|
||||
{
|
||||
private readonly Binding conditionBinding;
|
||||
|
||||
private static readonly DependencyProperty ConditionProperty =
|
||||
DependencyProperty.RegisterAttached("Condition",
|
||||
typeof(bool), typeof(ConditionExtension));
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0) : base(args0)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1) : base(args0, args1)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2) : base(args0, args1, args2)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3) : base(args0, args1, args2, args3)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4) : base(args0, args1, args2, args3, args4)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5) : base(args0, args1, args2, args3, args4, args5)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6) : base(args0, args1, args2, args3, args4, args5, args6)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7) : base(args0, args1, args2, args3, args4, args5, args6, args7)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9, args10)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9, args10, args11)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9, args10, args11, args12)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9, args10, args11, args12, args13)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9, args10, args11, args12, args13, args14)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
public ConditionExtension(Binding conditionBinding,
|
||||
object args0,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14,
|
||||
object args15) : base(args0, args1, args2, args3, args4, args5, args6, args7, args8, args9, args10, args11, args12, args13, args14, args15)
|
||||
{
|
||||
this.conditionBinding = conditionBinding;
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
BindingOperations.SetBinding(TargetObject, ConditionProperty, conditionBinding);
|
||||
if (TargetObject?.GetValue(ConditionProperty) is true)
|
||||
{
|
||||
base.OnInvoked(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class EventParameterExtension : MarkupExtension, IEventParameter
|
||||
{
|
||||
private readonly IValueConverter? converter;
|
||||
private readonly object? converterParameter;
|
||||
private readonly string? key;
|
||||
private readonly string? path;
|
||||
|
||||
public EventParameterExtension()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EventParameterExtension(string key, string path)
|
||||
{
|
||||
this.key = key;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public EventParameterExtension(string path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
|
||||
public EventParameterExtension(string path, IValueConverter converter)
|
||||
{
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
}
|
||||
|
||||
public EventParameterExtension(string path, IValueConverter converter, object converterParameter)
|
||||
{
|
||||
this.path = path;
|
||||
this.converter = converter;
|
||||
this.converterParameter = converterParameter;
|
||||
}
|
||||
|
||||
public List<object> GetParameters(EventArgs args)
|
||||
{
|
||||
List<object>? parameters = new();
|
||||
|
||||
dynamic? arguments = args.GetEventArguments(path, converter, converterParameter);
|
||||
if (arguments is not null)
|
||||
{
|
||||
if (arguments is ICollection<object> collection)
|
||||
{
|
||||
foreach (object? argument in collection)
|
||||
{
|
||||
parameters.Add(key is not null ? new KeyValuePair<string, object>(key, (dynamic)argument) : argument);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parameters.Add(key is not null ? new KeyValuePair<string, object>(key, arguments) : arguments);
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,448 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reflection;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Markup;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public partial class InvokeExtension : TriggerExtension
|
||||
{
|
||||
private static readonly DependencyProperty ParameterProperty =
|
||||
DependencyProperty.RegisterAttached("Parameter",
|
||||
typeof(object), typeof(InvokeExtension));
|
||||
|
||||
private static readonly DependencyProperty TargetProperty =
|
||||
DependencyProperty.RegisterAttached("Target",
|
||||
typeof(object), typeof(InvokeExtension));
|
||||
|
||||
private readonly Dictionary<Type, Delegate?> dummyHandlers = new();
|
||||
private readonly string name;
|
||||
private readonly List<object> parameters = new();
|
||||
private PropertyChangedRevoker? dataContextPropertyChangedRevoker;
|
||||
|
||||
public InvokeExtension(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
|
||||
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
|
||||
}
|
||||
|
||||
public InvokeExtension(string name,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4,
|
||||
object args5,
|
||||
object args6,
|
||||
object args7,
|
||||
object args8,
|
||||
object args9,
|
||||
object args10,
|
||||
object args11,
|
||||
object args12,
|
||||
object args13,
|
||||
object args14,
|
||||
object args15)
|
||||
{
|
||||
this.name = name;
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
parameters.Add(args3 is MarkupExtension ? args3 : args3.ToBinding());
|
||||
parameters.Add(args4 is MarkupExtension ? args4 : args4.ToBinding());
|
||||
parameters.Add(args5 is MarkupExtension ? args5 : args5.ToBinding());
|
||||
parameters.Add(args6 is MarkupExtension ? args6 : args6.ToBinding());
|
||||
parameters.Add(args7 is MarkupExtension ? args7 : args7.ToBinding());
|
||||
parameters.Add(args8 is MarkupExtension ? args8 : args8.ToBinding());
|
||||
parameters.Add(args9 is MarkupExtension ? args9 : args9.ToBinding());
|
||||
parameters.Add(args10 is MarkupExtension ? args10 : args10.ToBinding());
|
||||
parameters.Add(args11 is MarkupExtension ? args11 : args11.ToBinding());
|
||||
parameters.Add(args12 is MarkupExtension ? args12 : args12.ToBinding());
|
||||
parameters.Add(args13 is MarkupExtension ? args13 : args13.ToBinding());
|
||||
parameters.Add(args14 is MarkupExtension ? args14 : args14.ToBinding());
|
||||
parameters.Add(args15 is MarkupExtension ? args15 : args15.ToBinding());
|
||||
}
|
||||
|
||||
public Binding? BindingTarget { get; set; }
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
if (sender is DependencyObject dependencyObject)
|
||||
{
|
||||
if (!TryGetDataContext(dependencyObject, out object dataContext))
|
||||
{
|
||||
dataContextPropertyChangedRevoker = new PropertyChangedRevoker(dependencyObject, FrameworkElement.DataContextProperty, OnDataContextPropertyChangedChanged);
|
||||
void OnDataContextPropertyChangedChanged(object sender, DependencyPropertyChangedEventArgs _)
|
||||
{
|
||||
if (TryGetDataContext(dependencyObject, out dataContext))
|
||||
{
|
||||
dataContextPropertyChangedRevoker?.Dispose();
|
||||
CreaterHandler(dependencyObject, args, dataContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CreaterHandler(dependencyObject, args, dataContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetInvoke(DependencyObject sender, object dataContext, [AllowNull]out MethodInfo? methodInfo)
|
||||
{
|
||||
methodInfo = null;
|
||||
if (dataContext.GetType().GetMethod(name, BindingFlags.Public | BindingFlags.Instance) is MethodInfo dataContextMethodInfo)
|
||||
{
|
||||
methodInfo = dataContextMethodInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (sender.GetType().GetMethod(name, BindingFlags.Public | BindingFlags.Instance) is MethodInfo senderMethodInfo)
|
||||
{
|
||||
methodInfo = senderMethodInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void CreaterHandler(DependencyObject sender, EventArgs args, object dataContext)
|
||||
{
|
||||
if (TryGetInvoke(sender, dataContext, out MethodInfo? methodInfo))
|
||||
{
|
||||
ParameterInfo[] parameterInfo = methodInfo!.GetParameters();
|
||||
|
||||
List<object> parameters = new();
|
||||
foreach (object? parameter in this.parameters)
|
||||
{
|
||||
switch (parameter)
|
||||
{
|
||||
case IParameter keyedParameter:
|
||||
BindingOperations.SetBinding(sender, ParameterProperty, parameter.ToBinding());
|
||||
parameters.Add(new KeyValuePair<string, object>(keyedParameter.Key, (dynamic)sender.GetValue(ParameterProperty)));
|
||||
break;
|
||||
case IEventParameter eventParameter:
|
||||
parameters.AddRange(eventParameter.GetParameters(args));
|
||||
break;
|
||||
default:
|
||||
BindingOperations.SetBinding(sender, ParameterProperty, parameter.ToBinding());
|
||||
parameters.Add((dynamic)sender.GetValue(ParameterProperty));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodInfo is { })
|
||||
{
|
||||
methodInfo.Invoke(dataContext, parameters.Any() ? parameters.ToArray() : parameterInfo.Length > 0 ? new object?[] { null } : Array.Empty<object>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryGetDataContext(DependencyObject sender, out object dataContext)
|
||||
{
|
||||
if (BindingTarget is not null)
|
||||
{
|
||||
BindingOperations.SetBinding(sender, TargetProperty, BindingTarget);
|
||||
dataContext = sender.GetValue(TargetProperty);
|
||||
}
|
||||
else
|
||||
{
|
||||
dataContext = sender.GetValue(FrameworkElement.DataContextProperty) ?? sender.GetValue(FrameworkContentElement.DataContextProperty);
|
||||
}
|
||||
|
||||
return dataContext is not null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class ParameterExtension : Binding, IParameter
|
||||
{
|
||||
public ParameterExtension(string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public ParameterExtension(string key, string path) : base(path)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public string? Key { get; }
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class StateExtension : TriggerExtension
|
||||
{
|
||||
private static readonly DependencyProperty PropertyTargetProperty =
|
||||
DependencyProperty.RegisterAttached("PropertyTarget",
|
||||
typeof(object), typeof(StateExtension));
|
||||
|
||||
private static readonly DependencyProperty StateProperty =
|
||||
DependencyProperty.RegisterAttached("State",
|
||||
typeof(object), typeof(StateExtension));
|
||||
|
||||
private readonly BindingBase targetBinding;
|
||||
|
||||
private readonly BindingBase stateBinding;
|
||||
|
||||
public StateExtension(object target, object state)
|
||||
{
|
||||
this.targetBinding = target is BindingBase targetBinding ? targetBinding : target.ToBinding();
|
||||
this.stateBinding = state is BindingBase stateBinding ? stateBinding : state.ToBinding();
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
BindingOperations.SetBinding(TargetObject, PropertyTargetProperty, targetBinding);
|
||||
if (TargetObject?.GetValue(PropertyTargetProperty) is FrameworkElement target)
|
||||
{
|
||||
BindingOperations.SetBinding(target, StateProperty, stateBinding);
|
||||
object? state = target.GetValue(StateProperty);
|
||||
target.ApplyTemplate();
|
||||
|
||||
VisualStateManager.GoToElementState(target, (string)state, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using TheXamlGuy.UI.WPF;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class TriggerCollection : Collection<TriggerExtension>
|
||||
{
|
||||
public void Add(object item)
|
||||
{
|
||||
if (item is TriggerExtension trigger)
|
||||
{
|
||||
base.Add(trigger);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Reflection;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows;
|
||||
using System.Xaml;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
[MarkupExtensionReturnType(typeof(Delegate))]
|
||||
public class TriggerExtension : MarkupExtension
|
||||
{
|
||||
public DependencyObject? TargetObject { get; protected set; }
|
||||
|
||||
protected object? TargetInvoke { get; private set; }
|
||||
|
||||
public void Invoke(object sender, EventArgs args)
|
||||
{
|
||||
OnInvoked(sender, args);
|
||||
}
|
||||
|
||||
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||
{
|
||||
if (serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget target)
|
||||
{
|
||||
if (TargetObject is null)
|
||||
{
|
||||
if (target.TargetObject is DependencyObject dependencyObject)
|
||||
{
|
||||
TargetObject = dependencyObject;
|
||||
}
|
||||
else if (serviceProvider.GetService(typeof(IRootObjectProvider)) is IRootObjectProvider root)
|
||||
{
|
||||
TargetObject = (DependencyObject)root.RootObject;
|
||||
}
|
||||
}
|
||||
|
||||
TargetInvoke = target.TargetProperty;
|
||||
|
||||
MethodInfo invokeMethod = GetType().GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public)!;
|
||||
if (invokeMethod is null)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
switch (TargetInvoke)
|
||||
{
|
||||
case EventInfo info:
|
||||
return Delegate.CreateDelegate(info.EventHandlerType!, this, invokeMethod);
|
||||
case MethodInfo methodInfo:
|
||||
{
|
||||
if (methodInfo.GetParameters() is ParameterInfo[] methodParameters && methodParameters is { Length: 2 })
|
||||
{
|
||||
return Delegate.CreateDelegate(methodParameters[1].ParameterType, this, invokeMethod);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
protected virtual void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,35 @@
|
||||
using System.Windows.Media.Effects;
|
||||
using System.Windows;
|
||||
using System;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class BrightnessEffect : EffectBase
|
||||
{
|
||||
public static readonly DependencyProperty BrightnessProperty =
|
||||
DependencyProperty.Register(nameof(Brightness), typeof(double),
|
||||
typeof(BrightnessEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(0)));
|
||||
|
||||
private static readonly PixelShader Shader;
|
||||
|
||||
static BrightnessEffect()
|
||||
{
|
||||
Shader = new PixelShader
|
||||
{
|
||||
UriSource = new Uri("pack://application:,,,/TheXamlGuy.UI.WPF;component/Resources/Effects/BrightnessEffect.ps")
|
||||
};
|
||||
}
|
||||
|
||||
public BrightnessEffect()
|
||||
{
|
||||
PixelShader = Shader;
|
||||
|
||||
UpdateShaderValue(InputProperty);
|
||||
UpdateShaderValue(BrightnessProperty);
|
||||
}
|
||||
public double Brightness
|
||||
{
|
||||
get => (double)GetValue(BrightnessProperty);
|
||||
set => SetValue(BrightnessProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class ColorComplementEffect : EffectBase
|
||||
{
|
||||
private static readonly PixelShader Shader;
|
||||
|
||||
static ColorComplementEffect()
|
||||
{
|
||||
Shader = new PixelShader
|
||||
{
|
||||
UriSource = new Uri("pack://application:,,,/TheXamlGuy.UI.WPF;component/Resources/Effects/ColorComplementEffect.ps")
|
||||
};
|
||||
}
|
||||
|
||||
public ColorComplementEffect()
|
||||
{
|
||||
PixelShader = Shader;
|
||||
|
||||
UpdateShaderValue(InputProperty);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
using System.Windows.Media.Effects;
|
||||
using System.Windows;
|
||||
using System;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class ColorMatrixEffect : EffectBase
|
||||
{
|
||||
public static readonly DependencyProperty M11Property =
|
||||
DependencyProperty.Register("M11",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(0)));
|
||||
|
||||
public static readonly DependencyProperty M12Property =
|
||||
DependencyProperty.Register("M12",
|
||||
typeof(double),typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(5)));
|
||||
|
||||
public static readonly DependencyProperty M13Property =
|
||||
DependencyProperty.Register("M13",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(10)));
|
||||
|
||||
public static readonly DependencyProperty M14Property =
|
||||
DependencyProperty.Register("M14",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(15)));
|
||||
|
||||
public static readonly DependencyProperty M21Property =
|
||||
DependencyProperty.Register("M21",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(1)));
|
||||
|
||||
public static readonly DependencyProperty M22Property =
|
||||
DependencyProperty.Register("M22",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(6)));
|
||||
|
||||
public static readonly DependencyProperty M23Property =
|
||||
DependencyProperty.Register("M23",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(11)));
|
||||
|
||||
public static readonly DependencyProperty M24Property =
|
||||
DependencyProperty.Register("M24",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(16)));
|
||||
|
||||
public static readonly DependencyProperty M31Property =
|
||||
DependencyProperty.Register("M31",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(2)));
|
||||
|
||||
public static readonly DependencyProperty M32Property =
|
||||
DependencyProperty.Register("M32",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(7)));
|
||||
|
||||
public static readonly DependencyProperty M33Property =
|
||||
DependencyProperty.Register("M33",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(12)));
|
||||
|
||||
public static readonly DependencyProperty M34Property =
|
||||
DependencyProperty.Register("M34",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(17)));
|
||||
|
||||
public static readonly DependencyProperty M41Property =
|
||||
DependencyProperty.Register("M41",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(3)));
|
||||
|
||||
public static readonly DependencyProperty M42Property =
|
||||
DependencyProperty.Register("M42",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(8)));
|
||||
|
||||
public static readonly DependencyProperty M43Property =
|
||||
DependencyProperty.Register("M43",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(13)));
|
||||
|
||||
public static readonly DependencyProperty M44Property =
|
||||
DependencyProperty.Register("M44",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(18)));
|
||||
|
||||
public static readonly DependencyProperty M51Property =
|
||||
DependencyProperty.Register("M51",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(4)));
|
||||
|
||||
public static readonly DependencyProperty M52Property =
|
||||
DependencyProperty.Register("M52",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(9)));
|
||||
|
||||
public static readonly DependencyProperty M53Property =
|
||||
DependencyProperty.Register("M53",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(14)));
|
||||
|
||||
public static readonly DependencyProperty M54Property =
|
||||
DependencyProperty.Register("M54",
|
||||
typeof(double), typeof(ColorMatrixEffect), new PropertyMetadata(ValueBoxes.Double0Box, PixelShaderConstantCallback(19)));
|
||||
|
||||
private static readonly PixelShader Shader;
|
||||
|
||||
static ColorMatrixEffect()
|
||||
{
|
||||
Shader = new PixelShader
|
||||
{
|
||||
UriSource = new Uri("pack://application:,,,/TheXamlGuy.UI.WPF;component/Resources/Effects/ColorMatrixEffect.ps")
|
||||
};
|
||||
}
|
||||
|
||||
public ColorMatrixEffect()
|
||||
{
|
||||
PixelShader = Shader;
|
||||
|
||||
UpdateShaderValue(InputProperty);
|
||||
|
||||
UpdateShaderValue(M11Property);
|
||||
UpdateShaderValue(M21Property);
|
||||
UpdateShaderValue(M31Property);
|
||||
UpdateShaderValue(M41Property);
|
||||
UpdateShaderValue(M51Property);
|
||||
|
||||
UpdateShaderValue(M12Property);
|
||||
UpdateShaderValue(M22Property);
|
||||
UpdateShaderValue(M32Property);
|
||||
UpdateShaderValue(M42Property);
|
||||
UpdateShaderValue(M52Property);
|
||||
|
||||
UpdateShaderValue(M13Property);
|
||||
UpdateShaderValue(M23Property);
|
||||
UpdateShaderValue(M33Property);
|
||||
UpdateShaderValue(M43Property);
|
||||
UpdateShaderValue(M53Property);
|
||||
|
||||
UpdateShaderValue(M14Property);
|
||||
UpdateShaderValue(M24Property);
|
||||
UpdateShaderValue(M34Property);
|
||||
UpdateShaderValue(M44Property);
|
||||
UpdateShaderValue(M54Property);
|
||||
}
|
||||
|
||||
public double M11
|
||||
{
|
||||
get => (double)GetValue(M11Property);
|
||||
set => SetValue(M11Property, value);
|
||||
}
|
||||
public double M12
|
||||
{
|
||||
get => (double)GetValue(M12Property);
|
||||
set => SetValue(M12Property, value);
|
||||
}
|
||||
|
||||
public double M13
|
||||
{
|
||||
get => (double)GetValue(M13Property);
|
||||
set => SetValue(M13Property, value);
|
||||
}
|
||||
|
||||
public double M14
|
||||
{
|
||||
get => (double)GetValue(M14Property);
|
||||
set => SetValue(M14Property, value);
|
||||
}
|
||||
|
||||
public double M21
|
||||
{
|
||||
get => (double)GetValue(M21Property);
|
||||
set => SetValue(M21Property, value);
|
||||
}
|
||||
public double M22
|
||||
{
|
||||
get => (double)GetValue(M22Property);
|
||||
set => SetValue(M22Property, value);
|
||||
}
|
||||
|
||||
public double M23
|
||||
{
|
||||
get => (double)GetValue(M23Property);
|
||||
set => SetValue(M23Property, value);
|
||||
}
|
||||
|
||||
public double M24
|
||||
{
|
||||
get => (double)GetValue(M24Property);
|
||||
set => SetValue(M24Property, value);
|
||||
}
|
||||
|
||||
public double M31
|
||||
{
|
||||
get => (double)GetValue(M31Property);
|
||||
set => SetValue(M31Property, value);
|
||||
}
|
||||
public double M32
|
||||
{
|
||||
get => (double)GetValue(M32Property);
|
||||
set => SetValue(M32Property, value);
|
||||
}
|
||||
|
||||
public double M33
|
||||
{
|
||||
get => (double)GetValue(M33Property);
|
||||
set => SetValue(M33Property, value);
|
||||
}
|
||||
|
||||
public double M34
|
||||
{
|
||||
get => (double)GetValue(M34Property);
|
||||
set => SetValue(M34Property, value);
|
||||
}
|
||||
|
||||
public double M41
|
||||
{
|
||||
get => (double)GetValue(M41Property);
|
||||
set => SetValue(M41Property, value);
|
||||
}
|
||||
public double M42
|
||||
{
|
||||
get => (double)GetValue(M42Property);
|
||||
set => SetValue(M42Property, value);
|
||||
}
|
||||
|
||||
public double M43
|
||||
{
|
||||
get => (double)GetValue(M43Property);
|
||||
set => SetValue(M43Property, value);
|
||||
}
|
||||
|
||||
public double M44
|
||||
{
|
||||
get => (double)GetValue(M44Property);
|
||||
set => SetValue(M44Property, value);
|
||||
}
|
||||
|
||||
public double M51
|
||||
{
|
||||
get => (double)GetValue(M51Property);
|
||||
set => SetValue(M51Property, value);
|
||||
}
|
||||
public double M52
|
||||
{
|
||||
get => (double)GetValue(M52Property);
|
||||
set => SetValue(M52Property, value);
|
||||
}
|
||||
public double M53
|
||||
{
|
||||
get => (double)GetValue(M53Property);
|
||||
set => SetValue(M53Property, value);
|
||||
}
|
||||
public double M54
|
||||
{
|
||||
get => (double)GetValue(M54Property);
|
||||
set => SetValue(M54Property, value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class ContrastEffect : EffectBase
|
||||
{
|
||||
public static readonly DependencyProperty ContrastProperty =
|
||||
DependencyProperty.Register("Contrast",
|
||||
typeof(double), typeof(ContrastEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(0)));
|
||||
|
||||
private static readonly PixelShader Shader;
|
||||
|
||||
static ContrastEffect()
|
||||
{
|
||||
Shader = new PixelShader
|
||||
{
|
||||
UriSource = new Uri("pack://application:,,,/TheXamlGuy.UI.WPF;component/Resources/Effects/ContrastEffect.ps")
|
||||
};
|
||||
}
|
||||
|
||||
public ContrastEffect()
|
||||
{
|
||||
PixelShader = Shader;
|
||||
|
||||
UpdateShaderValue(InputProperty);
|
||||
UpdateShaderValue(ContrastProperty);
|
||||
}
|
||||
|
||||
public double Contrast
|
||||
{
|
||||
get => (double) GetValue(ContrastProperty);
|
||||
set => SetValue(ContrastProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Windows.Media.Effects;
|
||||
using System.Windows.Media;
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public abstract class EffectBase : ShaderEffect
|
||||
{
|
||||
public static readonly DependencyProperty InputProperty = RegisterPixelShaderSamplerProperty("Input", typeof(EffectBase), 0);
|
||||
|
||||
public Brush Input
|
||||
{
|
||||
get => (Brush)GetValue(InputProperty);
|
||||
set => SetValue(InputProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Effects;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class GrayScaleEffect : EffectBase
|
||||
{
|
||||
public static readonly DependencyProperty ScaleProperty =
|
||||
DependencyProperty.Register("Scale",
|
||||
typeof(double), typeof(GrayScaleEffect), new PropertyMetadata(ValueBoxes.Double1Box, PixelShaderConstantCallback(0)));
|
||||
|
||||
private static readonly PixelShader Shader;
|
||||
|
||||
static GrayScaleEffect()
|
||||
{
|
||||
Shader = new PixelShader
|
||||
{
|
||||
UriSource = new Uri("pack://application:,,,/TheXamlGuy.UI.WPF;component/Resources/Effects/GrayScaleEffect.ps")
|
||||
};
|
||||
}
|
||||
|
||||
public GrayScaleEffect()
|
||||
{
|
||||
PixelShader = Shader;
|
||||
|
||||
UpdateShaderValue(InputProperty);
|
||||
UpdateShaderValue(ScaleProperty);
|
||||
}
|
||||
|
||||
public double Scale
|
||||
{
|
||||
get => (double) GetValue(ScaleProperty);
|
||||
set => SetValue(ScaleProperty, value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
|
||||
[assembly: InternalsVisibleTo("TheXamlGuy.UI.WPF.Controls")]
|
||||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
|
||||
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "TheXamlGuy.UI.WPF")]
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF
|
||||
{
|
||||
public class PropertyChangedRevoker : DependencyObject, IDisposable
|
||||
{
|
||||
public static readonly DependencyProperty ValueProperty =
|
||||
DependencyProperty.Register(nameof(Value), typeof(object),
|
||||
typeof(PropertyChangedRevoker), new PropertyMetadata(null, OnValuePropertyChanged));
|
||||
|
||||
private readonly WeakReference weakPropertySource;
|
||||
|
||||
public PropertyChangedRevoker(DependencyObject propertySource, string path,
|
||||
DependencyPropertyChangedEventHandler valueChangedHandler) : this(propertySource, new PropertyPath(path),
|
||||
valueChangedHandler)
|
||||
{
|
||||
}
|
||||
|
||||
public PropertyChangedRevoker(DependencyObject propertySource, DependencyProperty property,
|
||||
DependencyPropertyChangedEventHandler valueChangedHandler) : this(propertySource,
|
||||
new PropertyPath(property), valueChangedHandler)
|
||||
{
|
||||
}
|
||||
|
||||
public PropertyChangedRevoker(DependencyObject propertySource, PropertyPath property,
|
||||
DependencyPropertyChangedEventHandler valueChangedHandler)
|
||||
{
|
||||
weakPropertySource = new WeakReference(propertySource);
|
||||
|
||||
Binding binding = new Binding
|
||||
{
|
||||
Path = property,
|
||||
Mode = BindingMode.OneWay,
|
||||
Source = propertySource
|
||||
};
|
||||
|
||||
BindingOperations.SetBinding(this, ValueProperty, binding);
|
||||
ValueChanged = valueChangedHandler;
|
||||
Property = property;
|
||||
}
|
||||
|
||||
public DependencyObject PropertySource
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return weakPropertySource.IsAlive ? weakPropertySource.Target as DependencyObject : null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get => GetValue(ValueProperty);
|
||||
set => SetValue(ValueProperty, value);
|
||||
}
|
||||
|
||||
public PropertyPath Property { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BindingOperations.ClearBinding(this, ValueProperty);
|
||||
}
|
||||
|
||||
private event DependencyPropertyChangedEventHandler ValueChanged;
|
||||
|
||||
private static void OnValuePropertyChanged(DependencyObject dependencyObject,
|
||||
DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
PropertyChangedRevoker sender = dependencyObject as PropertyChangedRevoker;
|
||||
sender?.OnValuePropertyChanged(args);
|
||||
}
|
||||
|
||||
private void OnValuePropertyChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
ValueChanged?.Invoke(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
sampler2D implicitInput : register(s0);
|
||||
float brightness : register(C0);
|
||||
|
||||
float4 main(float2 uv : TEXCOORD) : COLOR
|
||||
{
|
||||
float4 color = tex2D(implicitInput, uv);
|
||||
color.rgba *= brightness;
|
||||
|
||||
return color;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
sampler2D implicitInput : register(s0);
|
||||
|
||||
float4 main(float2 uv : TEXCOORD) : COLOR
|
||||
{
|
||||
float4 color = tex2D(implicitInput, uv);
|
||||
float4 complement;
|
||||
|
||||
complement.rgb = color.a - color.rgb;
|
||||
complement.a = color.a;
|
||||
|
||||
return complement;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,51 @@
|
||||
sampler2D implicitInput : register(s0);
|
||||
float a : register(c0);
|
||||
float b : register(c1);
|
||||
float c : register(c2);
|
||||
float d : register(c3);
|
||||
float e : register(c4);
|
||||
|
||||
float f : register(c5);
|
||||
float g : register(c6);
|
||||
float h : register(c7);
|
||||
float i : register(c8);
|
||||
float j : register(c9);
|
||||
|
||||
float k : register(c10);
|
||||
float l : register(c11);
|
||||
float m : register(c12);
|
||||
float n : register(c13);
|
||||
float o : register(c14);
|
||||
|
||||
float p : register(c15);
|
||||
float q : register(c16);
|
||||
float r : register(c17);
|
||||
float s : register(c18);
|
||||
float t : register(c19);
|
||||
|
||||
/*
|
||||
|
||||
-- -- -- --
|
||||
| a b c d e | | R |
|
||||
| f g h i j | | G |
|
||||
A = | k l m n o | C = | B | R = AC
|
||||
| p q r s t | | A |
|
||||
-- -- | 1 |
|
||||
-- --
|
||||
|
||||
*/
|
||||
|
||||
float4 main(float2 uv : TEXCOORD) : COLOR
|
||||
{
|
||||
float4 color = tex2D(implicitInput, uv);
|
||||
|
||||
float4x4 matrixA1 =
|
||||
{
|
||||
a, b, c, d,
|
||||
f, g, h, i,
|
||||
k, l, m, n,
|
||||
p, q, r, s
|
||||
};
|
||||
|
||||
return mul(matrixA1, color) + float4( e, j, o, t );
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
sampler2D implicitInput : register(s0);
|
||||
float contrast : register(C0);
|
||||
|
||||
float4 main(float2 uv : TEXCOORD) : COLOR
|
||||
{
|
||||
float4 color = tex2D(implicitInput, uv);
|
||||
float value = (1 - contrast) / 2;
|
||||
|
||||
color.rgba = color.rgba * contrast + value;
|
||||
|
||||
return color;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,15 @@
|
||||
sampler2D implicitInput : register(s0);
|
||||
float scale : register(c0);
|
||||
|
||||
float4 main(float2 uv : TEXCOORD) : COLOR
|
||||
{
|
||||
float4 color = tex2D(implicitInput, uv);
|
||||
|
||||
float4 complement;
|
||||
float intensity = (color.r + color.g + color.b) / 3;
|
||||
|
||||
complement.rgb = color.rgb * (1 - scale) + intensity * scale;
|
||||
complement.a = color.a;
|
||||
|
||||
return complement;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class SetterBaseCollection : ObservableCollection<SetterBase>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class StateTrigger : StateTriggerBase
|
||||
{
|
||||
public static readonly DependencyProperty IsActiveProperty =
|
||||
DependencyProperty.Register(nameof(IsActive),
|
||||
typeof(bool), typeof(StateTrigger),
|
||||
new PropertyMetadata(false, OnIsActivePropertyChanged));
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
get => (bool)GetValue(IsActiveProperty);
|
||||
set => SetValue(IsActiveProperty, value);
|
||||
}
|
||||
|
||||
private static void OnIsActivePropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
(dependencyObject as StateTrigger)?.SetActive((bool)args.NewValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public abstract class StateTriggerBase : DependencyObject
|
||||
{
|
||||
internal bool IsTriggerActive { get; private set; }
|
||||
|
||||
internal VisualStateExtension? Owner { get; set; }
|
||||
|
||||
protected void SetActive(bool isActive)
|
||||
{
|
||||
IsTriggerActive = isActive;
|
||||
Owner?.SetActive(IsTriggerActive);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public static class TemplateGenerator
|
||||
{
|
||||
public static DataTemplate CreateDataTemplate(Func<object> factory)
|
||||
{
|
||||
FrameworkElementFactory frameworkElementFactory = new(typeof(TemplateGeneratorControl));
|
||||
frameworkElementFactory.SetValue(TemplateGeneratorControl.FactoryProperty, factory);
|
||||
|
||||
DataTemplate dataTemplate = new(typeof(DependencyObject))
|
||||
{
|
||||
VisualTree = frameworkElementFactory
|
||||
};
|
||||
|
||||
return dataTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class TemplateGeneratorControl : ContentControl
|
||||
{
|
||||
internal static readonly DependencyProperty FactoryProperty =
|
||||
DependencyProperty.Register("Factory", typeof(Func<object>),
|
||||
typeof(TemplateGeneratorControl), new PropertyMetadata(null, OnFactoryPropertyChanged));
|
||||
|
||||
private static void OnFactoryPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (dependencyObject is TemplateGeneratorControl sender && args.NewValue is not null)
|
||||
{
|
||||
Func<object> factory = (Func<object>)args.NewValue;
|
||||
sender.Content = factory();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media.Animation;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
public class VisualStateExtension : VisualState, ISupportInitialize
|
||||
{
|
||||
public static readonly DependencyProperty IsStateTriggersAttachedProperty =
|
||||
DependencyProperty.RegisterAttached("IsStateTriggersAttached",
|
||||
typeof(bool), typeof(VisualStateExtension),
|
||||
new PropertyMetadata(false, EnableStateTriggersChanged));
|
||||
|
||||
private readonly ObservableCollection<StateTriggerBase> stateTriggers = new();
|
||||
|
||||
private Action? afterInit;
|
||||
private FrameworkElement? element;
|
||||
|
||||
private bool isInitializing;
|
||||
private bool lastState;
|
||||
private bool storyboardStateInvalidated;
|
||||
|
||||
public VisualStateExtension()
|
||||
{
|
||||
Name = Guid.NewGuid().ToString();
|
||||
|
||||
Setters = new SetterBaseCollection();
|
||||
Setters.CollectionChanged += OnSettersCollectionChanged;
|
||||
|
||||
stateTriggers.CollectionChanged += OnTriggersCollectionChanged;
|
||||
}
|
||||
|
||||
public SetterBaseCollection Setters { get; }
|
||||
public IList StateTriggers => stateTriggers;
|
||||
|
||||
internal FrameworkElement? Element
|
||||
{
|
||||
get => element;
|
||||
set
|
||||
{
|
||||
element = value;
|
||||
|
||||
if (element is not null)
|
||||
{
|
||||
if (element.IsLoaded)
|
||||
{
|
||||
UpdateActiveState();
|
||||
}
|
||||
else
|
||||
{
|
||||
element.Loaded += OnElementLoaded;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public static bool GetIsStateTriggersAttached(FrameworkElement element)
|
||||
{
|
||||
return (bool)element.GetValue(IsStateTriggersAttachedProperty);
|
||||
}
|
||||
|
||||
public static void SetIsStateTriggersAttached(FrameworkElement element, bool value)
|
||||
{
|
||||
element.SetValue(IsStateTriggersAttachedProperty, value);
|
||||
}
|
||||
|
||||
void ISupportInitialize.BeginInit()
|
||||
{
|
||||
isInitializing = true;
|
||||
}
|
||||
|
||||
void ISupportInitialize.EndInit()
|
||||
{
|
||||
isInitializing = false;
|
||||
afterInit?.Invoke();
|
||||
}
|
||||
internal void SetActive(bool active)
|
||||
{
|
||||
if (Element is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInitializing)
|
||||
{
|
||||
afterInit = () => SetActive(active);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Storyboard is not null && lastState != active)
|
||||
{
|
||||
if (active)
|
||||
{
|
||||
ClockState state = storyboardStateInvalidated ? Storyboard.GetCurrentState(Element) : ClockState.Stopped;
|
||||
|
||||
if (state == ClockState.Stopped)
|
||||
{
|
||||
Storyboard.Begin(Element, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (storyboardStateInvalidated)
|
||||
{
|
||||
Storyboard.Stop(Element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (active)
|
||||
{
|
||||
foreach (Setter setter in Setters.OfType<Setter>())
|
||||
{
|
||||
DependencyProperty property = setter.Property;
|
||||
object value = setter.Value;
|
||||
string targetName = setter.TargetName;
|
||||
DependencyObject? target = Element.FindName(targetName) as DependencyObject;
|
||||
|
||||
if (setter.Value is BindingBase binding)
|
||||
{
|
||||
BindingOperations.SetBinding(target, property, value as BindingBase);
|
||||
}
|
||||
else
|
||||
{
|
||||
target?.SetValue(property, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastState = active;
|
||||
}
|
||||
|
||||
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
base.OnPropertyChanged(args);
|
||||
if (args.Property.Name == nameof(Storyboard))
|
||||
{
|
||||
if (args.OldValue is Storyboard oldStoryBoard)
|
||||
{
|
||||
oldStoryBoard.CurrentStateInvalidated -= OnStoryboardCurrentStateInvalidated;
|
||||
}
|
||||
|
||||
if (args.NewValue is Storyboard newStoryBoard)
|
||||
{
|
||||
newStoryBoard.CurrentStateInvalidated += OnStoryboardCurrentStateInvalidated;
|
||||
}
|
||||
|
||||
storyboardStateInvalidated = false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnableStateTriggersChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (dependencyObject is FrameworkElement element)
|
||||
{
|
||||
if ((bool)args.NewValue)
|
||||
{
|
||||
VisualStateManagerContext.Set(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManagerContext.UnSet(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnElementLoaded(object sender, RoutedEventArgs args)
|
||||
{
|
||||
((FrameworkElement)sender).Loaded -= OnElementLoaded;
|
||||
UpdateActiveState();
|
||||
}
|
||||
|
||||
private void OnSettersCollectionChanged(object? sender, EventArgs args)
|
||||
{
|
||||
UpdateActiveState();
|
||||
}
|
||||
private void OnStoryboardCurrentStateInvalidated(object? sender, EventArgs args)
|
||||
{
|
||||
storyboardStateInvalidated = true;
|
||||
}
|
||||
|
||||
private void OnTriggersCollectionChanged(object? sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
if (args.NewItems is not null)
|
||||
{
|
||||
foreach (StateTriggerBase item in args.NewItems.OfType<StateTriggerBase>())
|
||||
{
|
||||
item.Owner = this;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.OldItems is not null)
|
||||
{
|
||||
foreach (StateTriggerBase? item in args.OldItems.OfType<StateTriggerBase>().Where(item => item.Owner == this))
|
||||
{
|
||||
item.Owner = null;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateActiveState();
|
||||
}
|
||||
|
||||
private void UpdateActiveState()
|
||||
{
|
||||
SetActive(stateTriggers.Any(t => t.IsTriggerActive));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
|
||||
namespace TheXamlGuy.UI.WPF;
|
||||
|
||||
internal class VisualStateManagerContext : IDisposable
|
||||
{
|
||||
private static readonly DependencyProperty VisualStateManagerContextProperty =
|
||||
DependencyProperty.RegisterAttached("VisualStateManagerContext",
|
||||
typeof(VisualStateManagerContext), typeof(VisualStateManagerContext));
|
||||
|
||||
private VisualStateManagerContext(FrameworkElement element)
|
||||
{
|
||||
Element = element;
|
||||
|
||||
VisualStateGroups = (ObservableCollection<VisualStateGroup>) element.GetValue(VisualStateManager.VisualStateGroupsProperty);
|
||||
|
||||
VisualStateGroups.CollectionChanged += CollectionChanged;
|
||||
ApplyElement(VisualStateGroups);
|
||||
}
|
||||
|
||||
private FrameworkElement? Element { get; set; }
|
||||
|
||||
private ObservableCollection<VisualStateGroup>? VisualStateGroups { get; set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
RemoveElement(VisualStateGroups);
|
||||
if (VisualStateGroups is not null)
|
||||
{
|
||||
VisualStateGroups.CollectionChanged -= CollectionChanged;
|
||||
}
|
||||
|
||||
Element = null;
|
||||
VisualStateGroups = null;
|
||||
}
|
||||
|
||||
internal static void Set(FrameworkElement element)
|
||||
{
|
||||
VisualStateManagerContext hook = new(element);
|
||||
element.SetValue(VisualStateManagerContextProperty, hook);
|
||||
}
|
||||
|
||||
internal static void UnSet(FrameworkElement element)
|
||||
{
|
||||
if (element.GetValue(VisualStateManagerContextProperty) is VisualStateManagerContext hook)
|
||||
{
|
||||
element.SetValue(VisualStateManagerContextProperty, null);
|
||||
hook.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void CollectionChanged(object? sender, NotifyCollectionChangedEventArgs args)
|
||||
{
|
||||
if (args.NewItems != null)
|
||||
{
|
||||
ApplyElement(args.NewItems.OfType<VisualStateGroup>());
|
||||
}
|
||||
|
||||
if (args.OldItems != null)
|
||||
{
|
||||
RemoveElement(args.OldItems.OfType<VisualStateGroup>());
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyElement(IEnumerable<VisualStateGroup> visualStateGroups)
|
||||
{
|
||||
foreach (VisualStateExtension? state in visualStateGroups.SelectMany(group => group.States.OfType<VisualStateExtension>()))
|
||||
{
|
||||
state.Element = Element;
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveElement(IEnumerable<VisualStateGroup>? visualStateGroups)
|
||||
{
|
||||
if (visualStateGroups is not null)
|
||||
{
|
||||
foreach (VisualStateExtension? state in visualStateGroups.SelectMany(group => group.States.OfType<VisualStateExtension>()))
|
||||
{
|
||||
state.Element = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0-windows10.0.18362.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<UseWPF>true</UseWPF>
|
||||
<RootNamespace>TheXamlGuy.UI.WPF</RootNamespace>
|
||||
<AssemblyName>TheXamlGuy.UI.WPF</AssemblyName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Effects\BrightnessEffect.fx" />
|
||||
<None Remove="Resources\Effects\BrightnessEffect.ps" />
|
||||
<None Remove="Resources\Effects\ColorComplementEffect.fx" />
|
||||
<None Remove="Resources\Effects\ColorComplementEffect.ps" />
|
||||
<None Remove="Resources\Effects\ColorMatrixEffect.fx" />
|
||||
<None Remove="Resources\Effects\ColorMatrixEffect.ps" />
|
||||
<None Remove="Resources\Effects\ContrastEffect.fx" />
|
||||
<None Remove="Resources\Effects\ContrastEffect.ps" />
|
||||
<None Remove="Resources\Effects\GrayScaleEffect.fx" />
|
||||
<None Remove="Resources\Effects\GrayScaleEffect.ps" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\UI\UI.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Effects\BrightnessEffect.fx" />
|
||||
<Resource Include="Resources\Effects\BrightnessEffect.ps" />
|
||||
<Resource Include="Resources\Effects\ColorComplementEffect.fx" />
|
||||
<Resource Include="Resources\Effects\ColorComplementEffect.ps" />
|
||||
<Resource Include="Resources\Effects\ColorMatrixEffect.fx" />
|
||||
<Resource Include="Resources\Effects\ColorMatrixEffect.ps" />
|
||||
<Resource Include="Resources\Effects\ContrastEffect.fx" />
|
||||
<Resource Include="Resources\Effects\ContrastEffect.ps" />
|
||||
<Resource Include="Resources\Effects\GrayScaleEffect.fx" />
|
||||
<Resource Include="Resources\Effects\GrayScaleEffect.ps" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user