Browse Source

Replacing inheritance-based smooth scrolling with Behavior implementation

pull/3234/head
SlimeNull 11 months ago
parent
commit
050bb96c80
  1. 3
      Directory.Packages.props
  2. 6
      EleCho.WpfSuite/AssemblyInfo.cs
  3. 69
      EleCho.WpfSuite/Controls/ListBox.cs
  4. 68
      EleCho.WpfSuite/Controls/ListBoxResources.xaml
  5. 60
      EleCho.WpfSuite/Controls/ListView.cs
  6. 68
      EleCho.WpfSuite/Controls/ListViewResources.xaml
  7. 71
      EleCho.WpfSuite/EleCho.WpfSuite.csproj
  8. 75
      EleCho.WpfSuite/MathHelper.cs
  9. 7
      EleCho.WpfSuite/Themes/Generic.xaml
  10. 26
      EleCho.WpfSuite/ValueConverters/FallbackConverter.cs
  11. 22
      EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs
  12. 17
      EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs
  13. 10
      ILSpy.sln
  14. 7
      ILSpy/Controls/ZoomScrollViewer.cs
  15. 2
      ILSpy/ILSpy.csproj
  16. 5
      ILSpy/MainWindow.xaml
  17. 18
      ILSpy/Options/DecompilerSettingsPanel.xaml
  18. 10
      ILSpy/Options/DisplaySettingsPanel.xaml
  19. 3
      ILSpy/Search/SearchPane.xaml
  20. 10
      ILSpy/TextView/DecompilerTextView.xaml
  21. 14
      LibScrollingOptimization/LibScrollingOptimization.csproj
  22. 2
      LibScrollingOptimization/ScrollViewerUtils.cs
  23. 164
      LibScrollingOptimization/SmoothScrollingBehavior.cs
  24. 4
      SharpTreeView/ICSharpCode.TreeView.csproj
  25. 2
      SharpTreeView/SharpTreeView.cs
  26. 4
      SharpTreeView/Themes/Generic.xaml

3
Directory.Packages.props

@ -30,7 +30,7 @@
<PackageVersion Include="Microsoft.NETCore.ILDAsm" Version="8.0.0" /> <PackageVersion Include="Microsoft.NETCore.ILDAsm" Version="8.0.0" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" /> <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" />
<PackageVersion Include="Microsoft.VisualStudio.Composition" Version="17.10.37" /> <PackageVersion Include="Microsoft.VisualStudio.Composition" Version="17.10.37" />
<PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" /> <PackageVersion Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.122" />
<PackageVersion Include="Mono.Cecil" Version="0.11.5" /> <PackageVersion Include="Mono.Cecil" Version="0.11.5" />
<PackageVersion Include="NaturalSort.Extension" Version="4.3.0" /> <PackageVersion Include="NaturalSort.Extension" Version="4.3.0" />
<PackageVersion Include="NSubstitute" Version="5.1.0" /> <PackageVersion Include="NSubstitute" Version="5.1.0" />
@ -46,6 +46,7 @@
<PackageVersion Include="System.Reflection.Metadata" Version="8.0.0" /> <PackageVersion Include="System.Reflection.Metadata" Version="8.0.0" />
<PackageVersion Include="System.Resources.Extensions" Version="8.0.0" /> <PackageVersion Include="System.Resources.Extensions" Version="8.0.0" />
<PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" /> <PackageVersion Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageVersion Include="TomsToolbox.Wpf" Version="2.15.0" />
<PackageVersion Include="TomsToolbox.Wpf.Styles" Version="2.14.0" /> <PackageVersion Include="TomsToolbox.Wpf.Styles" Version="2.14.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" /> <PackageVersion Include="coverlet.collector" Version="6.0.2" />
</ItemGroup> </ItemGroup>

6
EleCho.WpfSuite/AssemblyInfo.cs

@ -1,6 +0,0 @@
using System.Runtime.CompilerServices;
using System.Windows.Markup;
[assembly: System.Windows.ThemeInfo(System.Windows.ResourceDictionaryLocation.None, System.Windows.ResourceDictionaryLocation.SourceAssembly)]
[assembly: XmlnsDefinition("https://schemas.elecho.dev/wpfsuite", "EleCho.WpfSuite")]
//[assembly: XmlnsDefinition("https://schemas.elecho.dev/wpfsuite", "EleCho.WpfSuite.Markup")]

69
EleCho.WpfSuite/Controls/ListBox.cs

@ -1,69 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EleCho.WpfSuite
{
/// <inheritdoc/>
public class ListBox : System.Windows.Controls.ListBox
{
static ListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
}
/// <summary>
/// The CornerRadius property allows users to control the roundness of the corners independently by
/// setting a radius value for each corner. Radius values that are too large are scaled so that they
/// smoothly blend from corner to corner.
/// </summary>
public CornerRadius CornerRadius {
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Background when disabled
/// </summary>
public Brush DisabledBackground {
get { return (Brush)GetValue(DisabledBackgroundProperty); }
set { SetValue(DisabledBackgroundProperty, value); }
}
/// <summary>
/// BorderBrush when pressed by mouse
/// </summary>
public Brush DisabledBorderBrush {
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
}
/// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListBox));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListBox), new FrameworkPropertyMetadata(null));
}
}

68
EleCho.WpfSuite/Controls/ListBoxResources.xaml

@ -1,68 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ws="https://schemas.elecho.dev/wpfsuite">
<SolidColorBrush x:Key="ListBox.Static.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Static.Border" Color="#FFABADB3"/>
<SolidColorBrush x:Key="ListBox.Disabled.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Disabled.Border" Color="#FFD9D9D9"/>
<Style TargetType="{x:Type ws:ListBox}">
<Setter Property="Background" Value="{StaticResource ListBox.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}"/>
<Setter Property="DisabledBackground" Value="{StaticResource ListBox.Disabled.Background}"/>
<Setter Property="DisabledBorderBrush" Value="{StaticResource ListBox.Disabled.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ws:ListBox}">
<Border x:Name="Part_BD"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="1"
SnapsToDevicePixels="true">
<ws:ScrollViewer x:Name="PART_Content"
Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ws:ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Part_BD" Property="Background">
<Setter.Value>
<MultiBinding Converter="{x:Static ws:FallbackConverter.Instance}">
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="DisabledBackground"/>
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Background"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter TargetName="Part_BD" Property="BorderBrush">
<Setter.Value>
<MultiBinding Converter="{x:Static ws:FallbackConverter.Instance}">
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="DisabledBorderBrush"/>
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="BorderBrush"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

