├── .editorconfig
├── .gitattributes
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── HN.Controls.ImageEx.sln
├── LICENSE
├── README.md
├── appveyor.yml
├── build.cake
├── build.ps1
├── demo
├── UwpDemo
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Assets
│ │ ├── LockScreenLogo.scale-200.png
│ │ ├── SplashScreen.scale-200.png
│ │ ├── Square150x150Logo.scale-200.png
│ │ ├── Square44x44Logo.scale-200.png
│ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ │ ├── StoreLogo.png
│ │ ├── Wide310x150Logo.scale-200.png
│ │ ├── bliss.png
│ │ ├── newtons_cradle.gif
│ │ └── unicorn.png
│ ├── Package.appxmanifest
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ └── Default.rd.xml
│ ├── UwpDemo.csproj
│ └── Views
│ │ ├── AnimationView.xaml
│ │ ├── AnimationView.xaml.cs
│ │ ├── CornerRadiusView.xaml
│ │ ├── CornerRadiusView.xaml.cs
│ │ ├── LazyLoadingView.xaml
│ │ ├── LazyLoadingView.xaml.cs
│ │ ├── MainView.xaml
│ │ ├── MainView.xaml.cs
│ │ ├── MemoryUsageView.xaml
│ │ ├── MemoryUsageView.xaml.cs
│ │ ├── ProgressView.xaml
│ │ ├── ProgressView.xaml.cs
│ │ ├── RootView.xaml
│ │ ├── RootView.xaml.cs
│ │ ├── ShadowView.xaml
│ │ └── ShadowView.xaml.cs
└── WpfDemo
│ ├── App.config
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Images
│ ├── bliss.png
│ ├── newtons_cradle.gif
│ └── unicorn.png
│ ├── Views
│ ├── AnimationView.xaml
│ ├── AnimationView.xaml.cs
│ ├── CornerRadiusView.xaml
│ ├── CornerRadiusView.xaml.cs
│ ├── LazyLoadingView.xaml
│ ├── LazyLoadingView.xaml.cs
│ ├── MainView.xaml
│ ├── MainView.xaml.cs
│ ├── MemoryUsageView.xaml
│ ├── MemoryUsageView.xaml.cs
│ ├── ProgressView.xaml
│ ├── ProgressView.xaml.cs
│ ├── ShadowView.xaml
│ ├── ShadowView.xaml.cs
│ ├── StretchView.xaml
│ └── StretchView.xaml.cs
│ └── WpfDemo.csproj
├── src
├── HN.Controls.ImageEx.Core
│ ├── Cache
│ │ ├── DiskCacheBase.cs
│ │ └── IDiskCache.cs
│ ├── Constants.cs
│ ├── Controls
│ │ ├── ImageExFailedEventArgs.cs
│ │ └── ImageExFailedEventHandler.cs
│ ├── Extensions
│ │ └── UriExtensions.cs
│ ├── HN.Controls.ImageEx.Core.csproj
│ ├── HN.Controls.ImageEx.Core.nuspec
│ ├── Http
│ │ ├── HttpDownloadProgress.cs
│ │ └── ThrottlingDelegatingHandler.cs
│ ├── Media
│ │ ├── ImageBrushExFailedEventArgs.cs
│ │ └── ImageBrushExFailedEventHandler.cs
│ ├── Pipes
│ │ ├── ByteArrayPipe.cs
│ │ ├── DiskCachePipe.cs
│ │ ├── ILoadingContext.cs
│ │ ├── ILoadingPipe.cs
│ │ ├── LoadingContext.cs
│ │ ├── LoadingPipeBase.cs
│ │ ├── LoadingPipeBuilder.cs
│ │ ├── LoadingPipeDelegate.cs
│ │ ├── MemoryCachePipe.cs
│ │ ├── StringPipeBase.cs
│ │ └── UriPipeBase.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── Services
│ │ ├── IDesignModeService.cs
│ │ ├── IImageExOptions.cs
│ │ ├── IImageLoader.cs
│ │ ├── ImageExOptions.cs
│ │ └── ImageExOptionsExtensions.cs
├── HN.Controls.ImageEx.Uwp
│ ├── Animation
│ │ └── AnimationBridge.cs
│ ├── Cache
│ │ ├── DiskCache.cs
│ │ ├── FINDEX_INFO_LEVELS.cs
│ │ ├── FINDEX_SEARCH_OPS.cs
│ │ ├── UwpIONative.cs
│ │ └── WIN32_FIND_DATA.cs
│ ├── Controls
│ │ ├── ImageEx.Animation.cs
│ │ ├── ImageEx.CornerRadius.cs
│ │ ├── ImageEx.Design.cs
│ │ ├── ImageEx.Design.xaml
│ │ ├── ImageEx.Layout.cs
│ │ ├── ImageEx.LazyLoading.cs
│ │ ├── ImageEx.NineGrid.cs
│ │ ├── ImageEx.Retry.cs
│ │ ├── ImageEx.Shadow.cs
│ │ ├── ImageEx.Stretch.cs
│ │ ├── ImageEx.cs
│ │ ├── ImageEx.xaml
│ │ ├── ImageExAssist.cs
│ │ ├── ImageExAssist.xaml
│ │ ├── ImageExShadow.cs
│ │ └── StretchHelper.cs
│ ├── HN.Controls.ImageEx.Uwp.csproj
│ ├── HN.Controls.ImageEx.Uwp.nuspec
│ ├── Media
│ │ ├── ImageBrushEx.Retry.cs
│ │ ├── ImageBrushEx.cs
│ │ ├── ImageSurfaceFailedStatusException.cs
│ │ └── SvgImageFailedStatusException.cs
│ ├── Models
│ │ ├── IImageExDisplaySource.cs
│ │ ├── IMultiplyFrameImageExDisplaySource.cs
│ │ ├── ISingleFrameImageExDisplaySource.cs
│ │ ├── ImageExFrame.cs
│ │ ├── ImageExSource.cs
│ │ ├── MultiplyFrameImageExDisplaySource.cs
│ │ └── SingleFrameImageExDisplaySource.cs
│ ├── Pipes
│ │ ├── StreamToCompositionSurfacePipe.cs
│ │ ├── StreamToImageExSourcePipe.cs
│ │ ├── StreamToImageSourcePipe.cs
│ │ ├── StringPipe.cs
│ │ └── UriPipe.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ └── HN.Controls.ImageEx.Uwp.rd.xml
│ ├── Services
│ │ ├── DesignModeService.cs
│ │ ├── ImageExOptionsExtensions.cs
│ │ ├── ImageExService.cs
│ │ └── ImageLoader.cs
│ ├── Themes
│ │ └── Generic.xaml
│ └── VisualStudioToolsManifest.xml
├── HN.Controls.ImageEx.Wpf
│ ├── Animation
│ │ └── AnimationBridge.cs
│ ├── Cache
│ │ └── DiskCache.cs
│ ├── Controls
│ │ ├── ImageEx.Animation.cs
│ │ ├── ImageEx.CornerRadius.cs
│ │ ├── ImageEx.Design.cs
│ │ ├── ImageEx.Design.xaml
│ │ ├── ImageEx.Layout.cs
│ │ ├── ImageEx.LazyLoading.cs
│ │ ├── ImageEx.NineGrid.cs
│ │ ├── ImageEx.Retry.cs
│ │ ├── ImageEx.Shadow.cs
│ │ ├── ImageEx.Stretch.cs
│ │ ├── ImageEx.cs
│ │ ├── ImageEx.xaml
│ │ ├── ImageExAssist.cs
│ │ ├── ImageExAssist.xaml
│ │ ├── ImageExShadow.cs
│ │ └── StretchHelper.cs
│ ├── HN.Controls.ImageEx.Wpf.csproj
│ ├── HN.Controls.ImageEx.Wpf.nuspec
│ ├── Media
│ │ ├── ImageBrushExExtension.Retry.cs
│ │ └── ImageBrushExExtension.cs
│ ├── Models
│ │ ├── IImageExDisplaySource.cs
│ │ ├── IMultiplyFrameImageExDisplaySource.cs
│ │ ├── ISingleFrameImageExDisplaySource.cs
│ │ ├── ImageExFrame.cs
│ │ ├── ImageExSource.cs
│ │ ├── MultiplyFrameImageExDisplaySource.cs
│ │ └── SingleFrameImageExDisplaySource.cs
│ ├── Pipes
│ │ ├── StreamToImageExSourcePipe.cs
│ │ ├── StreamToImageSourcePipe.cs
│ │ ├── StringPipe.cs
│ │ └── UriPipe.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Services
│ │ ├── DesignModeService.cs
│ │ ├── ImageExOptionsExtensions.cs
│ │ ├── ImageExService.cs
│ │ └── ImageLoader.cs
│ ├── Themes
│ │ └── Generic.xaml
│ └── app.config
└── SolutionInfo.cs
├── test
└── HN.Controls.ImageEx.Core.Tests
│ ├── HN.Controls.ImageEx.Core.Tests.csproj
│ ├── Pipes
│ └── ByteArrayPipeTests.cs
│ └── Services
│ └── TestDesignModeService.cs
└── tools
└── packages.config
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | push:
4 | branches:
5 | - master
6 | pull_request:
7 | jobs:
8 | build:
9 | name: Build
10 | runs-on: windows-latest
11 |
12 | steps:
13 | - name: Checkout
14 | uses: actions/checkout@master
15 |
16 | - name: Run build script
17 | run: .\build.ps1
18 | shell: pwsh
19 | env:
20 | NUGET_APIKEY: ${{ secrets.NUGET_APIKEY }}
21 |
22 | - name: Upload nupkg
23 | uses: actions/upload-artifact@master
24 | with:
25 | name: Nuget Packages
26 | path: ./artifacts
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 h82258652
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HN.Controls.ImageEx
2 | [](https://github.com/h82258652/HN.Controls.ImageEx/workflows/CI/badge.svg)
3 |
4 | | Package | Nuget |
5 | | - | - |
6 | | HN.Controls.ImageEx.Core | [](https://www.nuget.org/packages/HN.Controls.ImageEx.Core) |
7 | | HN.Controls.ImageEx.Wpf | [](https://www.nuget.org/packages/HN.Controls.ImageEx.Wpf) |
8 | | HN.Controls.ImageEx.Uwp | [](https://www.nuget.org/packages/HN.Controls.ImageEx.Uwp) |
9 |
10 | An enhanced image for WPF and UWP.
11 | WPF version for .net framework 4.6.2 and .net core 3.1
12 | UWP version for 17763
13 | The usage please see the demo project.
14 |
15 | ## Notice!
16 | Due to there are some performance problems in SkiaSharp, the 2.x.x version will stop developing. You can use the 1.x.x version if you meet the performance problems. 3.x.x version is on the plan.
17 |
18 | ### WPF Support
19 | | | ImageEx | ImageBrushEx |
20 | | - | - | - |
21 | | Disk Cache | :heavy_check_mark: | :heavy_check_mark: |
22 | | Placeholder | :heavy_check_mark: | |
23 | | Loading Template | :heavy_check_mark: | |
24 | | Failed Template | :heavy_check_mark: | |
25 | | Retry | :heavy_check_mark: | :heavy_check_mark: |
26 | | Lazy Loading | :heavy_check_mark: | |
27 | | CornerRadius | :heavy_check_mark: | |
28 | | Shadow | :heavy_check_mark: | |
29 | | Gif | :heavy_check_mark: | |
30 | | Webp | :heavy_check_mark: | |
31 | | Fade in animation | :heavy_check_mark: | |
32 |
33 | ### UWP Support
34 | | | ImageEx | ImageBrushEx |
35 | | - | - | - |
36 | | Disk Cache | :heavy_check_mark: | :heavy_check_mark: |
37 | | Placeholder | :heavy_check_mark: | |
38 | | Loading Template | :heavy_check_mark: | |
39 | | Failed Template | :heavy_check_mark: | |
40 | | Retry | :heavy_check_mark: | :heavy_check_mark: |
41 | | Lazy Loading | :heavy_check_mark: | |
42 | | CornerRadius | :heavy_check_mark: | |
43 | | Shadow | :heavy_check_mark: | |
44 | | Gif | :heavy_check_mark: | |
45 | | Webp | :heavy_check_mark: | :heavy_check_mark: |
46 | | Fade in animation | :heavy_check_mark: | |
47 |
48 | ### Next plan:
49 | - [x] Update the lazy loading, support set the thresholds and give a default value. (Now is 300px)
50 | - [x] Built-in fade in animation while loaded image success. (Default duration is 0 second)
51 | - [x] Use ```SkiaSharp``` to resolve the image.
52 | - [x] ```CornerRadius``` support.
53 | - [x] Built-in shadow, same API for WPF and UWP.
54 | - [x] Gif animation controller, including ```Play```, ```Pause```, ```GotoFrame```, ```RepeatBehavior```(use metadata or custom), ```SpeedRatio```.
55 | - [x] Same API for WPF and UWP, such as ```StretchDirection```(exist in WPF but not UWP), ```NineGrid```(exist in UWP but not WPF).
56 | - [ ] Add ```IImageEx``` interface for ```ImageEx```.
57 | - [ ] Improve performance.
58 | - [ ] Target .net 5.
59 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.0.{build}
2 | pull_requests:
3 | do_not_increment_build_number: true
4 | image: Visual Studio 2017
5 | configuration: Release
6 | assembly_info:
7 | patch: true
8 | file: '**\AssemblyInfo.*'
9 | assembly_version: '{version}'
10 | assembly_file_version: '{version}'
11 | assembly_informational_version: '{version}'
12 | dotnet_csproj:
13 | patch: true
14 | file: '**\*.csproj'
15 | version: '{version}'
16 | package_version: '{version}'
17 | assembly_version: '{version}'
18 | file_version: '{version}'
19 | informational_version: '{version}'
20 | before_build:
21 | - cmd: pushd . && nuget restore && popd
22 | build:
23 | publish_nuget: true
24 | verbosity: minimal
--------------------------------------------------------------------------------
/build.cake:
--------------------------------------------------------------------------------
1 | ///////////////////////////////////////////////////////////////////////////////
2 | // TOOLS / ADDINS
3 | ///////////////////////////////////////////////////////////////////////////////
4 |
5 | #tool vswhere
6 |
7 | //////////////////////////////////////////////////////////////////////
8 | // ARGUMENTS
9 | //////////////////////////////////////////////////////////////////////
10 |
11 | var msBuildPath = GetFiles(VSWhereLatest() + "/**/MSBuild.exe").FirstOrDefault();
12 |
13 | var target = Argument("target", "Default");
14 | var configuration = Argument("configuration", "Release");
15 | var verbosity = Argument("verbosity", Verbosity.Minimal);
16 | var version = Argument("version", "2.0.3");
17 |
18 | //////////////////////////////////////////////////////////////////////
19 | // PREPARATION
20 | //////////////////////////////////////////////////////////////////////
21 |
22 | var solution = "./HN.Controls.ImageEx.sln";
23 |
24 | //////////////////////////////////////////////////////////////////////
25 | // TASKS
26 | //////////////////////////////////////////////////////////////////////
27 |
28 | Task("Clean")
29 | .ContinueOnError()
30 | .Does(() =>
31 | {
32 | CleanDirectories("./src/*/bin");
33 | });
34 |
35 | Task("Restore-NuGet-Packages")
36 | .IsDependentOn("Clean")
37 | .Does(() =>
38 | {
39 | NuGetRestore(solution, new NuGetRestoreSettings { NoCache = true });
40 | });
41 |
42 | Task("Version")
43 | .IsDependentOn("Restore-NuGet-Packages")
44 | .Does(() =>
45 | {
46 | var file = "./src/SolutionInfo.cs";
47 | CreateAssemblyInfo(file, new AssemblyInfoSettings
48 | {
49 | Version = version,
50 | FileVersion = version,
51 | InformationalVersion = version,
52 | Copyright = string.Format("Copyright © h82258652 2018 - {0}", DateTime.Now.Year)
53 | });
54 | });
55 |
56 | Task("Build")
57 | .IsDependentOn("Version")
58 | .Does(() =>
59 | {
60 | if(IsRunningOnWindows())
61 | {
62 | // Use MSBuild
63 | var settings = new MSBuildSettings
64 | {
65 | ToolPath = msBuildPath
66 | }
67 | .SetConfiguration(configuration)
68 | .SetVerbosity(verbosity);
69 | MSBuild(solution, settings);
70 | }
71 | else
72 | {
73 | // Use XBuild
74 | XBuild(solution, configurator =>
75 | configurator.SetConfiguration(configuration)
76 | .SetVerbosity(verbosity));
77 | }
78 | });
79 |
80 | Task("Test")
81 | .IsDependentOn("Build")
82 | .Does(() =>
83 | {
84 | var settings = new DotNetCoreTestSettings
85 | {
86 | Configuration = "Release"
87 | };
88 |
89 | var testProjects = GetFiles("./test/**/*.csproj");
90 | foreach(var testProject in testProjects)
91 | {
92 | DotNetCoreTest(testProject.FullPath, settings);
93 | }
94 | });
95 |
96 | Task("Package")
97 | .IsDependentOn("Test")
98 | .Does(() =>
99 | {
100 | var nugetPackSettings = new NuGetPackSettings
101 | {
102 | Version = version,
103 | OutputDirectory = "./artifacts",
104 | Repository = new NuGetRepository
105 | {
106 | Type = "git",
107 | Url = "https://github.com/h82258652/HN.Controls.ImageEx"
108 | }
109 | };
110 |
111 | var nuspecFiles = GetFiles("./src/*/*.nuspec");
112 | NuGetPack(nuspecFiles, nugetPackSettings);
113 | });
114 |
115 | Task("Publish")
116 | .IsDependentOn("Package")
117 | .Does(() =>
118 | {
119 | if(BuildSystem.IsRunningOnGitHubActions)
120 | {
121 | var packages = GetFiles("./artifacts/*.nupkg");
122 | var nugetApiKey = EnvironmentVariable("NUGET_APIKEY");
123 | NuGetPush(packages, new NuGetPushSettings
124 | {
125 | Source = "https://www.nuget.org",
126 | ApiKey = nugetApiKey,
127 | SkipDuplicate = true
128 | });
129 | }
130 | });
131 |
132 | //////////////////////////////////////////////////////////////////////
133 | // TASK TARGETS
134 | //////////////////////////////////////////////////////////////////////
135 |
136 | Task("Default")
137 | .IsDependentOn("Publish");
138 |
139 | //////////////////////////////////////////////////////////////////////
140 | // EXECUTION
141 | //////////////////////////////////////////////////////////////////////
142 |
143 | RunTarget(target);
--------------------------------------------------------------------------------
/demo/UwpDemo/App.xaml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/UwpDemo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Windows.ApplicationModel;
3 | using Windows.ApplicationModel.Activation;
4 | using Windows.UI.Xaml;
5 | using Windows.UI.Xaml.Navigation;
6 | using UwpDemo.Views;
7 |
8 | namespace UwpDemo
9 | {
10 | ///
11 | /// 提供特定于应用程序的行为,以补充默认的应用程序类。
12 | ///
13 | sealed partial class App : Application
14 | {
15 | ///
16 | /// 初始化单一实例应用程序对象。这是执行的创作代码的第一行,
17 | /// 已执行,逻辑上等同于 main() 或 WinMain()。
18 | ///
19 | public App()
20 | {
21 | this.InitializeComponent();
22 | this.Suspending += OnSuspending;
23 | }
24 |
25 | ///
26 | /// 在应用程序由最终用户正常启动时进行调用。
27 | /// 将在启动应用程序以打开特定文件等情况下使用。
28 | ///
29 | /// 有关启动请求和过程的详细信息。
30 | protected override void OnLaunched(LaunchActivatedEventArgs e)
31 | {
32 | var rootView = Window.Current.Content as RootView;
33 |
34 | // 不要在窗口已包含内容时重复应用程序初始化,
35 | // 只需确保窗口处于活动状态
36 | if (rootView == null)
37 | {
38 | // 创建要充当导航上下文的框架,并导航到第一页
39 | rootView = new RootView();
40 |
41 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
42 | {
43 | //TODO: 从之前挂起的应用程序加载状态
44 | }
45 |
46 | // 将框架放在当前窗口中
47 | Window.Current.Content = rootView;
48 | }
49 |
50 | if (e.PrelaunchActivated == false)
51 | {
52 | // 确保当前窗口处于活动状态
53 | Window.Current.Activate();
54 | }
55 | }
56 |
57 | ///
58 | /// 导航到特定页失败时调用
59 | ///
60 | ///导航失败的框架
61 | ///有关导航失败的详细信息
62 | private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
63 | {
64 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
65 | }
66 |
67 | ///
68 | /// 在将要挂起应用程序执行时调用。 在不知道应用程序
69 | /// 无需知道应用程序会被终止还是会恢复,
70 | /// 并让内存内容保持不变。
71 | ///
72 | /// 挂起的请求的源。
73 | /// 有关挂起请求的详细信息。
74 | private void OnSuspending(object sender, SuspendingEventArgs e)
75 | {
76 | var deferral = e.SuspendingOperation.GetDeferral();
77 | //TODO: 保存应用程序状态并停止任何后台活动
78 | deferral.Complete();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/bliss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/bliss.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/newtons_cradle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/newtons_cradle.gif
--------------------------------------------------------------------------------
/demo/UwpDemo/Assets/unicorn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/UwpDemo/Assets/unicorn.png
--------------------------------------------------------------------------------
/demo/UwpDemo/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
15 |
16 |
17 | UwpDemo
18 | h8225
19 | Assets\StoreLogo.png
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // General Information about an assembly is controlled through the following
5 | // set of attributes. Change these attribute values to modify the information
6 | // associated with an assembly.
7 | [assembly: AssemblyTitle("UwpDemo")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("UwpDemo")]
12 | [assembly: AssemblyCopyright("Copyright © 2018")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // Version information for an assembly consists of the following four values:
17 | //
18 | // Major Version
19 | // Minor Version
20 | // Build Number
21 | // Revision
22 | //
23 | // You can specify all the values or you can default the Build and Revision Numbers
24 | // by using the '*' as shown below:
25 | // [assembly: AssemblyVersion("1.0.*")]
26 | [assembly: AssemblyVersion("1.0.0.0")]
27 | [assembly: AssemblyFileVersion("1.0.0.0")]
28 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/demo/UwpDemo/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/AnimationView.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/AnimationView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Windows.UI.Xaml;
4 | using Windows.UI.Xaml.Controls;
5 | using Windows.UI.Xaml.Controls.Primitives;
6 |
7 | namespace UwpDemo.Views
8 | {
9 | public sealed partial class AnimationView
10 | {
11 | public AnimationView()
12 | {
13 | InitializeComponent();
14 | }
15 |
16 | private void FrameComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
17 | {
18 | if (FrameComboBox.SelectedItem != null)
19 | {
20 | var index = int.Parse(FrameComboBox.SelectedItem.ToString());
21 | ImageEx.GotoFrame(index);
22 | }
23 | }
24 |
25 | private void ImageEx_ImageOpened(object sender, EventArgs e)
26 | {
27 | FrameComboBox.ItemsSource = Enumerable.Range(0, ImageEx.FrameCount).ToList();
28 | FrameComboBox.SelectedIndex = 0;
29 | }
30 |
31 | private void PauseButton_Click(object sender, RoutedEventArgs e)
32 | {
33 | ImageEx.Pause();
34 | }
35 |
36 | private void PlayButton_Click(object sender, RoutedEventArgs e)
37 | {
38 | ImageEx.Play();
39 | }
40 |
41 | private void SpeedRatioSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
42 | {
43 | ImageEx.SpeedRatio = SpeedRatioSlider.Value;
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/CornerRadiusView.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
17 |
19 |
20 |
26 |
27 |
33 |
34 |
40 |
41 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/CornerRadiusView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Windows.UI.Xaml;
2 | using Windows.UI.Xaml.Controls.Primitives;
3 |
4 | namespace UwpDemo.Views
5 | {
6 | public sealed partial class CornerRadiusView
7 | {
8 | public CornerRadiusView()
9 | {
10 | InitializeComponent();
11 |
12 | UpdateCornerRadius();
13 | }
14 |
15 | private void BottomLeftSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
16 | {
17 | UpdateCornerRadius();
18 | }
19 |
20 | private void BottomRightSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
21 | {
22 | UpdateCornerRadius();
23 | }
24 |
25 | private void TopLeftSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
26 | {
27 | UpdateCornerRadius();
28 | }
29 |
30 | private void TopRightSlider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
31 | {
32 | UpdateCornerRadius();
33 | }
34 |
35 | private void UpdateCornerRadius()
36 | {
37 | if (TopLeftSlider != null && TopRightSlider != null && BottomRightSlider != null && BottomLeftSlider != null)
38 | {
39 | ImageEx.CornerRadius = new CornerRadius(TopLeftSlider.Value, TopRightSlider.Value, BottomRightSlider.Value, BottomLeftSlider.Value);
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/LazyLoadingView.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
18 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/LazyLoadingView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Windows.UI.Popups;
3 |
4 | namespace UwpDemo.Views
5 | {
6 | public sealed partial class LazyLoadingView
7 | {
8 | public LazyLoadingView()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | private async void ImageEx_ImageOpened(object sender, EventArgs e)
14 | {
15 | await new MessageDialog("Image Opened").ShowAsync();
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/MainView.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/MainView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Windows.UI.Xaml;
2 |
3 | namespace UwpDemo.Views
4 | {
5 | public sealed partial class MainView
6 | {
7 | public MainView()
8 | {
9 | InitializeComponent();
10 | }
11 |
12 | private void AnimationButton_Click(object sender, RoutedEventArgs e)
13 | {
14 | Frame.Navigate(typeof(AnimationView));
15 | }
16 |
17 | private void CornerRadiusButton_Click(object sender, RoutedEventArgs e)
18 | {
19 | Frame.Navigate(typeof(CornerRadiusView));
20 | }
21 |
22 | private void LazyLoadingButton_Click(object sender, RoutedEventArgs e)
23 | {
24 | Frame.Navigate(typeof(LazyLoadingView));
25 | }
26 |
27 | private void MemoryUsageButton_Click(object sender, RoutedEventArgs e)
28 | {
29 | Frame.Navigate(typeof(MemoryUsageView));
30 | }
31 |
32 | private void ProgressButton_Click(object sender, RoutedEventArgs e)
33 | {
34 | Frame.Navigate(typeof(ProgressView));
35 | }
36 |
37 | private void ShadowButton_Click(object sender, RoutedEventArgs e)
38 | {
39 | Frame.Navigate(typeof(ShadowView));
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/MemoryUsageView.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
19 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/MemoryUsageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using Windows.UI.Xaml;
5 |
6 | namespace UwpDemo.Views
7 | {
8 | public sealed partial class MemoryUsageView
9 | {
10 | private readonly Stopwatch _stopwatch;
11 |
12 | public MemoryUsageView()
13 | {
14 | InitializeComponent();
15 |
16 | _stopwatch = new Stopwatch();
17 | _stopwatch.Start();
18 |
19 | GridView.ItemsSource = Enumerable.Range(0, 100).Select(temp => "https://www.baidu.com/img/bd_logo1.png?t=" + Guid.NewGuid()).ToList();
20 | }
21 |
22 | private void MemoryUsageView_Loaded(object sender, RoutedEventArgs e)
23 | {
24 | _stopwatch.Stop();
25 | LoadTimeTextBlock.Text = $"Load time: {_stopwatch.ElapsedMilliseconds}ms";
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/ProgressView.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
30 |
31 |
34 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
54 |
55 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/ProgressView.xaml.cs:
--------------------------------------------------------------------------------
1 | using Windows.UI.Xaml;
2 |
3 | namespace UwpDemo.Views
4 | {
5 | public sealed partial class ProgressView
6 | {
7 | public ProgressView()
8 | {
9 | InitializeComponent();
10 | }
11 |
12 | private void LoadButton_Click(object sender, RoutedEventArgs e)
13 | {
14 | ImageEx.Source = "https://edmullen.net/test/rc.jpg";
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/RootView.xaml:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
18 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/RootView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Windows.System;
3 | using Windows.UI.Xaml;
4 |
5 | namespace UwpDemo.Views
6 | {
7 | public sealed partial class RootView
8 | {
9 | private readonly DispatcherTimer _timer;
10 |
11 | public RootView()
12 | {
13 | InitializeComponent();
14 | RootFrame.Navigate(typeof(MainView));
15 |
16 | _timer = new DispatcherTimer
17 | {
18 | Interval = TimeSpan.FromSeconds(0.2)
19 | };
20 | _timer.Tick += Timer_Tick;
21 | }
22 |
23 | private void GoBackButton_Click(object sender, RoutedEventArgs e)
24 | {
25 | if (RootFrame.CanGoBack)
26 | {
27 | RootFrame.GoBack();
28 | }
29 | }
30 |
31 | private void RootView_Loaded(object sender, RoutedEventArgs e)
32 | {
33 | _timer.Start();
34 | }
35 |
36 | private void RootView_Unloaded(object sender, RoutedEventArgs e)
37 | {
38 | _timer.Stop();
39 | }
40 |
41 | private void Timer_Tick(object sender, object e)
42 | {
43 | var appMemoryUsage = MemoryManager.AppMemoryUsage;
44 | var memoryUsage = Microsoft.Toolkit.Converters.ToFileSizeString((long)appMemoryUsage);
45 | MemoryUsageTextBlock.Text = memoryUsage;
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/ShadowView.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
28 |
29 |
32 |
33 |
36 |
37 |
40 |
41 |
44 |
45 |
48 |
49 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/demo/UwpDemo/Views/ShadowView.xaml.cs:
--------------------------------------------------------------------------------
1 | using HN.Controls;
2 | using Windows.UI.Xaml;
3 |
4 | namespace UwpDemo.Views
5 | {
6 | public sealed partial class ShadowView
7 | {
8 | public ShadowView()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | private void IsShadowEnabledCheckBox_Checked(object sender, RoutedEventArgs e)
14 | {
15 | ImageEx.DropShadow = (ImageExShadow)Resources["ImageExShadow"];
16 | }
17 |
18 | private void IsShadowEnabledCheckBox_Unchecked(object sender, RoutedEventArgs e)
19 | {
20 | ImageEx.DropShadow = null;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/demo/WpfDemo/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/WpfDemo/App.xaml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/WpfDemo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WpfDemo
2 | {
3 | public partial class App
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Images/bliss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/WpfDemo/Images/bliss.png
--------------------------------------------------------------------------------
/demo/WpfDemo/Images/newtons_cradle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/WpfDemo/Images/newtons_cradle.gif
--------------------------------------------------------------------------------
/demo/WpfDemo/Images/unicorn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/h82258652/HN.Controls.ImageEx/7358bb8d0039648694e7f4589a75c96895e63d15/demo/WpfDemo/Images/unicorn.png
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/AnimationView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/AnimationView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 |
6 | namespace WpfDemo.Views
7 | {
8 | public partial class AnimationView
9 | {
10 | public AnimationView()
11 | {
12 | InitializeComponent();
13 | }
14 |
15 | private void FrameComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
16 | {
17 | if (FrameComboBox.SelectedItem != null)
18 | {
19 | var index = int.Parse(FrameComboBox.SelectedItem.ToString());
20 | ImageEx.GotoFrame(index);
21 | }
22 | }
23 |
24 | private void ImageEx_ImageOpened(object sender, EventArgs e)
25 | {
26 | FrameComboBox.ItemsSource = Enumerable.Range(0, ImageEx.FrameCount).ToList();
27 | FrameComboBox.SelectedIndex = 0;
28 | }
29 |
30 | private void PauseButton_Click(object sender, RoutedEventArgs e)
31 | {
32 | ImageEx.Pause();
33 | }
34 |
35 | private void PlayButton_Click(object sender, RoutedEventArgs e)
36 | {
37 | ImageEx.Play();
38 | }
39 |
40 | private void SpeedRatioSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
41 | {
42 | ImageEx.SpeedRatio = SpeedRatioSlider.Value;
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/CornerRadiusView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
21 |
22 |
27 |
28 |
33 |
34 |
39 |
40 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/CornerRadiusView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace WpfDemo.Views
4 | {
5 | public partial class CornerRadiusView
6 | {
7 | public CornerRadiusView()
8 | {
9 | InitializeComponent();
10 |
11 | UpdateCornerRadius();
12 | }
13 |
14 | private void BottomLeftSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
15 | {
16 | UpdateCornerRadius();
17 | }
18 |
19 | private void BottomRightSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
20 | {
21 | UpdateCornerRadius();
22 | }
23 |
24 | private void TopLeftSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
25 | {
26 | UpdateCornerRadius();
27 | }
28 |
29 | private void TopRightSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e)
30 | {
31 | UpdateCornerRadius();
32 | }
33 |
34 | private void UpdateCornerRadius()
35 | {
36 | if (TopLeftSlider != null && TopRightSlider != null && BottomRightSlider != null && BottomLeftSlider != null)
37 | {
38 | ImageEx.CornerRadius = new CornerRadius(TopLeftSlider.Value, TopRightSlider.Value, BottomRightSlider.Value, BottomLeftSlider.Value);
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/LazyLoadingView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
14 |
15 |
21 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/LazyLoadingView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 |
4 | namespace WpfDemo.Views
5 | {
6 | public partial class LazyLoadingView
7 | {
8 | public LazyLoadingView()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | private void ImageEx_ImageOpened(object sender, EventArgs e)
14 | {
15 | MessageBox.Show("Image Opened");
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/MainView.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/MainView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace WpfDemo.Views
4 | {
5 | public partial class MainView
6 | {
7 | public MainView()
8 | {
9 | InitializeComponent();
10 | }
11 |
12 | private void AnimationButton_Click(object sender, RoutedEventArgs e)
13 | {
14 | new AnimationView().ShowDialog();
15 | }
16 |
17 | private void CornerRadiusButton_Click(object sender, RoutedEventArgs e)
18 | {
19 | new CornerRadiusView().ShowDialog();
20 | }
21 |
22 | private void LazyLoadingButton_Click(object sender, RoutedEventArgs e)
23 | {
24 | new LazyLoadingView().ShowDialog();
25 | }
26 |
27 | private void MemoryUsageButton_Click(object sender, RoutedEventArgs e)
28 | {
29 | new MemoryUsageView().ShowDialog();
30 | }
31 |
32 | private void ProgressButton_Click(object sender, RoutedEventArgs e)
33 | {
34 | new ProgressView().ShowDialog();
35 | }
36 |
37 | private void ShadowButton_Click(object sender, RoutedEventArgs e)
38 | {
39 | new ShadowView().ShowDialog();
40 | }
41 |
42 | private void StretchButton_Click(object sender, RoutedEventArgs e)
43 | {
44 | new StretchView().ShowDialog();
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/MemoryUsageView.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
27 |
31 |
32 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/MemoryUsageView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Windows;
5 | using System.Windows.Threading;
6 |
7 | namespace WpfDemo.Views
8 | {
9 | public partial class MemoryUsageView
10 | {
11 | private readonly Stopwatch _stopwatch;
12 | private readonly DispatcherTimer _timer;
13 |
14 | public MemoryUsageView()
15 | {
16 | InitializeComponent();
17 |
18 | _stopwatch = new Stopwatch();
19 | _stopwatch.Start();
20 |
21 | ListView.ItemsSource = Enumerable.Range(0, 100).Select(temp => "https://www.baidu.com/img/bd_logo1.png?t=" + Guid.NewGuid()).ToList();
22 |
23 | _timer = new DispatcherTimer
24 | {
25 | Interval = TimeSpan.FromSeconds(0.2)
26 | };
27 | _timer.Tick += Timer_Tick;
28 | }
29 |
30 | private void MemoryUsageView_Loaded(object sender, RoutedEventArgs e)
31 | {
32 | _stopwatch.Stop();
33 | LoadTimeTextBlock.Text = $"Load time: {_stopwatch.ElapsedMilliseconds}ms";
34 |
35 | _timer.Start();
36 | }
37 |
38 | private void MemoryUsageView_Unloaded(object sender, RoutedEventArgs e)
39 | {
40 | _timer.Stop();
41 | }
42 |
43 | private void Timer_Tick(object sender, EventArgs e)
44 | {
45 | var privateMemorySize64 = Process.GetCurrentProcess().PrivateMemorySize64;
46 | var memoryUsage = Microsoft.Toolkit.Converters.ToFileSizeString(privateMemorySize64);
47 | MemoryUsageTextBlock.Text = memoryUsage;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/ProgressView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
33 |
36 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
49 |
50 |
51 |
52 |
56 |
57 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/ProgressView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace WpfDemo.Views
4 | {
5 | public partial class ProgressView
6 | {
7 | public ProgressView()
8 | {
9 | InitializeComponent();
10 | }
11 |
12 | private void LoadButton_Click(object sender, RoutedEventArgs e)
13 | {
14 | ImageEx.Source = "https://edmullen.net/test/rc.jpg";
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/ShadowView.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
26 |
30 |
31 |
34 |
35 |
38 |
39 |
42 |
43 |
46 |
47 |
50 |
51 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/ShadowView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using HN.Controls;
3 |
4 | namespace WpfDemo.Views
5 | {
6 | public partial class ShadowView
7 | {
8 | public ShadowView()
9 | {
10 | InitializeComponent();
11 | }
12 |
13 | private void IsShadowEnabledCheckBox_Checked(object sender, RoutedEventArgs e)
14 | {
15 | ImageEx.DropShadow = (ImageExShadow)Resources["ImageExShadow"];
16 | }
17 |
18 | private void IsShadowEnabledCheckBox_Unchecked(object sender, RoutedEventArgs e)
19 | {
20 | ImageEx.DropShadow = null;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/demo/WpfDemo/Views/StretchView.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WpfDemo.Views
2 | {
3 | public partial class StretchView
4 | {
5 | public StretchView()
6 | {
7 | InitializeComponent();
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/demo/WpfDemo/WpfDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Cache/IDiskCache.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using JetBrains.Annotations;
5 |
6 | namespace HN.Cache
7 | {
8 | ///
9 | /// 磁盘缓存。
10 | ///
11 | public interface IDiskCache
12 | {
13 | ///
14 | /// 获取缓存文件夹路径。
15 | ///
16 | [NotNull]
17 | string CacheFolderPath { get; }
18 |
19 | ///
20 | /// 计算所有缓存的大小。单位:字节。
21 | ///
22 | /// 所有缓存的大小。单位:字节。
23 | ValueTask CalculateAllSizeAsync();
24 |
25 | ///
26 | /// 计算某个缓存的大小。单位:字节。
27 | ///
28 | /// 缓存的键。
29 | /// 某个缓存的大小。单位:字节。
30 | ValueTask CalculateSizeAsync([NotNull] string key);
31 |
32 | ///
33 | /// 删除所有缓存。
34 | ///
35 | /// 表示异步删除操作的任务。
36 | Task DeleteAllAsync();
37 |
38 | ///
39 | /// 删除某个缓存。
40 | ///
41 | /// 缓存的键。
42 | /// 表示异步删除操作的任务。
43 | Task DeleteAsync([NotNull] string key);
44 |
45 | ///
46 | /// 获取缓存。
47 | ///
48 | /// 缓存的键。
49 | /// 要监视取消请求的标记。
50 | /// 缓存的值。
51 | Task GetAsync([NotNull] string key, CancellationToken cancellationToken = default);
52 |
53 | ///
54 | /// 获取缓存。
55 | ///
56 | /// 缓存的键。
57 | /// 要监视取消请求的标记。
58 | /// 缓存的值。
59 | Task GetStreamAsync([NotNull] string key, CancellationToken cancellationToken = default);
60 |
61 | ///
62 | /// 获取某个缓存是否存在。
63 | ///
64 | /// 缓存的键。
65 | /// 某个缓存是否存在。
66 | Task IsExistAsync([NotNull] string key);
67 |
68 | ///
69 | /// 设置缓存。
70 | ///
71 | /// 缓存的键。
72 | /// 缓存的值。
73 | /// 要监视取消请求的标记。
74 | /// 表示异步设置操作的任务。
75 | Task SetAsync([NotNull] string key, [NotNull] byte[] data, CancellationToken cancellationToken = default);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Constants.cs:
--------------------------------------------------------------------------------
1 | namespace HN
2 | {
3 | internal static class Constants
4 | {
5 | internal const string HttpClientName = "ImageEx";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Controls/ImageExFailedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using JetBrains.Annotations;
3 |
4 | namespace HN.Controls
5 | {
6 | ///
7 | ///
8 | /// 图像源加载失败事件数据。
9 | ///
10 | public class ImageExFailedEventArgs : EventArgs
11 | {
12 | ///
13 | ///
14 | /// 初始化 类的新实例。
15 | ///
16 | /// 引起该加载失败的源。
17 | /// 说明加载失败原因的异常。
18 | public ImageExFailedEventArgs(object source, Exception failedException)
19 | {
20 | Source = source ?? throw new ArgumentNullException(nameof(source));
21 | Exception = failedException ?? throw new ArgumentNullException(nameof(failedException));
22 | }
23 |
24 | ///
25 | /// 获取说明加载失败原因的异常。
26 | ///
27 | ///
28 | /// 说明加载失败原因的异常。
29 | ///
30 | [NotNull]
31 | public Exception Exception { get; }
32 |
33 | ///
34 | /// 获取引起该加载失败的源。
35 | ///
36 | ///
37 | /// 引起加载失败的源。
38 | ///
39 | [NotNull]
40 | public object Source { get; }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Controls/ImageExFailedEventHandler.cs:
--------------------------------------------------------------------------------
1 | namespace HN.Controls
2 | {
3 | ///
4 | /// 表示将处理无法加载图像源的事件的方法。
5 | ///
6 | /// 事件源。
7 | /// 事件数据。
8 | public delegate void ImageExFailedEventHandler(in object sender, in ImageExFailedEventArgs e);
9 | }
10 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Extensions/UriExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using JetBrains.Annotations;
3 |
4 | namespace HN.Extensions
5 | {
6 | ///
7 | /// 扩展类。
8 | ///
9 | public static class UriExtensions
10 | {
11 | ///
12 | /// 获取 实例是否是 Http 协议。
13 | ///
14 | /// 实例。
15 | /// 实例是否是 Http 协议。
16 | /// uri 为 。
17 | public static bool IsHttp([NotNull] this Uri uri)
18 | {
19 | if (uri == null)
20 | {
21 | throw new ArgumentNullException(nameof(uri));
22 | }
23 |
24 | var scheme = uri.Scheme;
25 | return uri.IsAbsoluteUri &&
26 | (string.Equals(scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase) ||
27 | string.Equals(scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase));
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/HN.Controls.ImageEx.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | HN
6 | HN.Controls.ImageEx.Core
7 | 1.0.0
8 | HN.Controls.ImageEx.Core
9 | h82258652
10 | https://licenses.nuget.org/MIT
11 | https://github.com/h82258652/HN.Controls.ImageEx
12 | HN.Controls.ImageEx.Core
13 |
14 | false
15 | true
16 | latest
17 | enable
18 | true
19 | true
20 | $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
21 | true
22 | true
23 | snupkg
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/HN.Controls.ImageEx.Core.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | HN.Controls.ImageEx.Core
5 | $version$
6 | HN.Controls.ImageEx.Core
7 | h82258652
8 | h82258652
9 | MIT
10 | https://github.com/h82258652/HN.Controls.ImageEx
11 | false
12 | HN.Controls.ImageEx.Core
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Http/HttpDownloadProgress.cs:
--------------------------------------------------------------------------------
1 | namespace HN.Http
2 | {
3 | ///
4 | /// Http 下载进度。
5 | ///
6 | public struct HttpDownloadProgress
7 | {
8 | ///
9 | /// 获取或设置已接收的字节数。
10 | ///
11 | public ulong BytesReceived { get; set; }
12 |
13 | ///
14 | /// 获取下载进度。
15 | ///
16 | public float? Percentage
17 | {
18 | get
19 | {
20 | if (TotalBytesToReceive.HasValue)
21 | {
22 | return BytesReceived * 1f / TotalBytesToReceive.Value;
23 | }
24 |
25 | return null;
26 | }
27 | }
28 |
29 | ///
30 | /// 获取或设置总共需要接收的字节数。
31 | ///
32 | public ulong? TotalBytesToReceive { get; set; }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Http/ThrottlingDelegatingHandler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net.Http;
3 | using System.Threading;
4 | using System.Threading.Tasks;
5 | using JetBrains.Annotations;
6 |
7 | namespace HN.Http
8 | {
9 | ///
10 | /// 限制同时并发 Http 请求处理器。
11 | ///
12 | public class ThrottlingDelegatingHandler : DelegatingHandler
13 | {
14 | private readonly SemaphoreSlim _throttler;
15 |
16 | ///
17 | /// 初始化 类的新实例。
18 | ///
19 | /// 类实例。
20 | public ThrottlingDelegatingHandler([NotNull] SemaphoreSlim throttler)
21 | {
22 | _throttler = throttler ?? throw new ArgumentNullException(nameof(throttler));
23 | }
24 |
25 | ///
26 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
27 | {
28 | if (request == null)
29 | {
30 | throw new ArgumentNullException(nameof(request));
31 | }
32 |
33 | await _throttler.WaitAsync(cancellationToken);
34 | try
35 | {
36 | return await base.SendAsync(request, cancellationToken);
37 | }
38 | finally
39 | {
40 | _throttler.Release();
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Media/ImageBrushExFailedEventArgs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using JetBrains.Annotations;
3 |
4 | namespace HN.Media
5 | {
6 | ///
7 | ///
8 | /// 图像源加载失败事件数据。
9 | ///
10 | public class ImageBrushExFailedEventArgs : EventArgs
11 | {
12 | ///
13 | ///
14 | /// 初始化 类的新实例。
15 | ///
16 | /// 引起该加载失败的源。
17 | /// 说明加载失败原因的异常。
18 | public ImageBrushExFailedEventArgs(object source, Exception failedException)
19 | {
20 | Source = source ?? throw new ArgumentNullException(nameof(source));
21 | Exception = failedException ?? throw new ArgumentNullException(nameof(failedException));
22 | }
23 |
24 | ///
25 | /// 获取说明该加载失败原因的异常。
26 | ///
27 | ///
28 | /// 说明该加载失败原因的异常。
29 | ///
30 | [NotNull]
31 | public Exception Exception { get; }
32 |
33 | ///
34 | /// 获取引起该加载失败的源。
35 | ///
36 | ///
37 | /// 引起加载失败的源。
38 | ///
39 | [NotNull]
40 | public object Source { get; }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Media/ImageBrushExFailedEventHandler.cs:
--------------------------------------------------------------------------------
1 | namespace HN.Media
2 | {
3 | ///
4 | /// 表示将处理无法加载图像源的事件的方法。
5 | ///
6 | /// 事件源。
7 | /// 事件数据。
8 | public delegate void ImageBrushExFailedEventHandler(in object sender, in ImageBrushExFailedEventArgs e);
9 | }
10 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/ByteArrayPipe.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using HN.Services;
5 |
6 | namespace HN.Pipes
7 | {
8 | ///
9 | ///
10 | /// 若当前的值是 数组类型,则该管道会进行处理。
11 | ///
12 | /// 加载源目标的类型。
13 | public class ByteArrayPipe : LoadingPipeBase where TSource : class
14 | {
15 | ///
16 | ///
17 | /// 初始化 类的新实例。
18 | ///
19 | /// 设计模式服务。
20 | public ByteArrayPipe(IDesignModeService designModeService) : base(designModeService)
21 | {
22 | }
23 |
24 | ///
25 | public override Task InvokeAsync(ILoadingContext context, LoadingPipeDelegate next, CancellationToken cancellationToken = default)
26 | {
27 | if (context.Current is byte[] bytes)
28 | {
29 | context.Current = new MemoryStream(bytes);
30 | }
31 |
32 | return next(context, cancellationToken);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/DiskCachePipe.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using HN.Cache;
5 | using HN.Extensions;
6 | using HN.Services;
7 | using JetBrains.Annotations;
8 | using Nito.AsyncEx;
9 |
10 | namespace HN.Pipes
11 | {
12 | ///
13 | ///
14 | /// 磁盘加载管道。
15 | ///
16 | /// 加载源目标的类型。
17 | public class DiskCachePipe : LoadingPipeBase where TSource : class
18 | {
19 | private readonly IDiskCache _diskCache;
20 |
21 | ///
22 | ///
23 | /// 初始化 类的新实例。
24 | ///
25 | /// 设计模式服务。
26 | /// 磁盘缓存。
27 | public DiskCachePipe(IDesignModeService designModeService, [NotNull] IDiskCache diskCache) : base(designModeService)
28 | {
29 | _diskCache = diskCache ?? throw new ArgumentNullException(nameof(diskCache));
30 | }
31 |
32 | ///
33 | public override async Task InvokeAsync(ILoadingContext context, LoadingPipeDelegate next, CancellationToken cancellationToken = default)
34 | {
35 | if (IsInDesignMode)
36 | {
37 | await next(context, cancellationToken);
38 | return;
39 | }
40 |
41 | var uri = context.Current as Uri;
42 | if (uri == null || !uri.IsHttp())
43 | {
44 | await next(context, cancellationToken);
45 | return;
46 | }
47 |
48 | var cacheKey = uri.AbsoluteUri;
49 | if (await _diskCache.IsExistAsync(cacheKey))
50 | {
51 | context.Current = await _diskCache.GetStreamAsync(cacheKey, cancellationToken);
52 | try
53 | {
54 | await next(context, cancellationToken);
55 | }
56 | catch
57 | {
58 | _diskCache.DeleteAsync(cacheKey).Ignore();
59 | throw;
60 | }
61 | }
62 | else
63 | {
64 | await next(context, cancellationToken);
65 |
66 | var bytes = context.HttpResponseBytes;
67 | if (bytes != null)
68 | {
69 | _diskCache.SetAsync(cacheKey, bytes, CancellationToken.None).Ignore();
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/ILoadingContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using HN.Http;
4 | using JetBrains.Annotations;
5 |
6 | namespace HN.Pipes
7 | {
8 | ///
9 | /// 加载上下文。
10 | ///
11 | /// 加载源目标的类型。
12 | public interface ILoadingContext where TSource : class
13 | {
14 | ///
15 | /// 下载进度发生变化事件。
16 | ///
17 | [CanBeNull]
18 | event EventHandler? DownloadProgressChanged;
19 |
20 | ///
21 | /// 设置或获取当前管道的值。
22 | ///
23 | ///
24 | /// 当前管道的值。
25 | ///
26 | [NotNull]
27 | object Current { get; set; }
28 |
29 | ///
30 | /// 获取需求的高度。
31 | ///
32 | ///
33 | /// 需求的高度。
34 | ///
35 | double? DesiredHeight { get; }
36 |
37 | ///
38 | /// 获取需求的宽度。
39 | ///
40 | ///
41 | /// 需求的宽度。
42 | ///
43 | double? DesiredWidth { get; }
44 |
45 | ///
46 | /// 若管道处理过程中涉及 HTTP 传输,则存放 HTTP 响应的内容在此。
47 | ///
48 | ///
49 | /// 若管道处理过程中涉及 HTTP 传输,则有值。
50 | ///
51 | [CanBeNull]
52 | byte[]? HttpResponseBytes { get; set; }
53 |
54 | ///
55 | /// 获取原始输入的数据源。
56 | ///
57 | ///
58 | /// 原始输入的数据源。
59 | ///
60 | [NotNull]
61 | object OriginSource { get; }
62 |
63 | ///
64 | /// 附加目标源到可视树上。
65 | ///
66 | /// 目标源对象。
67 | void AttachSource([NotNull] TSource source);
68 |
69 | ///
70 | /// 在 UI 线程上执行同步操作。
71 | ///
72 | /// 同步操作。
73 | void InvokeOnUIThread(Action callback);
74 |
75 | ///
76 | /// 在 UI 线程上执行异步操作。
77 | ///
78 | /// 异步操作。
79 | /// 异步操作任务。
80 | Task InvokeOnUIThreadAsync(Func callback);
81 |
82 | ///
83 | /// 发起下载进度发生变化事件。
84 | ///
85 | /// 当前下载进度。
86 | void RaiseDownloadProgressChanged(HttpDownloadProgress progress);
87 |
88 | ///
89 | /// 重置该上下文为初始状态。
90 | ///
91 | void Reset();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/ILoadingPipe.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using JetBrains.Annotations;
5 |
6 | namespace HN.Pipes
7 | {
8 | ///
9 | ///
10 | /// 加载管道。
11 | ///
12 | /// 加载源目标的类型。
13 | public interface ILoadingPipe : IDisposable where TSource : class
14 | {
15 | ///
16 | /// 获取当前是否在设计模式下。
17 | ///
18 | bool IsInDesignMode { get; }
19 |
20 | ///
21 | /// 执行管道加载逻辑。
22 | ///
23 | /// 加载上下文。
24 | /// 下一个加载管道的调用委托。
25 | /// 要监视取消请求的标记。
26 | /// 表示异步加载操作的任务。
27 | Task InvokeAsync([NotNull] ILoadingContext context, [NotNull] LoadingPipeDelegate next, CancellationToken cancellationToken = default);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/LoadingPipeBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using HN.Services;
5 | using JetBrains.Annotations;
6 |
7 | namespace HN.Pipes
8 | {
9 | ///
10 | ///
11 | /// 加载管道的基本实现。
12 | ///
13 | /// 加载源目标的类型。
14 | public abstract class LoadingPipeBase : ILoadingPipe where TSource : class
15 | {
16 | private readonly IDesignModeService _designModeService;
17 |
18 | ///
19 | /// 初始化 类的新实例。
20 | ///
21 | /// 设计模式服务。
22 | protected LoadingPipeBase([NotNull] IDesignModeService designModeService)
23 | {
24 | _designModeService = designModeService ?? throw new ArgumentNullException(nameof(designModeService));
25 | }
26 |
27 | ///
28 | public bool IsInDesignMode => _designModeService.IsInDesignMode;
29 |
30 | ///
31 | public virtual void Dispose()
32 | {
33 | }
34 |
35 | ///
36 | public abstract Task InvokeAsync(ILoadingContext context, LoadingPipeDelegate next, CancellationToken cancellationToken = default);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/LoadingPipeBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 | using JetBrains.Annotations;
5 | using Microsoft.Extensions.DependencyInjection;
6 |
7 | namespace HN.Pipes
8 | {
9 | ///
10 | /// 该类用于构建加载管道。
11 | ///
12 | public static class LoadingPipeBuilder
13 | {
14 | ///
15 | /// 构建加载管道。
16 | ///
17 | /// 加载源目标的类型。
18 | /// 服务集合。
19 | /// 管道调用的委托。
20 | [NotNull]
21 | public static LoadingPipeDelegate Build([NotNull] IServiceCollection services) where TSource : class
22 | {
23 | if (services == null)
24 | {
25 | throw new ArgumentNullException(nameof(services));
26 | }
27 |
28 | LoadingPipeDelegate end = (context, cancellationToken) =>
29 | {
30 | if (!(context.Current is TSource))
31 | {
32 | throw new NotSupportedException();
33 | }
34 |
35 | return Task.CompletedTask;
36 | };
37 |
38 | var serviceProvider = services.BuildServiceProvider();
39 | var pipes = serviceProvider.GetServices>();
40 | foreach (var pipe in pipes.Reverse())
41 | {
42 | Func, LoadingPipeDelegate> handler = next =>
43 | {
44 | return (context, cancellationToken) =>
45 | {
46 | using (pipe)
47 | {
48 | return pipe.InvokeAsync(context, next, cancellationToken);
49 | }
50 | };
51 | };
52 | end = handler(end);
53 | }
54 |
55 | return end;
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/LoadingPipeDelegate.cs:
--------------------------------------------------------------------------------
1 | using System.Threading;
2 | using System.Threading.Tasks;
3 | using JetBrains.Annotations;
4 |
5 | namespace HN.Pipes
6 | {
7 | ///
8 | /// 加载管道调用委托。
9 | ///
10 | /// 加载源目标的类型。
11 | /// 加载上下文。
12 | /// 要监视取消请求的标记。
13 | /// 表示异步加载操作的任务。
14 | public delegate Task LoadingPipeDelegate([NotNull] ILoadingContext context, CancellationToken cancellationToken = default) where TSource : class;
15 | }
16 |
--------------------------------------------------------------------------------
/src/HN.Controls.ImageEx.Core/Pipes/MemoryCachePipe.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using HN.Services;
5 | using Weakly;
6 |
7 | namespace HN.Pipes
8 | {
9 | ///
10 | ///
11 | /// 内存缓存加载管道。
12 | ///
13 | /// 加载源目标的类型。
14 | public class MemoryCachePipe : LoadingPipeBase where TSource : class
15 | {
16 | private static readonly WeakValueDictionary