60
EleCho.WpfSuite/Controls/ListView.cs

@ -1,60 +0,0 @@
using System.Windows;
using System.Windows.Media;
namespace EleCho.WpfSuite
{
/// <inheritdoc/>
public class ListView : System.Windows.Controls.ListView
{
static ListView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListView), new FrameworkPropertyMetadata(typeof(ListView)));
}
/// <summary>
/// The CornerRadius property allows users to control the roundness of the corners independently by
/// setting a radius value for each corner. Radius values that are too large are scaled so that they
/// smoothly blend from corner to corner.
/// </summary>
public CornerRadius CornerRadius {
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
/// <summary>
/// Background when disabled
/// </summary>
public Brush DisabledBackground {
get { return (Brush)GetValue(DisabledBackgroundProperty); }
set { SetValue(DisabledBackgroundProperty, value); }
}
/// <summary>
/// BorderBrush when pressed by mouse
/// </summary>
public Brush DisabledBorderBrush {
get { return (Brush)GetValue(DisabledBorderBrushProperty); }
set { SetValue(DisabledBorderBrushProperty, value); }
}
/// <summary>
/// DependencyProperty of <see cref="CornerRadius"/> property
/// </summary>
public static readonly DependencyProperty CornerRadiusProperty =
System.Windows.Controls.Border.CornerRadiusProperty.AddOwner(typeof(ListView));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBackground"/> property
/// </summary>
public static readonly DependencyProperty DisabledBackgroundProperty =
DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
/// <summary>
/// The DependencyProperty of <see cref="DisabledBorderBrush"/> property
/// </summary>
public static readonly DependencyProperty DisabledBorderBrushProperty =
DependencyProperty.Register(nameof(DisabledBorderBrush), typeof(Brush), typeof(ListView), new FrameworkPropertyMetadata(null));
}
}

68
EleCho.WpfSuite/Controls/ListViewResources.xaml

@ -1,68 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ws="https://schemas.elecho.dev/wpfsuite">
<SolidColorBrush x:Key="ListBox.Static.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Static.Border" Color="#FFABADB3"/>
<SolidColorBrush x:Key="ListBox.Disabled.Background" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="ListBox.Disabled.Border" Color="#FFD9D9D9"/>
<Style TargetType="{x:Type ws:ListView}">
<Setter Property="Background" Value="{StaticResource ListBox.Static.Background}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBox.Static.Border}"/>
<Setter Property="DisabledBackground" Value="{StaticResource ListBox.Disabled.Background}"/>
<Setter Property="DisabledBorderBrush" Value="{StaticResource ListBox.Disabled.Border}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ws:ListView}">
<Border x:Name="Part_BD"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
Padding="1"
SnapsToDevicePixels="true">
<ws:ScrollViewer x:Name="PART_Content"
Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ws:ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Part_BD" Property="Background">
<Setter.Value>
<MultiBinding Converter="{x:Static ws:FallbackConverter.Instance}">
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="DisabledBackground"/>
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="Background"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter TargetName="Part_BD" Property="BorderBrush">
<Setter.Value>
<MultiBinding Converter="{x:Static ws:FallbackConverter.Instance}">
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="DisabledBorderBrush"/>
<Binding RelativeSource="{RelativeSource Mode=TemplatedParent}" Path="BorderBrush"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsGrouping" Value="true"/>
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

71
EleCho.WpfSuite/EleCho.WpfSuite.csproj

@ -1,71 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0-windows;net6.0-windows;net48;net47;net46;net45</TargetFrameworks>
<Nullable>enable</Nullable>
<LangVersion>latest</LangVersion>
<UseWPF>true</UseWPF>
<EnableWindowsTargeting>true</EnableWindowsTargeting>
<RootNamespace>EleCho.WpfSuite</RootNamespace>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<Version>0.6.0</Version>
<Authors>EleCho</Authors>
<Copyright>Copyright © 2024 EleCho</Copyright>
<PackageProjectUrl>https://wpfsuite.elecho.dev</PackageProjectUrl>
<PackageIcon>logo.png</PackageIcon>
<PackageTags>WPF;MVVM;XAML;Toolkit;Control;Layout;Transition;Converter;Animation;MarkupExtension;BindingProxy</PackageTags>
<Description>WPF layout panels, controls, value converters, markup extensions, transitions and utilities</Description>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/OrgEleCho/EleCho.WpfSuite</RepositoryUrl>
</PropertyGroup>
<ItemGroup>
<Page Remove="Controls\ButtonResources.xaml" />
<Page Remove="Controls\CheckBoxResources.xaml" />
<Page Remove="Controls\ComboBoxItemResources.xaml" />
<Page Remove="Controls\ComboBoxResources.xaml" />
<Page Remove="Controls\ConditionalControlResources.xaml" />
<Page Remove="Controls\ContextMenuResources.xaml" />
<Page Remove="Controls\FrameResources.xaml" />
<Page Remove="Controls\GroupBoxResources.xaml" />
<Page Remove="Controls\ImageResources.xaml" />
<Page Remove="Controls\ListBoxResources.xaml" />
<Page Remove="Controls\ListViewResources.xaml" />
<Page Remove="Controls\MenuItemResources.xaml" />
<Page Remove="Controls\MenuResources.xaml" />
<Page Remove="Controls\PasswordBoxResources.xaml" />
<Page Remove="Controls\PopupResources.xaml" />
<Page Remove="Controls\ProgressBarResources.xaml" />
<Page Remove="Controls\SlicedImageResources.xaml" />
<Page Remove="Controls\TabControlResources.xaml" />
<Page Remove="Controls\TabItemResources.xaml" />
<Page Remove="Controls\TextBoxResources.xaml" />
<Page Remove="Controls\ToggleButtonResources.xaml" />
<Page Remove="Controls\TooltipResources.xaml" />
<Page Remove="Controls\TransitioningContentControlResources.xaml" />
</ItemGroup>
<ItemGroup>
<Resource Include="Controls\ListBoxResources.xaml">
<Generator>MSBuild:Compile</Generator>
</Resource>
<Resource Include="Controls\ListViewResources.xaml" />
</ItemGroup>
<ItemGroup>
<None Update="Controls\ListBoxItemResources.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
<None Update="Controls\ListBoxResources.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
<None Update="Controls\ScrollViewerResources.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
</ItemGroup>
</Project>

75
EleCho.WpfSuite/MathHelper.cs

@ -1,75 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
namespace EleCho.WpfSuite
{
internal static class MathHelper
{
internal const double DBL_EPSILON = 2.2204460492503131e-016;
public static bool AreClose(double value1, double value2) =>
// ReSharper disable once CompareOfFloatsByEqualityOperator
value1 == value2 || IsVerySmall(value1 - value2);
public static double Lerp(double x, double y, double alpha) => x * (1.0 - alpha) + y * alpha;
public static bool IsVerySmall(double value) => Math.Abs(value) < 1E-06;
public static bool IsZero(double value) => Math.Abs(value) < 10.0 * DBL_EPSILON;
public static bool IsFiniteDouble(double x) => !double.IsInfinity(x) && !double.IsNaN(x);
public static double DoubleFromMantissaAndExponent(double x, int exp) => x * Math.Pow(2.0, exp);
public static bool GreaterThan(double value1, double value2) => value1 > value2 && !AreClose(value1, value2);
public static bool GreaterThanOrClose(double value1, double value2)
{
if (value1 <= value2)
{
return AreClose(value1, value2);
}
return true;
}
public static double Hypotenuse(double x, double y) => Math.Sqrt(x * x + y * y);
public static bool LessThan(double value1, double value2) => value1 < value2 && !AreClose(value1, value2);
public static bool LessThanOrClose(double value1, double value2)
{
if (value1 >= value2)
{
return AreClose(value1, value2);
}
return true;
}
public static double EnsureRange(double value, double? min, double? max)
{
if (min.HasValue && value < min.Value)
{
return min.Value;
}
if (max.HasValue && value > max.Value)
{
return max.Value;
}
return value;
}
public static double SafeDivide(double lhs, double rhs, double fallback)
{
if (!IsVerySmall(rhs))
{
return lhs / rhs;
}
return fallback;
}
}
}

7
EleCho.WpfSuite/Themes/Generic.xaml

@ -1,7 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ListBoxResources.xaml"/>
<ResourceDictionary Source="pack://application:,,,/EleCho.WpfSuite;component/Controls/ListViewResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

26
EleCho.WpfSuite/ValueConverters/FallbackConverter.cs

@ -1,26 +0,0 @@
using System;
using System.Globalization;
using System.Windows;
namespace EleCho.WpfSuite
{
/// <summary>
/// Fallback between multiple values, return the first non-null value
/// </summary>
public class FallbackConverter : SingletonMultiValueConverterBase<FallbackConverter>
{
/// <inheritdoc/>
public override object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture)
{
foreach (var value in values)
{
if (value is not null &&
value != DependencyProperty.UnsetValue)
return value;
}
return null;
}
}
}

22
EleCho.WpfSuite/ValueConverters/MultiValueConverterBase.cs

@ -1,22 +0,0 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace EleCho.WpfSuite
{
/// <summary>
/// Base class of multi value converter
/// </summary>
/// <typeparam name="TSelf"></typeparam>
public abstract class MultiValueConverterBase<TSelf> : IMultiValueConverter
{
/// <inheritdoc/>
public abstract object? Convert(object?[] values, Type targetType, object? parameter, CultureInfo culture);
/// <inheritdoc/>
public virtual object?[] ConvertBack(object? value, Type[] targetTypes, object? parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}

17
EleCho.WpfSuite/ValueConverters/SingletonMultiValueConverterBase.cs

@ -1,17 +0,0 @@
namespace EleCho.WpfSuite
{
/// <summary>
/// Base class of singleton multi value converter
/// </summary>
/// <typeparam name="TSelf"></typeparam>
public abstract class SingletonMultiValueConverterBase<TSelf> : MultiValueConverterBase<TSelf>
where TSelf : SingletonMultiValueConverterBase<TSelf>, new()
{
private static TSelf? _instance = null;
/// <summary>
/// Get an instance of <typeparamref name="TSelf"/>
/// </summary>
public static TSelf Instance => _instance ?? new();
}
}

10
ILSpy.sln

@ -38,7 +38,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.ILSpyX", "ICSha
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.BamlDecompiler", "ICSharpCode.BamlDecompiler\ICSharpCode.BamlDecompiler.csproj", "{81A30182-3378-4952-8880-F44822390040}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.BamlDecompiler", "ICSharpCode.BamlDecompiler\ICSharpCode.BamlDecompiler.csproj", "{81A30182-3378-4952-8880-F44822390040}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EleCho.WpfSuite", "EleCho.WpfSuite\EleCho.WpfSuite.csproj", "{486469B9-51AF-43D0-ABCE-F5FA7E5FBE4C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LibScrollingOptimization", "LibScrollingOptimization\LibScrollingOptimization.csproj", "{376D29B0-38FE-4517-A1A2-A54FBFEFF56C}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -102,10 +102,10 @@ Global
{81A30182-3378-4952-8880-F44822390040}.Debug|Any CPU.Build.0 = Debug|Any CPU {81A30182-3378-4952-8880-F44822390040}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81A30182-3378-4952-8880-F44822390040}.Release|Any CPU.ActiveCfg = Release|Any CPU {81A30182-3378-4952-8880-F44822390040}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81A30182-3378-4952-8880-F44822390040}.Release|Any CPU.Build.0 = Release|Any CPU {81A30182-3378-4952-8880-F44822390040}.Release|Any CPU.Build.0 = Release|Any CPU
{486469B9-51AF-43D0-ABCE-F5FA7E5FBE4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {376D29B0-38FE-4517-A1A2-A54FBFEFF56C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{486469B9-51AF-43D0-ABCE-F5FA7E5FBE4C}.Debug|Any CPU.Build.0 = Debug|Any CPU {376D29B0-38FE-4517-A1A2-A54FBFEFF56C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{486469B9-51AF-43D0-ABCE-F5FA7E5FBE4C}.Release|Any CPU.ActiveCfg = Release|Any CPU {376D29B0-38FE-4517-A1A2-A54FBFEFF56C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{486469B9-51AF-43D0-ABCE-F5FA7E5FBE4C}.Release|Any CPU.Build.0 = Release|Any CPU {376D29B0-38FE-4517-A1A2-A54FBFEFF56C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

7
ILSpy/Controls/ZoomScrollViewer.cs

@ -30,7 +30,7 @@ using System.Windows.Media;
namespace ICSharpCode.ILSpy.Controls namespace ICSharpCode.ILSpy.Controls
{ {
public class ZoomScrollViewer : EleCho.WpfSuite.ScrollViewer public class ZoomScrollViewer : ScrollViewer
{ {
static ZoomScrollViewer() static ZoomScrollViewer()
{ {
@ -108,7 +108,7 @@ namespace ICSharpCode.ILSpy.Controls
z.ComputedZoomButtonCollapsed = (z.AlwaysShowZoomButtons == false) && (z.CurrentZoom == 1.0); z.ComputedZoomButtonCollapsed = (z.AlwaysShowZoomButtons == false) && (z.CurrentZoom == 1.0);
} }
protected override void OnMouseWheel(MouseWheelEventArgs e) protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
{ {
if (!e.Handled && Keyboard.Modifiers == ModifierKeys.Control && MouseWheelZoom) if (!e.Handled && Keyboard.Modifiers == ModifierKeys.Control && MouseWheelZoom)
{ {
@ -165,7 +165,8 @@ namespace ICSharpCode.ILSpy.Controls
e.Handled = true; e.Handled = true;
} }
base.OnMouseWheel(e);
base.OnPreviewMouseWheel(e);
} }
internal static double RoundToOneIfClose(double val) internal static double RoundToOneIfClose(double val)

2
ILSpy/ILSpy.csproj

@ -84,9 +84,9 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\EleCho.WpfSuite\EleCho.WpfSuite.csproj" />
<ProjectReference Include="..\ICSharpCode.ILSpyX\ICSharpCode.ILSpyX.csproj" /> <ProjectReference Include="..\ICSharpCode.ILSpyX\ICSharpCode.ILSpyX.csproj" />
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" /> <ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj" />
<ProjectReference Include="..\LibScrollingOptimization\LibScrollingOptimization.csproj" />
<ProjectReference Include="..\SharpTreeView\ICSharpCode.TreeView.csproj" /> <ProjectReference Include="..\SharpTreeView\ICSharpCode.TreeView.csproj" />
</ItemGroup> </ItemGroup>

5
ILSpy/MainWindow.xaml

@ -21,6 +21,8 @@
xmlns:b="http://schemas.microsoft.com/xaml/behaviors" xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes" xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:toms="urn:TomsToolbox" xmlns:toms="urn:TomsToolbox"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:scroll="clr-namespace:LibScrollingOptimization;assembly=LibScrollingOptimization"
d:DataContext="{d:DesignInstance local:MainWindowViewModel}" d:DataContext="{d:DesignInstance local:MainWindowViewModel}"
> >
<Window.Resources> <Window.Resources>
@ -34,6 +36,9 @@
AllowDropOrder="True" AllowDropOrder="True"
AllowDrop="True" AllowDrop="True"
BorderThickness="0" Visibility="Visible"> BorderThickness="0" Visibility="Visible">
<behaviors:Interaction.Behaviors>
<scroll:SmoothScrollingBehavior/>
</behaviors:Interaction.Behaviors>
<tv:SharpTreeView.ItemContainerStyle> <tv:SharpTreeView.ItemContainerStyle>
<Style TargetType="tv:SharpTreeViewItem"> <Style TargetType="tv:SharpTreeViewItem">

18
ILSpy/Options/DecompilerSettingsPanel.xaml

@ -4,7 +4,8 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:options="clr-namespace:ICSharpCode.ILSpy.Options" xmlns:options="clr-namespace:ICSharpCode.ILSpy.Options"
xmlns:ws="https://schemas.elecho.dev/wpfsuite"> xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:scroll="clr-namespace:LibScrollingOptimization;assembly=LibScrollingOptimization">
<UserControl.Resources> <UserControl.Resources>
<CollectionViewSource x:Key="SettingsCollection" Source="{Binding Settings}"> <CollectionViewSource x:Key="SettingsCollection" Source="{Binding Settings}">
<CollectionViewSource.GroupDescriptions> <CollectionViewSource.GroupDescriptions>
@ -21,18 +22,21 @@
<ColumnDefinition Width="*" /> <ColumnDefinition Width="*" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Margin="3" Grid.ColumnSpan="3" TextWrapping="Wrap" Text="{x:Static properties:Resources.DecompilerSettingsPanelLongText}" /> <TextBlock Margin="3" Grid.ColumnSpan="3" TextWrapping="Wrap" Text="{x:Static properties:Resources.DecompilerSettingsPanelLongText}" />
<ws:ListBox Grid.Row="1" <ListBox Grid.Row="1"
ItemsSource="{Binding Source={StaticResource SettingsCollection}}" ItemsSource="{Binding Source={StaticResource SettingsCollection}}"
Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}"
BorderBrush="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}"
Padding="-1"> Padding="-1">
<ws:ListBox.ItemContainerStyle> <behaviors:Interaction.Behaviors>
<scroll:SmoothScrollingBehavior/>
</behaviors:Interaction.Behaviors>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem"> <Style TargetType="ListBoxItem">
<Setter Property="IsTabStop" Value="False"/> <Setter Property="IsTabStop" Value="False"/>
<Setter Property="Focusable" Value="False"/> <Setter Property="Focusable" Value="False"/>
</Style> </Style>
</ws:ListBox.ItemContainerStyle> </ListBox.ItemContainerStyle>
<ws:ListBox.GroupStyle> <ListBox.GroupStyle>
<GroupStyle> <GroupStyle>
<GroupStyle.Panel> <GroupStyle.Panel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
@ -57,12 +61,12 @@
</Style> </Style>
</GroupStyle.ContainerStyle> </GroupStyle.ContainerStyle>
</GroupStyle> </GroupStyle>
</ws:ListBox.GroupStyle> </ListBox.GroupStyle>
<ListBox.ItemTemplate> <ListBox.ItemTemplate>
<DataTemplate> <DataTemplate>
<CheckBox Margin="19,0,0,0" IsChecked="{Binding IsEnabled}" Content="{Binding Description}" /> <CheckBox Margin="19,0,0,0" IsChecked="{Binding IsEnabled}" Content="{Binding Description}" />
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ws:ListBox> </ListBox>
</Grid> </Grid>
</UserControl> </UserControl>

10
ILSpy/Options/DisplaySettingsPanel.xaml

@ -7,12 +7,16 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes" xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:ws="https://schemas.elecho.dev/wpfsuite" xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:scroll="clr-namespace:LibScrollingOptimization;assembly=LibScrollingOptimization"
d:DataContext="{d:DesignInstance local:DisplaySettingsViewModel}"> d:DataContext="{d:DesignInstance local:DisplaySettingsViewModel}">
<UserControl.Resources> <UserControl.Resources>
<local:FontSizeConverter x:Key="fontSizeConv" /> <local:FontSizeConverter x:Key="fontSizeConv" />
</UserControl.Resources> </UserControl.Resources>
<ws:ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<behaviors:Interaction.Behaviors>
<scroll:SmoothScrollingBehavior/>
</behaviors:Interaction.Behaviors>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<DockPanel> <DockPanel>
<Label DockPanel.Dock="Left" Content="{x:Static properties:Resources.DisplaySettingsPanel_Theme}" /> <Label DockPanel.Dock="Left" Content="{x:Static properties:Resources.DisplaySettingsPanel_Theme}" />
@ -106,5 +110,5 @@
</StackPanel> </StackPanel>
</GroupBox> </GroupBox>
</StackPanel> </StackPanel>
</ws:ScrollViewer> </ScrollViewer>
</UserControl> </UserControl>

3
ILSpy/Search/SearchPane.xaml

@ -4,7 +4,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="self" mc:Ignorable="d" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="self" mc:Ignorable="d"
xmlns:ws="https://schemas.elecho.dev/wpfsuite" xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:scroll="clr-namespace:LibScrollingOptimization;assembly=LibScrollingOptimization"
d:DesignHeight="300" d:DesignWidth="300"> d:DesignHeight="300" d:DesignWidth="300">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>

10
ILSpy/TextView/DecompilerTextView.xaml

@ -1,13 +1,15 @@
<UserControl x:Class="ICSharpCode.ILSpy.TextView.DecompilerTextView" x:ClassModifier="public" x:Name="self" <UserControl x:Class="ICSharpCode.ILSpy.TextView.DecompilerTextView" x:ClassModifier="public" x:Name="self"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties" xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls" xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
xmlns:local="clr-namespace:ICSharpCode.ILSpy.TextView" xmlns:local="clr-namespace:ICSharpCode.ILSpy.TextView"
xmlns:editing="clr-namespace:ICSharpCode.AvalonEdit.Editing;assembly=ICSharpCode.AvalonEdit" xmlns:editing="clr-namespace:ICSharpCode.AvalonEdit.Editing;assembly=ICSharpCode.AvalonEdit"
xmlns:folding="clr-namespace:ICSharpCode.AvalonEdit.Folding;assembly=ICSharpCode.AvalonEdit" xmlns:folding="clr-namespace:ICSharpCode.AvalonEdit.Folding;assembly=ICSharpCode.AvalonEdit"
xmlns:styles="urn:TomsToolbox.Wpf.Styles" xmlns:styles="urn:TomsToolbox.Wpf.Styles"
xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"> xmlns:themes="clr-namespace:ICSharpCode.ILSpy.Themes"
xmlns:scrolling="clr-namespace:LibScrollingOptimization;assembly=LibScrollingOptimization">
<UserControl.Resources> <UserControl.Resources>
<BooleanToVisibilityConverter x:Key="boolToVisibility" /> <BooleanToVisibilityConverter x:Key="boolToVisibility" />
<SolidColorBrush x:Key="waitAdornerBackgoundBrush" Color="{DynamicResource {x:Static SystemColors.WindowColorKey}}" Opacity=".75" /> <SolidColorBrush x:Key="waitAdornerBackgoundBrush" Color="{DynamicResource {x:Static SystemColors.WindowColorKey}}" Opacity=".75" />
@ -81,7 +83,11 @@
Padding="{TemplateBinding Padding}" Padding="{TemplateBinding Padding}"
BorderBrush="{TemplateBinding BorderBrush}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" BorderThickness="{TemplateBinding BorderThickness}"
TextOptions.TextFormattingMode="{Binding CurrentZoom, ElementName=PART_ScrollViewer, Converter={x:Static local:ZoomLevelToTextFormattingModeConverter.Instance}}" /> TextOptions.TextFormattingMode="{Binding CurrentZoom, ElementName=PART_ScrollViewer, Converter={x:Static local:ZoomLevelToTextFormattingModeConverter.Instance}}" >
<behaviors:Interaction.Behaviors>
<scrolling:SmoothScrollingBehavior/>
</behaviors:Interaction.Behaviors>
</controls:ZoomScrollViewer>
<ControlTemplate.Triggers> <ControlTemplate.Triggers>
<Trigger Property="WordWrap" <Trigger Property="WordWrap"
Value="True"> Value="True">

14
LibScrollingOptimization/LibScrollingOptimization.csproj

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0-windows7</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="TomsToolbox.Wpf" />
</ItemGroup>
</Project>

2
EleCho.WpfSuite/Utilities/ScrollViewerUtils.cs → LibScrollingOptimization/ScrollViewerUtils.cs

@ -3,7 +3,7 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
namespace EleCho.WpfSuite namespace LibScrollingOptimization
{ {
/// <summary> /// <summary>
/// ScrollViewer Utilities /// ScrollViewer Utilities

164
EleCho.WpfSuite/Controls/ScrollViewer.cs → LibScrollingOptimization/SmoothScrollingBehavior.cs

@ -3,29 +3,41 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Controls.Primitives; using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation; using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EleCho.WpfSuite using TomsToolbox.Wpf;
using TomsToolbox.Wpf.Interactivity;
namespace LibScrollingOptimization
{ {
/// <inheritdoc/> /// <summary>
public class ScrollViewer : System.Windows.Controls.ScrollViewer ///
/// </summary>
public class SmoothScrollingBehavior : FrameworkElementBehavior<Control>
{ {
static ScrollViewer() private ScrollViewer? _scrollViewer;
private ScrollContentPresenter? _scrollContentPresenter;
private delegate bool GetBool(ScrollViewer scrollViewer);
private static readonly GetBool _propertyHandlesMouseWheelScrollingGetter;
private static readonly IEasingFunction _scrollingAnimationEase = new CubicEase() { EasingMode = EasingMode.EaseOut };
private const long _millisecondsBetweenTouchpadScrolling = 100;
private bool _animationRunning = false;
private int _lastScrollDelta = 0;
private int _lastVerticalScrollingDelta = 0;
private int _lastHorizontalScrollingDelta = 0;
private long _lastScrollingTick;
static SmoothScrollingBehavior()
{ {
DefaultStyleKeyProperty.OverrideMetadata(typeof(ScrollViewer), new FrameworkPropertyMetadata(typeof(ScrollViewer)));
#if NETCOREAPP #if NETCOREAPP
_propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer) _propertyHandlesMouseWheelScrollingGetter = typeof(ScrollViewer)
@ -40,42 +52,67 @@ namespace EleCho.WpfSuite
#endif #endif
} }
private delegate bool GetBool(ScrollViewer scrollViewer); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_ScrollInfo")]
private static readonly GetBool _propertyHandlesMouseWheelScrollingGetter; static extern IScrollInfo GetScrollInfo(ScrollViewer scrollViewer);
private static readonly IEasingFunction _scrollingAnimationEase = new CubicEase() { EasingMode = EasingMode.EaseOut };
private const long _millisecondsBetweenTouchpadScrolling = 100;
private bool _animationRunning = false; /// <inheritdoc />
private int _lastScrollDelta = 0; protected override void OnAssociatedObjectLoaded()
private int _lastVerticalScrollingDelta = 0; {
private int _lastHorizontalScrollingDelta = 0; base.OnAssociatedObjectLoaded();
private long _lastScrollingTick;
_scrollViewer = AssociatedObject.VisualDescendantsAndSelf().OfType<ScrollViewer>().FirstOrDefault();
private FrameworkElement? _scrollContentPresenter; if (_scrollViewer == null)
return;
_scrollViewer.PreviewMouseWheel += ScrollViewer_PreviewMouseWheel;
_scrollContentPresenter = _scrollViewer.VisualDescendants().OfType<ScrollContentPresenter>().FirstOrDefault();
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnApplyTemplate() protected override void OnAssociatedObjectUnloaded()
{ {
base.OnApplyTemplate(); base.OnAssociatedObjectUnloaded();
_scrollContentPresenter = GetTemplateChild("PART_ScrollContentPresenter") as FrameworkElement; if (_scrollViewer == null)
return;
_scrollViewer.PreviewMouseWheel -= ScrollViewer_PreviewMouseWheel;
}
private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!ScrollWithWheelDelta)
{
return;
}
else
{
Debug.WriteLine(e.Delta);
CoreScrollWithWheelDelta(e);
}
} }
private void CoreScrollWithWheelDelta(MouseWheelEventArgs e) private void CoreScrollWithWheelDelta(MouseWheelEventArgs e)
{ {
if (_scrollViewer == null || _scrollContentPresenter == null)
return;
if (e.Handled) if (e.Handled)
{ {
return; return;
} }
if (!AlwaysHandleMouseWheelScrolling && if (!AlwaysHandleMouseWheelScrolling &&
!_propertyHandlesMouseWheelScrollingGetter.Invoke(this)) !_propertyHandlesMouseWheelScrollingGetter.Invoke(_scrollViewer))
{ {
return; return;
} }
bool vertical = ExtentHeight > 0; bool vertical = _scrollViewer.ExtentHeight > 0;
bool horizontal = ExtentWidth > 0; bool horizontal = _scrollViewer.ExtentWidth > 0;
var tickCount = Environment.TickCount; var tickCount = Environment.TickCount;
var isTouchpadScrolling = var isTouchpadScrolling =
@ -99,31 +136,31 @@ namespace EleCho.WpfSuite
if (vertical) if (vertical)
{ {
if (ScrollInfo is IScrollInfo scrollInfo) if (GetScrollInfo(_scrollViewer) is IScrollInfo scrollInfo)
{ {
// 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta
scrollDelta *= scrollInfo.ViewportHeight / (_scrollContentPresenter?.ActualHeight ?? ActualHeight); scrollDelta *= scrollInfo.ViewportHeight / (_scrollContentPresenter?.ActualHeight ?? _scrollViewer.ActualHeight);
} }
var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastVerticalScrollingDelta); var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastVerticalScrollingDelta);
var nowOffset = sameDirectionAsLast && _animationRunning ? VerticalOffsetTarget : VerticalOffset; var nowOffset = sameDirectionAsLast && _animationRunning ? VerticalOffsetTarget : _scrollViewer.VerticalOffset;
var newOffset = nowOffset - scrollDelta; var newOffset = nowOffset - scrollDelta;
if (newOffset < 0) if (newOffset < 0)
newOffset = 0; newOffset = 0;
if (newOffset > ScrollableHeight) if (newOffset > _scrollViewer.ScrollableHeight)
newOffset = ScrollableHeight; newOffset = _scrollViewer.ScrollableHeight;
SetValue(VerticalOffsetTargetPropertyKey, newOffset); SetValue(VerticalOffsetTargetPropertyKey, newOffset);
BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, null); _scrollViewer.BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, null);
if (!EnableScrollingAnimation || isTouchpadScrolling) if (!EnableScrollingAnimation || isTouchpadScrolling)
{ {
ScrollToVerticalOffset(newOffset); _scrollViewer.ScrollToVerticalOffset(newOffset);
} }
else else
{ {
var diff = newOffset - VerticalOffset; var diff = newOffset - _scrollViewer.VerticalOffset;
var absDiff = Math.Abs(diff); var absDiff = Math.Abs(diff);
var duration = ScrollingAnimationDuration; var duration = ScrollingAnimationDuration;
if (absDiff < Mouse.MouseWheelDeltaForOneLine) if (absDiff < Mouse.MouseWheelDeltaForOneLine)
@ -134,45 +171,45 @@ namespace EleCho.WpfSuite
DoubleAnimation doubleAnimation = new DoubleAnimation() { DoubleAnimation doubleAnimation = new DoubleAnimation() {
EasingFunction = _scrollingAnimationEase, EasingFunction = _scrollingAnimationEase,
Duration = duration, Duration = duration,
From = VerticalOffset, From = _scrollViewer.VerticalOffset,
To = newOffset, To = newOffset,
}; };
doubleAnimation.Completed += DoubleAnimation_Completed; doubleAnimation.Completed += DoubleAnimation_Completed;
_animationRunning = true; _animationRunning = true;
BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); _scrollViewer.BeginAnimation(ScrollViewerUtils.VerticalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace);
} }
_lastVerticalScrollingDelta = e.Delta; _lastVerticalScrollingDelta = e.Delta;
} }
else if (horizontal) else if (horizontal)
{ {
if (ScrollInfo is IScrollInfo scrollInfo) if (GetScrollInfo(_scrollViewer) is IScrollInfo scrollInfo)
{ {
// 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta // 考虑到 VirtualizingPanel 可能是虚拟的大小, 所以这里需要校正 Delta
scrollDelta *= scrollInfo.ViewportWidth / (_scrollContentPresenter?.ActualWidth ?? ActualWidth); scrollDelta *= scrollInfo.ViewportWidth / (_scrollContentPresenter?.ActualWidth ?? _scrollViewer.ActualWidth);
} }
var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastHorizontalScrollingDelta); var sameDirectionAsLast = Math.Sign(e.Delta) == Math.Sign(_lastHorizontalScrollingDelta);
var nowOffset = sameDirectionAsLast && _animationRunning ? HorizontalOffsetTarget : HorizontalOffset; var nowOffset = sameDirectionAsLast && _animationRunning ? HorizontalOffsetTarget : _scrollViewer.HorizontalOffset;
var newOffset = nowOffset - scrollDelta; var newOffset = nowOffset - scrollDelta;
if (newOffset < 0) if (newOffset < 0)
newOffset = 0; newOffset = 0;
if (newOffset > ScrollableWidth) if (newOffset > _scrollViewer.ScrollableWidth)
newOffset = ScrollableWidth; newOffset = _scrollViewer.ScrollableWidth;
SetValue(HorizontalOffsetTargetPropertyKey, newOffset); SetValue(HorizontalOffsetTargetPropertyKey, newOffset);
BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, null); _scrollViewer.BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, null);
if (!EnableScrollingAnimation || isTouchpadScrolling) if (!EnableScrollingAnimation || isTouchpadScrolling)
{ {
ScrollToHorizontalOffset(newOffset); _scrollViewer.ScrollToHorizontalOffset(newOffset);
} }
else else
{ {
var diff = newOffset - HorizontalOffset; var diff = newOffset - _scrollViewer.HorizontalOffset;
var absDiff = Math.Abs(diff); var absDiff = Math.Abs(diff);
var duration = ScrollingAnimationDuration; var duration = ScrollingAnimationDuration;
if (absDiff < Mouse.MouseWheelDeltaForOneLine) if (absDiff < Mouse.MouseWheelDeltaForOneLine)
@ -183,14 +220,14 @@ namespace EleCho.WpfSuite
DoubleAnimation doubleAnimation = new DoubleAnimation() { DoubleAnimation doubleAnimation = new DoubleAnimation() {
EasingFunction = _scrollingAnimationEase, EasingFunction = _scrollingAnimationEase,
Duration = duration, Duration = duration,
From = HorizontalOffset, From = _scrollViewer.HorizontalOffset,
To = newOffset, To = newOffset,
}; };
doubleAnimation.Completed += DoubleAnimation_Completed; doubleAnimation.Completed += DoubleAnimation_Completed;
_animationRunning = true; _animationRunning = true;
BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace); _scrollViewer.BeginAnimation(ScrollViewerUtils.HorizontalOffsetProperty, doubleAnimation, HandoffBehavior.SnapshotAndReplace);
} }
_lastHorizontalScrollingDelta = e.Delta; _lastHorizontalScrollingDelta = e.Delta;
@ -207,21 +244,6 @@ namespace EleCho.WpfSuite
_animationRunning = false; _animationRunning = false;
} }
/// <inheritdoc/>
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!ScrollWithWheelDelta)
{
base.OnMouseWheel(e);
}
else
{
Debug.WriteLine(e.Delta);
CoreScrollWithWheelDelta(e);
}
}
/// <summary> /// <summary>
/// The horizontal offset of scrolling target /// The horizontal offset of scrolling target
/// </summary> /// </summary>
@ -297,13 +319,13 @@ namespace EleCho.WpfSuite
/// The key needed set a read-only property /// The key needed set a read-only property
/// </summary> /// </summary>
public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey = public static readonly DependencyPropertyKey HorizontalOffsetTargetPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); DependencyProperty.RegisterReadOnly(nameof(HorizontalOffsetTarget), typeof(double), typeof(SmoothScrollingBehavior), new PropertyMetadata(0.0));
/// <summary> /// <summary>
/// The key needed set a read-only property /// The key needed set a read-only property
/// </summary> /// </summary>
public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey = public static readonly DependencyPropertyKey VerticalOffsetTargetPropertyKey =
DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(ScrollViewer), new PropertyMetadata(0.0)); DependencyProperty.RegisterReadOnly(nameof(VerticalOffsetTarget), typeof(double), typeof(SmoothScrollingBehavior), new PropertyMetadata(0.0));
/// <summary> /// <summary>
/// The key needed set a read-only property /// The key needed set a read-only property
@ -405,40 +427,40 @@ namespace EleCho.WpfSuite
/// The DependencyProperty of <see cref="ScrollWithWheelDelta"/> property. /// The DependencyProperty of <see cref="ScrollWithWheelDelta"/> property.
/// </summary> /// </summary>
public static readonly DependencyProperty ScrollWithWheelDeltaProperty = public static readonly DependencyProperty ScrollWithWheelDeltaProperty =
DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(ScrollViewer), DependencyProperty.RegisterAttached(nameof(ScrollWithWheelDelta), typeof(bool), typeof(SmoothScrollingBehavior),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="EnableScrollingAnimation"/> property. /// The DependencyProperty of <see cref="EnableScrollingAnimation"/> property.
/// </summary> /// </summary>
public static readonly DependencyProperty EnableScrollingAnimationProperty = public static readonly DependencyProperty EnableScrollingAnimationProperty =
DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(ScrollViewer), DependencyProperty.RegisterAttached(nameof(EnableScrollingAnimation), typeof(bool), typeof(SmoothScrollingBehavior),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="ScrollingAnimationDuration"/> property. /// The DependencyProperty of <see cref="ScrollingAnimationDuration"/> property.
/// </summary> /// </summary>
public static readonly DependencyProperty ScrollingAnimationDurationProperty = public static readonly DependencyProperty ScrollingAnimationDurationProperty =
DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(ScrollViewer), DependencyProperty.RegisterAttached(nameof(ScrollingAnimationDuration), typeof(Duration), typeof(SmoothScrollingBehavior),
new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration); new FrameworkPropertyMetadata(new Duration(TimeSpan.FromMilliseconds(250)), FrameworkPropertyMetadataOptions.Inherits), ValidateScrollingAnimationDuration);
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="AlwaysHandleMouseWheelScrolling"/> property /// The DependencyProperty of <see cref="AlwaysHandleMouseWheelScrolling"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty = public static readonly DependencyProperty AlwaysHandleMouseWheelScrollingProperty =
DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(ScrollViewer), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits)); DependencyProperty.RegisterAttached(nameof(AlwaysHandleMouseWheelScrolling), typeof(bool), typeof(SmoothScrollingBehavior), new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="MouseScrollDeltaFactor"/> property /// The DependencyProperty of <see cref="MouseScrollDeltaFactor"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty MouseScrollDeltaFactorProperty = public static readonly DependencyProperty MouseScrollDeltaFactorProperty =
DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0)); DependencyProperty.Register(nameof(MouseScrollDeltaFactor), typeof(double), typeof(SmoothScrollingBehavior), new PropertyMetadata(1.0));
/// <summary> /// <summary>
/// The DependencyProperty of <see cref="TouchpadScrollDeltaFactor"/> property /// The DependencyProperty of <see cref="TouchpadScrollDeltaFactor"/> property
/// </summary> /// </summary>
public static readonly DependencyProperty TouchpadScrollDeltaFactorProperty = public static readonly DependencyProperty TouchpadScrollDeltaFactorProperty =
DependencyProperty.Register(nameof(TouchpadScrollDeltaFactor), typeof(double), typeof(ScrollViewer), new PropertyMetadata(1.0)); DependencyProperty.Register(nameof(TouchpadScrollDeltaFactor), typeof(double), typeof(SmoothScrollingBehavior), new PropertyMetadata(1.0));
private static bool ValidateScrollingAnimationDuration(object value) private static bool ValidateScrollingAnimationDuration(object value)
=> value is Duration duration && duration.HasTimeSpan; => value is Duration duration && duration.HasTimeSpan;

4
SharpTreeView/ICSharpCode.TreeView.csproj

@ -25,8 +25,4 @@
<PackageReference Include="TomsToolbox.Wpf.Styles" /> <PackageReference Include="TomsToolbox.Wpf.Styles" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\EleCho.WpfSuite\EleCho.WpfSuite.csproj" />
</ItemGroup>
</Project> </Project>

2
SharpTreeView/SharpTreeView.cs

@ -30,7 +30,7 @@ using System.Windows.Threading;
namespace ICSharpCode.TreeView namespace ICSharpCode.TreeView
{ {
public class SharpTreeView : EleCho.WpfSuite.ListView public class SharpTreeView : ListView
{ {
static SharpTreeView() static SharpTreeView()
{ {

4
SharpTreeView/Themes/Generic.xaml

@ -86,7 +86,7 @@
BorderThickness="1" BorderThickness="1"
BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" BorderBrush="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"
Padding="0 1 2 0"> Padding="0 1 2 0">
<ws:ScrollViewer Name="PART_ContentHost" /> <ScrollViewer Name="PART_ContentHost" />
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter.Value> </Setter.Value>
@ -94,7 +94,7 @@
</Style> </Style>
<Style TargetType="{x:Type Default:SharpTreeView}" <Style TargetType="{x:Type Default:SharpTreeView}"
BasedOn="{StaticResource {x:Type ws:ListView}}"> BasedOn="{StaticResource {x:Static styles:ResourceKeys.ListBoxStyle}}">
<Setter Property="Background" Value="Transparent"/> <Setter Property="Background" Value="Transparent"/>
<Style.Triggers> <Style.Triggers>
<Trigger Property="ShowRoot" <Trigger Property="ShowRoot"

Loading…
Cancel
Save