├── logo.png
├── global.json
├── MicaDemo
├── Assets
│ ├── StoreLogo.backup.png
│ ├── LargeTile.scale-100.png
│ ├── LargeTile.scale-125.png
│ ├── LargeTile.scale-150.png
│ ├── LargeTile.scale-200.png
│ ├── LargeTile.scale-400.png
│ ├── SmallTile.scale-100.png
│ ├── SmallTile.scale-125.png
│ ├── SmallTile.scale-150.png
│ ├── SmallTile.scale-200.png
│ ├── SmallTile.scale-400.png
│ ├── StoreLogo.scale-100.png
│ ├── StoreLogo.scale-125.png
│ ├── StoreLogo.scale-150.png
│ ├── StoreLogo.scale-200.png
│ ├── StoreLogo.scale-400.png
│ ├── SplashScreen.scale-100.png
│ ├── SplashScreen.scale-125.png
│ ├── SplashScreen.scale-150.png
│ ├── SplashScreen.scale-200.png
│ ├── SplashScreen.scale-400.png
│ ├── Photos
│ │ └── BigFourSummerHeat.jpg
│ ├── Square150x150Logo.scale-100.png
│ ├── Square150x150Logo.scale-125.png
│ ├── Square150x150Logo.scale-150.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square150x150Logo.scale-400.png
│ ├── Square44x44Logo.scale-100.png
│ ├── Square44x44Logo.scale-125.png
│ ├── Square44x44Logo.scale-150.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.scale-400.png
│ ├── Wide310x150Logo.scale-100.png
│ ├── Wide310x150Logo.scale-125.png
│ ├── Wide310x150Logo.scale-150.png
│ ├── Wide310x150Logo.scale-200.png
│ ├── Wide310x150Logo.scale-400.png
│ ├── Square44x44Logo.targetsize-16.png
│ ├── Square44x44Logo.targetsize-24.png
│ ├── Square44x44Logo.targetsize-32.png
│ ├── Square44x44Logo.targetsize-48.png
│ ├── Square44x44Logo.targetsize-256.png
│ ├── Square44x44Logo.altform-unplated_targetsize-16.png
│ ├── Square44x44Logo.altform-unplated_targetsize-256.png
│ ├── Square44x44Logo.altform-unplated_targetsize-32.png
│ ├── Square44x44Logo.altform-unplated_targetsize-48.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── Square44x44Logo.altform-lightunplated_targetsize-16.png
│ ├── Square44x44Logo.altform-lightunplated_targetsize-24.png
│ ├── Square44x44Logo.altform-lightunplated_targetsize-256.png
│ ├── Square44x44Logo.altform-lightunplated_targetsize-32.png
│ └── Square44x44Logo.altform-lightunplated_targetsize-48.png
├── Helpers
│ ├── UIHelper.cs
│ ├── Converters
│ │ ├── BoolToVisibilityConverter.cs
│ │ ├── ConverterTools.cs
│ │ └── BoolToObjectConverter.cs
│ ├── WindowHelper.cs
│ ├── UIElementHelper.cs
│ └── ThemeHelper.cs
├── Controls
│ ├── ColorPickerEx.xaml
│ ├── TitleBar.xaml
│ ├── TitleBar.xaml.cs
│ └── ColorPickerEx.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── Default.rd.xml
├── App.xaml
├── Package.appxmanifest
├── Pages
│ ├── MainPage.xaml.cs
│ ├── MainPage.xaml
│ ├── BlurPage.xaml.cs
│ ├── MicaPage.xaml.cs
│ ├── BlurPage.xaml
│ └── MicaPage.xaml
├── Themes
│ └── Color.xaml
├── App.xaml.cs
├── Common
│ ├── Enumerable.cs
│ ├── WeakEvent.cs
│ ├── ExceptionHandling.cs
│ └── ThreadSwitcher.cs
├── ViewModels
│ └── BrushViewModel.cs
└── MicaDemo.csproj
├── Directory.Build.targets
├── MicaForUWP
├── MicaForUWP.targets
├── Properties
│ └── MicaForUWP.rd.xml
├── Media
│ └── BackgroundSource.cs
├── Helpers
│ └── ApiInfoHelper.cs
├── MicaForUWP.nuspec
└── MicaForUWP.csproj
├── .github
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── feature_request.yaml
│ └── bug_report.yaml
├── FUNDING.yml
└── workflows
│ └── build-and-package.yml
├── LICENSE
├── Directory.Build.props
├── README.md
├── MicaForUWP.sln
└── .gitignore
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/logo.png
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "msbuild-sdks": {
3 | "MSBuild.Sdk.Extras": "3.0.44"
4 | }
5 | }
--------------------------------------------------------------------------------
/MicaDemo/Assets/StoreLogo.backup.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/StoreLogo.backup.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/LargeTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/LargeTile.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/LargeTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/LargeTile.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/LargeTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/LargeTile.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/LargeTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/LargeTile.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/LargeTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/LargeTile.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SmallTile.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SmallTile.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SmallTile.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SmallTile.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SmallTile.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SmallTile.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SmallTile.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SmallTile.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SmallTile.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SmallTile.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/StoreLogo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/StoreLogo.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/StoreLogo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/StoreLogo.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/StoreLogo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/StoreLogo.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/StoreLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/StoreLogo.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/StoreLogo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/StoreLogo.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SplashScreen.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SplashScreen.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SplashScreen.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SplashScreen.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SplashScreen.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SplashScreen.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/SplashScreen.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/SplashScreen.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Photos/BigFourSummerHeat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Photos/BigFourSummerHeat.jpg
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square150x150Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square150x150Logo.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square150x150Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square150x150Logo.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square150x150Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square150x150Logo.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square150x150Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square150x150Logo.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Wide310x150Logo.scale-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Wide310x150Logo.scale-100.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Wide310x150Logo.scale-125.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Wide310x150Logo.scale-125.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Wide310x150Logo.scale-150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Wide310x150Logo.scale-150.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Wide310x150Logo.scale-400.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Wide310x150Logo.scale-400.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.targetsize-16.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.targetsize-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.targetsize-24.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.targetsize-32.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.targetsize-48.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.targetsize-256.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-16.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-256.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-32.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-unplated_targetsize-48.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-16.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-24.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-256.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-32.png
--------------------------------------------------------------------------------
/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/HEAD/MicaDemo/Assets/Square44x44Logo.altform-lightunplated_targetsize-48.png
--------------------------------------------------------------------------------
/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | runtime; build; native; contentfiles; analyzers; buildtransitive
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/MicaForUWP/MicaForUWP.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(MSBuildThisFileDirectory)..\..\lib\native\MicaForUWP.winmd
6 | true
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: true
2 | contact_links:
3 | - name: Question
4 | url: https://github.com/wherewhere/Mica-For-UWP/discussions/new?category=q-a
5 | about: Ask a question
6 | - name: Discussion
7 | url: https://github.com/wherewhere/Mica-For-UWP/discussions/new?category=general
8 | about: Start a discussion
9 |
--------------------------------------------------------------------------------
/MicaDemo/Helpers/UIHelper.cs:
--------------------------------------------------------------------------------
1 | using Windows.UI.Xaml;
2 |
3 | namespace MicaDemo.Helpers
4 | {
5 | internal static class UIHelper
6 | {
7 | public static double TitleBarHeight { get; } = ThemeHelper.IsStatusBarSupported ? 4 : 32;
8 | public static Thickness ScrollViewerMargin => new Thickness(0, TitleBarHeight, 0, TitleBarHeight);
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/MicaDemo/Controls/ColorPickerEx.xaml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/MicaForUWP/Properties/MicaForUWP.rd.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/MicaForUWP/Media/BackgroundSource.cs:
--------------------------------------------------------------------------------
1 | namespace MicaForUWP.Media
2 | {
3 | ///
4 | /// Defines values that specify whether the brush samples from the app content or from the content behind the app window.
5 | ///
6 | public enum BackgroundSource
7 | {
8 | ///
9 | /// The brush samples from the content behind the app window.
10 | ///
11 | HostBackdrop = 0,
12 |
13 | ///
14 | /// The brush samples from the app content.
15 | ///
16 | Backdrop = 1,
17 |
18 | ///
19 | /// The brush samples from the wallpaper behind the app window.
20 | ///
21 | WallpaperBackdrop = 2
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: wherewhere
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: ['afdian.com/@wherewhere']
14 |
--------------------------------------------------------------------------------
/MicaDemo/Helpers/Converters/BoolToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using Windows.UI.Xaml;
6 |
7 | namespace MicaDemo.Helpers.Converters
8 | {
9 | ///
10 | /// This class converts a boolean value into a Visibility enumeration.
11 | ///
12 | public class BoolToVisibilityConverter : BoolToObjectConverter
13 | {
14 | ///
15 | /// Initializes a new instance of the class.
16 | ///
17 | public BoolToVisibilityConverter()
18 | {
19 | TrueValue = Visibility.Visible;
20 | FalseValue = Visibility.Collapsed;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/MicaDemo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | // 有关程序集的一般信息由以下
5 | // 控制。更改这些特性值可修改
6 | // 与程序集关联的信息。
7 | [assembly: AssemblyTitle("MicaDemo")]
8 | [assembly: AssemblyDescription("A demo for Mica for UWP which is a lib to use Mica in UWP without WinUI.")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("MicaDemo")]
12 | [assembly: AssemblyCopyright("Copyright © 2017 - 2025 wherewhere. All Rights Reserved.")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // 程序集的版本信息由下列四个值组成:
17 | //
18 | // 主版本
19 | // 次版本
20 | // 生成号
21 | // 修订号
22 | //
23 | //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
24 | //通过使用 "*",如下所示:
25 | // [assembly: AssemblyVersion("1.0.*")]
26 | [assembly: AssemblyVersion("0.0.4.0")]
27 | [assembly: AssemblyFileVersion("0.0.4.0")]
28 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/MicaDemo/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 wherewhere
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 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | false
5 | Full
6 | en-US
7 | $(DefineConstants);WINDOWS_UWP;WINRT
8 | $(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets
9 | native
10 | UAP,Version=v10.0
11 | winmdobj
12 | uap10.0
13 | .NETCore
14 | v5.0
15 | UAP
16 | 10.0.10240.0
17 | 10.0.22621.0
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.yaml:
--------------------------------------------------------------------------------
1 | name: Feature request
2 | description: Suggest an idea for this project
3 | title: "Feature title"
4 | labels: [enhancement]
5 | body:
6 | - type: textarea
7 | validations:
8 | required: true
9 | attributes:
10 | label: Describe your feature request
11 | description: A clear and concise description of what the problem is.
12 | placeholder: I'm always frustrated when [...]
13 | - type: dropdown
14 | validations:
15 | required: true
16 | attributes:
17 | label: How important is this to you?
18 | options:
19 | - "Nice-to-have"
20 | - "Important"
21 | - "Critical"
22 | - type: textarea
23 | attributes:
24 | label: Describe the solution you'd like
25 | description: A clear and concise description of what you want to happen.
26 | - type: textarea
27 | attributes:
28 | label: Describe alternatives you've considered
29 | description: A clear and concise description of any alternative solutions or features you've considered.
30 | - type: textarea
31 | attributes:
32 | label: Additional context
33 | description: Add any other context or screenshots about the feature request here.
34 |
--------------------------------------------------------------------------------
/MicaDemo/Helpers/Converters/ConverterTools.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using Windows.UI.Xaml.Markup;
4 |
5 | namespace MicaDemo.Helpers.Converters
6 | {
7 | ///
8 | /// Static class used to provide internal tools
9 | ///
10 | internal static class ConverterTools
11 | {
12 | ///
13 | /// Helper method to safely cast an object to a boolean
14 | ///
15 | /// Parameter to cast to a boolean
16 | /// Bool value or false if cast failed
17 | internal static bool TryParseBool(object parameter)
18 | {
19 | bool parsed = false;
20 | if (parameter != null)
21 | {
22 | bool.TryParse(parameter.ToString(), out parsed);
23 | }
24 |
25 | return parsed;
26 | }
27 |
28 | ///
29 | /// Helper method to convert a value from a source type to a target type.
30 | ///
31 | /// The value to convert
32 | /// The target type
33 | /// The converted value
34 | internal static object Convert(object value, Type targetType)
35 | {
36 | return targetType.IsInstanceOfType(value) ? value : XamlBindingHelper.ConvertValue(targetType, value);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/MicaDemo/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Segoe Fluent Icons,Segoe MDL2 Assets,Segoe UI Symbol
13 |
21 |
29 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/MicaForUWP/Helpers/ApiInfoHelper.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Versioning;
2 | using Windows.Foundation.Metadata;
3 |
4 | namespace MicaForUWP.Helpers
5 | {
6 | ///
7 | /// Gets information about the availability of Windows Runtime APIs.
8 | ///
9 | #if NET
10 | #pragma warning disable CA1416
11 | [SupportedOSPlatform("Windows10.0.10240.0")]
12 | #endif
13 | public static class ApiInfoHelper
14 | {
15 | #region Properties
16 |
17 | ///
18 | /// Gets is supported.
19 | ///
20 | #if NET
21 | [SupportedOSPlatformGuard("Windows10.0.16299.0")]
22 | #endif
23 | public static bool IsActivationModeSupported { get; } = ApiInformation.IsPropertyPresent("Windows.UI.Core.CoreWindow", "ActivationMode");
24 |
25 | #endregion
26 |
27 | #region Methods
28 |
29 | ///
30 | /// Gets is supported.
31 | ///
32 | #if NET
33 | [SupportedOSPlatformGuard("Windows10.0.14393.0")]
34 | #endif
35 | public static bool IsCreateBackdropBrushSupported { get; } = ApiInformation.IsMethodPresent("Windows.UI.Composition.Compositor", "CreateBackdropBrush");
36 |
37 | ///
38 | /// Gets is supported.
39 | ///
40 | #if NET
41 | [SupportedOSPlatformGuard("Windows10.0.15063.0")]
42 | #endif
43 | public static bool IsCreateHostBackdropBrushSupported { get; } = ApiInformation.IsMethodPresent("Windows.UI.Composition.Compositor", "CreateHostBackdropBrush");
44 |
45 | ///
46 | /// Gets is supported.
47 | ///
48 | #if NET
49 | [SupportedOSPlatformGuard("Windows10.0.22000.0")]
50 | #endif
51 | public static bool IsTryCreateBlurredWallpaperBackdropBrushSupported { get; } = ApiInformation.IsMethodPresent("Windows.UI.Composition.Compositor", "TryCreateBlurredWallpaperBackdropBrush");
52 |
53 | #endregion
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/MicaForUWP/MicaForUWP.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | $authors$
8 | $requireLicenseAcceptance$
9 | $license$
10 | $icon$
11 | $readme$
12 | $projectUrl$
13 | $iconUrl$
14 | $description$
15 | $releaseNotes$
16 | $copyright$
17 | UWP;Mica;WinUI
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/MicaDemo/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
14 |
15 |
16 |
17 |
18 | Mica Demo
19 | wherewhere
20 | Assets\StoreLogo.png
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/MicaDemo/Pages/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using MicaDemo.Pages;
2 | using Windows.Foundation.Metadata;
3 | using Windows.Phone.UI.Input;
4 | using Windows.UI.Core;
5 | using Windows.UI.Xaml;
6 | using Windows.UI.Xaml.Controls;
7 |
8 | // https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x804 上介绍了“空白页”项模板
9 |
10 | namespace MicaDemo
11 | {
12 | ///
13 | /// 可用于自身或导航至 Frame 内部的空白页。
14 | ///
15 | public sealed partial class MainPage : Page
16 | {
17 | public MainPage()
18 | {
19 | InitializeComponent();
20 | SystemNavigationManager.GetForCurrentView().BackRequested += System_BackRequested;
21 | if (ApiInformation.IsTypePresent("Windows.Phone.UI.Input.HardwareButtons"))
22 | { HardwareButtons.BackPressed += System_BackPressed; }
23 | if (!ApiInformation.IsMethodPresent("Windows.UI.Composition.Compositor", "TryCreateBlurredWallpaperBackdropBrush"))
24 | {
25 | MicaSymbol.Symbol = Symbol.Cancel;
26 | ToolTipService.SetToolTip(Mica, "Not Support Wallpaper Backdrop");
27 | }
28 | if (!ApiInformation.IsTypePresent("Windows.UI.Xaml.Media.XamlCompositionBrushBase"))
29 | {
30 | BlurSymbol.Symbol = Symbol.Cancel;
31 | Mica.IsEnabled = Blur.IsEnabled = false;
32 | ToolTipService.SetToolTip(Blur, "Not Support Composition Brush");
33 | }
34 | }
35 |
36 | private void System_BackRequested(object sender, BackRequestedEventArgs e)
37 | {
38 | if (!e.Handled)
39 | {
40 | e.Handled = TryGoBack();
41 | }
42 | }
43 |
44 | private void System_BackPressed(object sender, BackPressedEventArgs e)
45 | {
46 | if (!e.Handled)
47 | {
48 | e.Handled = TryGoBack();
49 | }
50 | }
51 |
52 | private bool TryGoBack(bool goBack = true)
53 | {
54 | if (!Dispatcher.HasThreadAccess || !Frame.CanGoBack)
55 | { return false; }
56 |
57 | if (goBack) { Frame.GoBack(); }
58 | return true;
59 | }
60 |
61 | private void Mica_Click(object sender, RoutedEventArgs e)
62 | {
63 | Frame.Navigate(typeof(MicaPage));
64 | }
65 |
66 | private void Blur_Click(object sender, RoutedEventArgs e)
67 | {
68 | Frame.Navigate(typeof(BlurPage));
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/MicaDemo/Pages/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
10 |
19 |
34 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/.github/workflows/build-and-package.yml:
--------------------------------------------------------------------------------
1 | name: build and package
2 |
3 | on:
4 | push:
5 | pull_request:
6 | branches: [main]
7 | paths:
8 | - 'MicaDemo/**'
9 | - 'MicaForUWP/**'
10 |
11 | jobs:
12 | build-and-package:
13 |
14 | name: build-and-package
15 | runs-on: windows-latest
16 |
17 | env:
18 | Solution_Name: MicaForUWP.sln
19 | Project_Directory: MicaDemo
20 | Signing_Certificate: MicaDemo_TemporaryKey.pfx
21 |
22 | steps:
23 | - name: Checkout
24 | uses: actions/checkout@v4
25 | with:
26 | fetch-depth: 0
27 |
28 | # Decode the base 64 encoded pfx and save the Signing_Certificate
29 | - name: Decode the pfx
30 | run: |
31 | $pfx_cert_byte = [System.Convert]::FromBase64String("$env:Certificate")
32 | $certificatePath = Join-Path -Path $env:Project_Directory -ChildPath $env:Signing_Certificate
33 | [IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte)
34 | env:
35 | Certificate: ${{ secrets.Base64_Encoded_Pfx }}
36 |
37 | # Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
38 | - name: Setup MSBuild.exe
39 | uses: microsoft/setup-msbuild@v2
40 | with:
41 | msbuild-architecture: x64
42 |
43 | # Restore the application to populate the obj folder with RuntimeIdentifiers
44 | - name: Restore the application
45 | run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration
46 | env:
47 | Configuration: Release
48 |
49 | # Create the app package by building and packaging the Windows Application Packaging project
50 | - name: Create the app package
51 | run: msbuild $env:Solution_Name `
52 | /p:LangVersion=latest `
53 | /p:AppxBundlePlatforms="$env:Appx_Bundle_Platforms" `
54 | /p:Configuration=$env:Configuration `
55 | /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode `
56 | /p:AppxBundle=$env:Appx_Bundle `
57 | /p:AppxPackageDir="$env:Appx_Package_Dir" `
58 | /p:AppxPackageSigningEnabled=true `
59 | /p:PackageCertificateThumbprint="$env:Thumbprint" `
60 | /p:PackageCertificateKeyFile=$env:Signing_Certificate `
61 | /p:PackageCertificatePassword="$env:Password"
62 | env:
63 | Appx_Bundle: Always
64 | Appx_Bundle_Platforms: x86|x64|ARM
65 | Appx_Package_Build_Mode: SideloadOnly
66 | Appx_Package_Dir: AppxPackages\
67 | Configuration: Release
68 | Thumbprint: 0CDF4A03E9BE9DD789894BB3C7AD3DEDECD9AB25
69 | Password: ${{ secrets.Password }}
70 |
71 | # Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact
72 | - name: Upload build artifacts
73 | uses: actions/upload-artifact@v4
74 | with:
75 | name: MSIX Package
76 | path: MicaDemo/AppxPackages/**
77 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yaml:
--------------------------------------------------------------------------------
1 | name: Bug report
2 | description: Create a report to help us improve
3 | title: "Bug title"
4 | labels: [bug]
5 | body:
6 | - type: textarea
7 | validations:
8 | required: true
9 | attributes:
10 | label: Describe the bug
11 | description: Please enter a short, clear description of the bug.
12 | - type: textarea
13 | validations:
14 | required: true
15 | attributes:
16 | label: Steps to reproduce the bug
17 | description: Please provide any required setup and steps to reproduce the behavior.
18 | placeholder: |
19 | 1. Go to '...'
20 | 2. Click on '....'
21 | - type: textarea
22 | attributes:
23 | label: Expected behavior
24 | description: Please provide a description of what you expected to happen
25 | - type: textarea
26 | attributes:
27 | label: Screenshots
28 | description: If applicable, add screenshots here to help explain your problem
29 | - type: dropdown
30 | attributes:
31 | label: NuGet package version
32 | description: Specify the version of Mica For UWP you're using.
33 | options:
34 | - "Latest Source"
35 | - "0.2.13"
36 | - "0.2.12"
37 | - "0.1.11"
38 | - "0.1.10"
39 | - "0.1.9"
40 | - "0.1.8"
41 | - "0.0.7"
42 | - "0.0.6"
43 | - "0.0.5"
44 | - "0.0.4"
45 | - "0.0.3"
46 | - "0.0.2"
47 | - "0.0.1"
48 | - type: dropdown
49 | attributes:
50 | label: Windows version
51 | description: Which Windows versions did you see the issue on?
52 | options:
53 | - "Insider Build (xxxxx)"
54 | - "Windows 11 version 22H2 (22621, 2022 Update)"
55 | - "Windows 11 version 21H2 (22000)"
56 | - "Windows 10 version 22H2 (19045, 2022 Update)"
57 | - "Windows 10 version 21H2 (19044, November 2021 Update)"
58 | - "Windows 10 version 21H1 (19043, May 2021 Update)"
59 | - "Windows 10 version 20H2 (19042, October 2020 Update)"
60 | - "Windows 10 version 2004 (19041, May 2020 Update)"
61 | - "Windows 10 version 1909 (18363, November 2019 Update)"
62 | - "Windows 10 version 1903 (18362, May 2019 Update)"
63 | - "Windows 10 version 1809 (17763, October 2018 Update)"
64 | - "Windows 10 version 1803 (17134, April 2018 Update)"
65 | - "Windows 10 version 1709 (16299, Fall Creators Update)"
66 | - "Windows 10 version 1703 (15063, Creators Update)"
67 | - "Windows 10 version 1609 (14393, Anniversary Update)"
68 | - "Windows 10 version 1511 (10586, November Update)"
69 | - "Windows 10 version 1507 (10240)"
70 | - type: dropdown
71 | attributes:
72 | label: IDE
73 | description: Which IDE are you using?
74 | multiple: true
75 | options:
76 | - "Visual Studio 2022-preview"
77 | - "Visual Studio 2022"
78 | - "Visual Studio 2019"
79 | - "Visual Studio 2017"
80 | - "Visual Studio 2015"
81 | - "Other"
82 | - type: textarea
83 | attributes:
84 | label: Additional context
85 | description: Enter any other applicable info here
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Mica For UWP
4 | 一个无需 WinUI 便可实现的 Mica 笔刷
5 |
6 | [](https://github.com/wherewhere/Mica-For-UWP/blob/master/LICENSE "LICENSE")
7 | [](https://github.com/wherewhere/Mica-For-UWP/issues "Issues")
8 | [](https://github.com/wherewhere/Mica-For-UWP/stargazers "Stargazers")
9 |
10 | [](https://www.microsoft.com/store/apps/9NK6JSM7MDNX "Demo")
11 | [](https://www.nuget.org/packages/MicaForUWP "NuGet")
12 |
13 | ## 目录
14 | - [Mica For UWP](#mica-for-uwp)
15 | - [目录](#目录)
16 | - [如何使用](#如何使用)
17 | - [使用到的模块](#使用到的模块)
18 | - [参与人员](#参与人员)
19 |
20 | ## 如何使用
21 | 和普通的笔刷一样
22 | ```xml
23 |
27 |
32 |
37 |
42 |
43 | ```
44 |
45 | ## 使用到的模块
46 | - [Win2D](https://github.com/Microsoft/Win2D "Win2D")
47 |
48 | ## 参与人员
49 | [](https://github.com/wherewhere/Mica-For-UWP/graphs/contributors "Contributors")
50 |
--------------------------------------------------------------------------------
/MicaDemo/Themes/Color.xaml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1
5 | #4C3A3A3A
6 | #19000000
7 | #FF323232
8 | #FF202020
9 | #0DFFFFFF
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 1
18 | #80FFFFFF
19 | #0F000000
20 | #FFE6E6E6
21 | #FFF3F3F3
22 | #B3FFFFFF
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 2
31 | #FF323232
32 | #FF000000
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/MicaDemo/Controls/TitleBar.xaml:
--------------------------------------------------------------------------------
1 |
12 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
54 |
60 |
69 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/MicaDemo/Helpers/Converters/BoolToObjectConverter.cs:
--------------------------------------------------------------------------------
1 | // Licensed to the .NET Foundation under one or more agreements.
2 | // The .NET Foundation licenses this file to you under the MIT license.
3 | // See the LICENSE file in the project root for more information.
4 |
5 | using System;
6 | using Windows.UI.Xaml;
7 | using Windows.UI.Xaml.Data;
8 |
9 | namespace MicaDemo.Helpers.Converters
10 | {
11 | ///
12 | /// This class converts a boolean value into an other object.
13 | /// Can be used to convert true/false to visibility, a couple of colors, couple of images, etc.
14 | ///
15 | public partial class BoolToObjectConverter : DependencyObject, IValueConverter
16 | {
17 | ///
18 | /// Identifies the property.
19 | ///
20 | public static readonly DependencyProperty TrueValueProperty =
21 | DependencyProperty.Register(nameof(TrueValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null));
22 |
23 | ///
24 | /// Identifies the property.
25 | ///
26 | public static readonly DependencyProperty FalseValueProperty =
27 | DependencyProperty.Register(nameof(FalseValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null));
28 |
29 | ///
30 | /// Gets or sets the value to be returned when the boolean is true
31 | ///
32 | public object TrueValue
33 | {
34 | get { return GetValue(TrueValueProperty); }
35 | set { SetValue(TrueValueProperty, value); }
36 | }
37 |
38 | ///
39 | /// Gets or sets the value to be returned when the boolean is false
40 | ///
41 | public object FalseValue
42 | {
43 | get { return GetValue(FalseValueProperty); }
44 | set { SetValue(FalseValueProperty, value); }
45 | }
46 |
47 | ///
48 | /// Convert a boolean value to an other object.
49 | ///
50 | /// The source data being passed to the target.
51 | /// The type of the target property, as a type reference.
52 | /// An optional parameter to be used to invert the converter logic.
53 | /// The language of the conversion.
54 | /// The value to be passed to the target dependency property.
55 | public object Convert(object value, Type targetType, object parameter, string language)
56 | {
57 | bool boolValue = value is bool && (bool)value;
58 |
59 | // Negate if needed
60 | if (ConverterTools.TryParseBool(parameter))
61 | {
62 | boolValue = !boolValue;
63 | }
64 |
65 | return ConverterTools.Convert(boolValue ? TrueValue : FalseValue, targetType);
66 | }
67 |
68 | ///
69 | /// Convert back the value to a boolean
70 | ///
71 | /// If the parameter is a reference type, must match its reference to return true.
72 | /// The target data being passed to the source.
73 | /// The type of the target property, as a type reference (System.Type for Microsoft .NET, a TypeName helper struct for Visual C++ component extensions (C++/CX)).
74 | /// An optional parameter to be used to invert the converter logic.
75 | /// The language of the conversion.
76 | /// The value to be passed to the source object.
77 | public object ConvertBack(object value, Type targetType, object parameter, string language)
78 | {
79 | bool result = Equals(value, ConverterTools.Convert(TrueValue, value.GetType()));
80 |
81 | if (ConverterTools.TryParseBool(parameter))
82 | {
83 | result = !result;
84 | }
85 |
86 | return result;
87 | }
88 | }
89 | }
--------------------------------------------------------------------------------
/MicaForUWP/MicaForUWP.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | true
5 | true
6 | $(NoWarn);NU1902;NU1903
7 |
8 |
9 |
10 | wherewhere
11 | true
12 | Copyright © 2017 - 2025 wherewhere. All Rights Reserved.
13 | true
14 | true
15 | true
16 | git
17 | https://github.com/wherewhere/Mica-For-UWP
18 | Mica UWP - Use Mica without WinUI
19 | 0.2.13
20 | A UWP Library that implement an easy way to use Mica material without WinUI.
21 |
22 |
23 |
24 | 6.2.14
25 | 7.3
26 | uap10.0
27 | $(TargetFrameworks);native;netcoreapp3.1;uap10.0.15138.0
28 | $(TargetFrameworks);net8.0-windows10.0.22000.0
29 |
30 |
31 |
32 | true
33 | Icon.png
34 | https://raw.githubusercontent.com/wherewhere/Mica-For-UWP/main/logo.png
35 | MIT
36 | https://github.com/wherewhere/Mica-For-UWP
37 | README.md
38 | https://github.com/wherewhere/Mica-For-UWP/releases
39 | true
40 | UWP;Mica;WinUI
41 | snupkg
42 |
43 |
44 |
45 | MicaForUWP.nuspec
46 | id=$(AssemblyName);version=$(VersionPrefix);title=$(Title);authors=$(Authors);requireLicenseAcceptance=$(PackageRequireLicenseAcceptance);license=$(PackageLicenseExpression);icon=$(PackageIcon);readme=$(PackageReadmeFile);projectUrl=$(PackageProjectUrl);iconUrl=$(PackageIconUrl);description=$(Description);releaseNotes=$(PackageReleaseNotes);copyright=$(Copyright);repositoryType=$(RepositoryType);repositoryUrl=$(PackageProjectUrl);repositoryCommit=$(RepositoryCommit);buildOutput=bin\$(Configuration)
47 |
48 |
49 |
50 | true
51 |
52 |
53 |
54 | true
55 | latest
56 | true
57 | false
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 10.0
75 | 10.0.26100.0
76 |
77 |
78 |
79 | 10.0.15138.0
80 | 10.0.26100.0
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/MicaDemo/Helpers/WindowHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Windows.ApplicationModel.Core;
5 | using Windows.Foundation.Metadata;
6 | using Windows.UI.Core;
7 | using Windows.UI.ViewManagement;
8 | using Windows.UI.WindowManagement;
9 | using Windows.UI.Xaml;
10 | using Windows.UI.Xaml.Controls;
11 | using Windows.UI.Xaml.Hosting;
12 |
13 | namespace MicaDemo.Helpers
14 | {
15 | ///
16 | /// Helpers class to allow the app to find the Window that contains an
17 | /// arbitrary ().
18 | /// To do this, we keep track of all active Windows. The app code must call
19 | /// rather than "new ()"
20 | /// so we can keep track of all the relevant windows.
21 | ///
22 | public static class WindowHelper
23 | {
24 | public static bool IsAppWindowSupported { get; } = ApiInformation.IsTypePresent("Windows.UI.WindowManagement.AppWindow");
25 | public static bool IsXamlRootSupported { get; } = ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot");
26 |
27 | public static async Task CreateWindowAsync(Action launched)
28 | {
29 | CoreApplicationView newView = CoreApplication.CreateNewView();
30 | int newViewId = 0;
31 | await newView.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
32 | {
33 | Window window = Window.Current;
34 | TrackWindow(window);
35 | launched(window);
36 | window.Activate();
37 | newViewId = ApplicationView.GetForCurrentView().Id;
38 | });
39 | return await ApplicationViewSwitcher.TryShowAsStandaloneAsync(newViewId);
40 | }
41 |
42 | public static async Task> CreateWindowAsync()
43 | {
44 | Frame newFrame = new Frame();
45 | AppWindow newWindow = await AppWindow.TryCreateAsync();
46 | ElementCompositionPreview.SetAppWindowContent(newWindow, newFrame);
47 | TrackWindow(newWindow, newFrame);
48 | return new Tuple(newWindow, newFrame);
49 | }
50 |
51 | public static void TrackWindow(this Window window)
52 | {
53 | if (!ActiveWindows.ContainsKey(window.Dispatcher))
54 | {
55 | window.Closed += (sender, args) =>
56 | {
57 | ActiveWindows.Remove(window.Dispatcher);
58 | window = null;
59 | };
60 | ActiveWindows[window.Dispatcher] = window;
61 | }
62 | }
63 |
64 | private static void TrackWindow(this AppWindow window, Frame frame)
65 | {
66 | if (!ActiveAppWindows.TryGetValue(frame.Dispatcher, out Dictionary windows))
67 | {
68 | ActiveAppWindows[frame.Dispatcher] = windows = new Dictionary();
69 | }
70 |
71 | if (!windows.ContainsKey(frame.XamlRoot))
72 | {
73 | window.Closed += (sender, args) =>
74 | {
75 | windows.Remove(frame.XamlRoot);
76 | if (windows.Count <= 0)
77 | { ActiveAppWindows.Remove(frame.Dispatcher); }
78 | frame.Content = null;
79 | window = null;
80 | };
81 | windows[frame.XamlRoot] = window;
82 | }
83 | }
84 |
85 | public static bool IsAppWindow(this UIElement element) =>
86 | IsAppWindowSupported
87 | && element?.XamlRoot != null
88 | && ActiveAppWindows.TryGetValue(element.Dispatcher, out Dictionary windows)
89 | && windows.ContainsKey(element.XamlRoot);
90 |
91 | public static AppWindow GetWindowForElement(this UIElement element) =>
92 | IsAppWindowSupported
93 | && element?.XamlRoot != null
94 | && ActiveAppWindows.TryGetValue(element.Dispatcher, out Dictionary windows)
95 | && windows.TryGetValue(element.XamlRoot, out AppWindow window)
96 | ? window : null;
97 |
98 | public static UIElement GetXamlRootForWindow(this AppWindow window) => ElementCompositionPreview.GetAppWindowContent(window);
99 |
100 | public static Dictionary ActiveWindows { get; } = new Dictionary();
101 | public static Dictionary> ActiveAppWindows { get; } = IsAppWindowSupported ? new Dictionary>() : null;
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/MicaDemo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using MicaDemo.Common;
2 | using MicaDemo.Helpers;
3 | using System;
4 | using Windows.ApplicationModel;
5 | using Windows.ApplicationModel.Activation;
6 | using Windows.ApplicationModel.Core;
7 | using Windows.Foundation.Metadata;
8 | using Windows.System.Profile;
9 | using Windows.UI.Xaml;
10 | using Windows.UI.Xaml.Controls;
11 | using Windows.UI.Xaml.Media.Animation;
12 | using Windows.UI.Xaml.Navigation;
13 |
14 | namespace MicaDemo
15 | {
16 | ///
17 | /// 提供特定于应用程序的行为,以补充默认的应用程序类。
18 | ///
19 | public sealed partial class App : Application
20 | {
21 | ///
22 | /// 初始化单一实例应用程序对象。这是执行的创作代码的第一行,
23 | /// 已执行,逻辑上等同于 main() 或 WinMain()。
24 | ///
25 | public App()
26 | {
27 | InitializeComponent();
28 | Suspending += OnSuspending;
29 | UnhandledException += Application_UnhandledException;
30 | if (ApiInformation.IsEnumNamedValuePresent("Windows.UI.Xaml.FocusVisualKind", "Reveal") && AnalyticsInfo.VersionInfo.DeviceFamily == "Windows.Xbox")
31 | {
32 | FocusVisualKind = FocusVisualKind.Reveal;
33 | }
34 | }
35 |
36 | ///
37 | /// 在应用程序由最终用户正常启动时进行调用。
38 | /// 将在启动应用程序以打开特定文件等情况下使用。
39 | ///
40 | /// 有关启动请求和过程的详细信息。
41 | protected override void OnLaunched(LaunchActivatedEventArgs e)
42 | {
43 | if (!isLoaded)
44 | {
45 | RegisterExceptionHandlingSynchronizationContext();
46 | isLoaded = true;
47 | }
48 |
49 | Window window = Window.Current;
50 |
51 | // 不要在窗口已包含内容时重复应用程序初始化,
52 | // 只需确保窗口处于活动状态
53 | if (!(window.Content is Frame rootFrame))
54 | {
55 | CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
56 |
57 | // 创建要充当导航上下文的框架,并导航到第一页
58 | rootFrame = new Frame();
59 |
60 | rootFrame.NavigationFailed += OnNavigationFailed;
61 |
62 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
63 | {
64 | //TODO: 从之前挂起的应用程序加载状态
65 | }
66 |
67 | // 将框架放在当前窗口中
68 | window.Content = rootFrame;
69 |
70 | WindowHelper.TrackWindow(window);
71 | ThemeHelper.Initialize(window);
72 | }
73 |
74 | if (!e.PrelaunchActivated)
75 | {
76 | if (ApiInformation.IsMethodPresent("Windows.ApplicationModel.Core.CoreApplication", "EnablePrelaunch"))
77 | {
78 | CoreApplication.EnablePrelaunch(true);
79 | }
80 |
81 | if (rootFrame.Content == null)
82 | {
83 | // 当导航堆栈尚未还原时,导航到第一页,
84 | // 并通过将所需信息作为导航参数传入来配置
85 | // 参数
86 | rootFrame.Navigate(typeof(MainPage), e.Arguments, new DrillInNavigationTransitionInfo());
87 | }
88 |
89 | // 确保当前窗口处于活动状态
90 | window.Activate();
91 | }
92 | }
93 |
94 | ///
95 | /// 导航到特定页失败时调用
96 | ///
97 | ///导航失败的框架
98 | ///有关导航失败的详细信息
99 | private void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
100 | {
101 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
102 | }
103 |
104 | ///
105 | /// 在将要挂起应用程序执行时调用。 在不知道应用程序
106 | /// 无需知道应用程序会被终止还是会恢复,
107 | /// 并让内存内容保持不变。
108 | ///
109 | /// 挂起的请求的源。
110 | /// 有关挂起请求的详细信息。
111 | private void OnSuspending(object sender, SuspendingEventArgs e)
112 | {
113 | SuspendingDeferral deferral = e.SuspendingOperation.GetDeferral();
114 | //TODO: 保存应用程序状态并停止任何后台活动
115 | deferral.Complete();
116 | }
117 |
118 | private void Application_UnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e) => e.Handled = true;
119 |
120 | ///
121 | /// Should be called from OnActivated and OnLaunched.
122 | ///
123 | private void RegisterExceptionHandlingSynchronizationContext()
124 | {
125 | ExceptionHandlingSynchronizationContext
126 | .Register()
127 | .UnhandledException += SynchronizationContext_UnhandledException;
128 | }
129 |
130 | private void SynchronizationContext_UnhandledException(object sender, Common.UnhandledExceptionEventArgs e) => e.Handled = true;
131 |
132 | private bool isLoaded;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/MicaDemo/Controls/TitleBar.xaml.cs:
--------------------------------------------------------------------------------
1 | using Windows.UI.Xaml;
2 | using Windows.UI.Xaml.Controls;
3 | using Windows.UI.Xaml.Input;
4 | using Windows.UI.Xaml.Markup;
5 |
6 | //https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板
7 |
8 | namespace MicaDemo.Controls
9 | {
10 | [ContentProperty(Name = "RightAreaContent")]
11 | public sealed partial class TitleBar : UserControl
12 | {
13 | public static readonly DependencyProperty TitleProperty =
14 | DependencyProperty.Register(
15 | nameof(Title),
16 | typeof(string),
17 | typeof(TitleBar),
18 | new PropertyMetadata(default(string)));
19 |
20 | public static readonly DependencyProperty TitleHeightProperty =
21 | DependencyProperty.Register(
22 | nameof(TitleHeight),
23 | typeof(double),
24 | typeof(TitleBar),
25 | new PropertyMetadata(40d));
26 |
27 | public static readonly DependencyProperty IsBackEnableProperty =
28 | DependencyProperty.Register(
29 | nameof(IsBackEnable),
30 | typeof(bool),
31 | typeof(TitleBar),
32 | new PropertyMetadata(true));
33 |
34 | public static readonly DependencyProperty RightAreaContentProperty =
35 | DependencyProperty.Register(
36 | nameof(RightAreaContent),
37 | typeof(object),
38 | typeof(TitleBar),
39 | null);
40 |
41 | public static readonly DependencyProperty BackgroundVisibilityProperty =
42 | DependencyProperty.Register(
43 | nameof(BackgroundVisibility),
44 | typeof(Visibility),
45 | typeof(TitleBar),
46 | new PropertyMetadata(Visibility.Collapsed));
47 |
48 | public static readonly DependencyProperty BackButtonVisibilityProperty =
49 | DependencyProperty.Register(
50 | nameof(BackButtonVisibility),
51 | typeof(Visibility),
52 | typeof(TitleBar),
53 | new PropertyMetadata(Visibility.Visible));
54 |
55 | public static readonly DependencyProperty RefreshButtonVisibilityProperty =
56 | DependencyProperty.Register(
57 | nameof(RefreshButtonVisibility),
58 | typeof(Visibility),
59 | typeof(TitleBar),
60 | new PropertyMetadata(Visibility.Collapsed));
61 |
62 | public string Title
63 | {
64 | get => (string)GetValue(TitleProperty);
65 | set => SetValue(TitleProperty, value);
66 | }
67 |
68 | public double TitleHeight
69 | {
70 | get => (double)GetValue(TitleHeightProperty);
71 | set => SetValue(TitleHeightProperty, value);
72 | }
73 |
74 | public bool IsBackEnable
75 | {
76 | get => (bool)GetValue(IsBackEnableProperty);
77 | set => SetValue(IsBackEnableProperty, value);
78 | }
79 |
80 | public object RightAreaContent
81 | {
82 | get => GetValue(RightAreaContentProperty);
83 | set => SetValue(RightAreaContentProperty, value);
84 | }
85 |
86 | public Visibility BackgroundVisibility
87 | {
88 | get => (Visibility)GetValue(BackgroundVisibilityProperty);
89 | set => SetValue(BackgroundVisibilityProperty, value);
90 | }
91 |
92 | public Visibility BackButtonVisibility
93 | {
94 | get => (Visibility)GetValue(BackButtonVisibilityProperty);
95 | set => SetValue(BackButtonVisibilityProperty, value);
96 | }
97 |
98 | public Visibility RefreshButtonVisibility
99 | {
100 | get => (Visibility)GetValue(RefreshButtonVisibilityProperty);
101 | set => SetValue(RefreshButtonVisibilityProperty, value);
102 | }
103 |
104 | public event RoutedEventHandler RefreshEvent;
105 | public event RoutedEventHandler BackRequested;
106 |
107 | public TitleBar() => InitializeComponent();
108 |
109 | private void RefreshButton_Click(object sender, RoutedEventArgs e) => RefreshEvent?.Invoke(sender, e);
110 |
111 | private void BackButton_Click(object sender, RoutedEventArgs e) => BackRequested?.Invoke(sender, e);
112 |
113 | private void TitleGrid_Tapped(object sender, TappedRoutedEventArgs e)
114 | {
115 | if (e.OriginalSource is Grid || (e.OriginalSource is TextBlock a && a == TitleBlock))
116 | { RefreshEvent?.Invoke(sender, e); }
117 | }
118 |
119 | public void ShowProgressRing()
120 | {
121 | ProgressRing.IsActive = true;
122 | ProgressRing.Visibility = Visibility.Visible;
123 | }
124 |
125 | public void HideProgressRing()
126 | {
127 | ProgressRing.Visibility = Visibility.Collapsed;
128 | ProgressRing.IsActive = false;
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/MicaForUWP.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.1.32113.165
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicaDemo", "MicaDemo\MicaDemo.csproj", "{6E6F491C-7B25-4BBC-AA5F-147E14A200C4}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MicaForUWP", "MicaForUWP\MicaForUWP.csproj", "{50913772-1182-44A9-8157-0410895E0DB3}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|ARM = Debug|ARM
14 | Debug|ARM64 = Debug|ARM64
15 | Debug|x64 = Debug|x64
16 | Debug|x86 = Debug|x86
17 | Release|Any CPU = Release|Any CPU
18 | Release|ARM = Release|ARM
19 | Release|ARM64 = Release|ARM64
20 | Release|x64 = Release|x64
21 | Release|x86 = Release|x86
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|Any CPU.ActiveCfg = Debug|x64
25 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|Any CPU.Build.0 = Debug|x64
26 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|Any CPU.Deploy.0 = Debug|x64
27 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|ARM.ActiveCfg = Debug|ARM
28 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|ARM.Build.0 = Debug|ARM
29 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|ARM.Deploy.0 = Debug|ARM
30 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|ARM64.ActiveCfg = Debug|ARM64
31 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|ARM64.Build.0 = Debug|ARM64
32 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|ARM64.Deploy.0 = Debug|ARM64
33 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|x64.ActiveCfg = Debug|x64
34 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|x64.Build.0 = Debug|x64
35 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|x64.Deploy.0 = Debug|x64
36 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|x86.ActiveCfg = Debug|x86
37 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|x86.Build.0 = Debug|x86
38 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Debug|x86.Deploy.0 = Debug|x86
39 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|Any CPU.ActiveCfg = Release|x64
40 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|Any CPU.Build.0 = Release|x64
41 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|Any CPU.Deploy.0 = Release|x64
42 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|ARM.ActiveCfg = Release|ARM
43 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|ARM.Build.0 = Release|ARM
44 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|ARM.Deploy.0 = Release|ARM
45 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|ARM64.ActiveCfg = Release|ARM64
46 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|ARM64.Build.0 = Release|ARM64
47 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|ARM64.Deploy.0 = Release|ARM64
48 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|x64.ActiveCfg = Release|x64
49 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|x64.Build.0 = Release|x64
50 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|x64.Deploy.0 = Release|x64
51 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|x86.ActiveCfg = Release|x86
52 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|x86.Build.0 = Release|x86
53 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}.Release|x86.Deploy.0 = Release|x86
54 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
55 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
56 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|ARM.ActiveCfg = Debug|Any CPU
57 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|ARM.Build.0 = Debug|Any CPU
58 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|ARM64.ActiveCfg = Debug|Any CPU
59 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|ARM64.Build.0 = Debug|Any CPU
60 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|x64.ActiveCfg = Debug|Any CPU
61 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|x64.Build.0 = Debug|Any CPU
62 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|x86.ActiveCfg = Debug|Any CPU
63 | {50913772-1182-44A9-8157-0410895E0DB3}.Debug|x86.Build.0 = Debug|Any CPU
64 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
65 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|Any CPU.Build.0 = Release|Any CPU
66 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|ARM.ActiveCfg = Release|Any CPU
67 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|ARM.Build.0 = Release|Any CPU
68 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|ARM64.ActiveCfg = Release|Any CPU
69 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|ARM64.Build.0 = Release|Any CPU
70 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|x64.ActiveCfg = Release|Any CPU
71 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|x64.Build.0 = Release|Any CPU
72 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|x86.ActiveCfg = Release|Any CPU
73 | {50913772-1182-44A9-8157-0410895E0DB3}.Release|x86.Build.0 = Release|Any CPU
74 | EndGlobalSection
75 | GlobalSection(SolutionProperties) = preSolution
76 | HideSolutionNode = FALSE
77 | EndGlobalSection
78 | GlobalSection(ExtensibilityGlobals) = postSolution
79 | SolutionGuid = {DAF7DD8F-AD7B-44FF-B85A-FA04AF23897F}
80 | EndGlobalSection
81 | EndGlobal
82 |
--------------------------------------------------------------------------------
/MicaDemo/Controls/ColorPickerEx.xaml.cs:
--------------------------------------------------------------------------------
1 | using Windows.Foundation.Metadata;
2 | using Windows.UI;
3 | using Windows.UI.Xaml;
4 | using Windows.UI.Xaml.Controls;
5 | using Windows.UI.Xaml.Controls.Primitives;
6 | using Windows.UI.Xaml.Data;
7 |
8 | //https://go.microsoft.com/fwlink/?LinkId=234236 上介绍了“用户控件”项模板
9 |
10 | namespace MicaDemo.Controls
11 | {
12 | public sealed partial class ColorPickerEx : UserControl
13 | {
14 | private Slider ASlider;
15 | private Slider RSlider;
16 | private Slider GSlider;
17 | private Slider BSlider;
18 |
19 | #region ContextFlyout
20 |
21 | ///
22 | /// Identifies the dependency property.
23 | ///
24 | public static readonly DependencyProperty ColorProperty =
25 | DependencyProperty.Register(
26 | nameof(Color),
27 | typeof(Color),
28 | typeof(ColorPickerEx),
29 | new PropertyMetadata(default(Color), OnColorPropertyChanged));
30 |
31 | public Color Color
32 | {
33 | get => (Color)GetValue(ColorProperty);
34 | set => SetValue(ColorProperty, value);
35 | }
36 |
37 | private static void OnColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
38 | {
39 | if (!ApiInformation.IsTypePresent("Windows.UI.Xaml.Controls.ColorPicker"))
40 | {
41 | (d as ColorPickerEx).OnColorPropertyChanged(e);
42 | }
43 | }
44 |
45 | #endregion
46 |
47 | public ColorPickerEx()
48 | {
49 | InitializeComponent();
50 | CreateColorPicker();
51 | }
52 |
53 | private void CreateColorPicker()
54 | {
55 | if (ApiInformation.IsTypePresent("Windows.UI.Xaml.Controls.ColorPicker"))
56 | {
57 | ColorPicker ColorPicker = new ColorPicker
58 | {
59 | IsAlphaEnabled = true,
60 | IsAlphaSliderVisible = true,
61 | IsAlphaTextInputVisible = true,
62 | IsMoreButtonVisible = true,
63 | };
64 | ColorPicker.SetBinding(ColorPicker.ColorProperty, new Binding
65 | {
66 | Source = this,
67 | Mode = BindingMode.TwoWay,
68 | Path = new PropertyPath(nameof(Color))
69 | });
70 | Content = ColorPicker;
71 | }
72 | else
73 | {
74 | StackPanel StackPanel = new StackPanel();
75 |
76 | ASlider = new Slider
77 | {
78 | Header = "Alpha",
79 | Minimum = 0,
80 | Maximum = 255,
81 | StepFrequency = 1
82 | };
83 | RSlider = new Slider
84 | {
85 | Header = "Red",
86 | Minimum = 0,
87 | Maximum = 255,
88 | StepFrequency = 1
89 | };
90 | GSlider = new Slider
91 | {
92 | Header = "Green",
93 | Minimum = 0,
94 | Maximum = 255,
95 | StepFrequency = 1
96 | };
97 | BSlider = new Slider
98 | {
99 | Header = "Blue",
100 | Minimum = 0,
101 | Maximum = 255,
102 | StepFrequency = 1
103 | };
104 |
105 | ASlider.ValueChanged += OnValueChanged;
106 | RSlider.ValueChanged += OnValueChanged;
107 | GSlider.ValueChanged += OnValueChanged;
108 | BSlider.ValueChanged += OnValueChanged;
109 |
110 | StackPanel.Children.Add(ASlider);
111 | StackPanel.Children.Add(RSlider);
112 | StackPanel.Children.Add(GSlider);
113 | StackPanel.Children.Add(BSlider);
114 |
115 | Content = StackPanel;
116 | }
117 | }
118 |
119 | private void SetSliderValue(Color Color)
120 | {
121 | if (ASlider != null) { ASlider.Value = Color.A; }
122 | if (RSlider != null) { RSlider.Value = Color.R; }
123 | if (GSlider != null) { GSlider.Value = Color.G; }
124 | if (BSlider != null) { BSlider.Value = Color.B; }
125 | }
126 |
127 | private void OnColorPropertyChanged(DependencyPropertyChangedEventArgs e)
128 | {
129 | if (e.NewValue != e.OldValue && e.NewValue is Color Color)
130 | {
131 | SetSliderValue(Color);
132 | }
133 | }
134 |
135 | private void OnValueChanged(object sender, RangeBaseValueChangedEventArgs e)
136 | {
137 | if (e.NewValue != e.OldValue)
138 | {
139 | Color = Color.FromArgb((byte)ASlider.Value, (byte)RSlider.Value, (byte)GSlider.Value, (byte)BSlider.Value);
140 | }
141 | }
142 | }
143 | }
144 |
--------------------------------------------------------------------------------
/MicaDemo/Common/Enumerable.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Collections.Immutable;
4 | using System.Linq;
5 |
6 | namespace MicaDemo.Common
7 | {
8 | public static class Enumerable
9 | {
10 | ///
11 | /// Adds the elements of the specified collection to the end of the .
12 | ///
13 | /// The type of the elements of .
14 | /// The to be added.
15 | /// The collection whose elements should be added to the end of the .
16 | /// The collection itself cannot be , but it can contain elements that are
17 | /// , if type is a reference type.
18 | /// or is null.
19 | public static void AddRange(this ICollection source, IEnumerable collection)
20 | {
21 | if (source == null)
22 | {
23 | throw new ArgumentNullException(nameof(source));
24 | }
25 |
26 | if (collection == null)
27 | {
28 | throw new ArgumentNullException(nameof(collection));
29 | }
30 |
31 | if (source is List list)
32 | {
33 | list.AddRange(collection);
34 | }
35 | else if (source is TSource[] array)
36 | {
37 | int length = collection.Count();
38 | int count = collection is List _list
39 | ? _list.FindLastIndex(x => x != null) + 1
40 | : collection is TSource[] _array
41 | ? Array.FindLastIndex(_array, x => x != null) + 1
42 | : length;
43 |
44 | if (count > 0)
45 | {
46 | int _size = Array.FindLastIndex(array, x => x != null) + 1;
47 | if (array.Length - _size < count)
48 | {
49 | throw new ArgumentOutOfRangeException(nameof(array));
50 | }
51 |
52 | if (count == length)
53 | {
54 | if (collection is ICollection _collection)
55 | {
56 | _collection.CopyTo(array, _size);
57 | }
58 | else
59 | {
60 | foreach (TSource item in collection)
61 | {
62 | array[_size++] = item;
63 | }
64 | }
65 | }
66 | else
67 | {
68 | using (IEnumerator enumerator = collection.GetEnumerator())
69 | {
70 | while (--count >= 0 && enumerator.MoveNext())
71 | {
72 | array[_size++] = enumerator.Current;
73 | }
74 | }
75 | }
76 | }
77 | }
78 | else if (source is ISet set)
79 | {
80 | set.UnionWith(collection);
81 | }
82 | else
83 | {
84 | foreach (TSource item in collection)
85 | {
86 | source.Add(item);
87 | }
88 | }
89 | }
90 |
91 | ///
92 | /// Performs the specified action on each element of the .
93 | ///
94 | /// The type of the elements of .
95 | ///
96 | /// The delegate to perform on each element of the .
97 | /// or is null.
98 | public static void ForEach(this IEnumerable source, Action action)
99 | {
100 | if (source == null)
101 | {
102 | throw new ArgumentNullException(nameof(source));
103 | }
104 |
105 | if (action == null)
106 | {
107 | throw new ArgumentNullException(nameof(action));
108 | }
109 |
110 | if (source is List list)
111 | {
112 | list.ForEach(action);
113 | }
114 | else if (source is TSource[] array)
115 | {
116 | #if NETCORE463
117 | Array.ForEach(array, action);
118 | #else
119 | foreach (TSource item in array)
120 | {
121 | action(item);
122 | }
123 | #endif
124 | }
125 | else if (source is ImmutableList immutableList)
126 | {
127 | immutableList.ForEach(action);
128 | }
129 | else
130 | {
131 | foreach (TSource item in source)
132 | {
133 | action(item);
134 | }
135 | }
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/MicaDemo/Pages/BlurPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using MicaDemo.Common;
2 | using MicaDemo.Helpers;
3 | using MicaDemo.ViewModels;
4 | using MicaForUWP.Media;
5 | using System;
6 | using Windows.ApplicationModel.Core;
7 | using Windows.UI;
8 | using Windows.UI.WindowManagement;
9 | using Windows.UI.Xaml;
10 | using Windows.UI.Xaml.Controls;
11 | using Windows.UI.Xaml.Input;
12 | using Windows.UI.Xaml.Media.Animation;
13 | using Windows.UI.Xaml.Navigation;
14 |
15 | // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板
16 |
17 | namespace MicaDemo.Pages
18 | {
19 | ///
20 | /// 可用于自身或导航至 Frame 内部的空白页。
21 | ///
22 | public sealed partial class BlurPage : Page
23 | {
24 | private readonly BrushViewModel Provider;
25 |
26 | private bool isDark;
27 | private long token;
28 |
29 | private bool IsHideCard
30 | {
31 | get => Provider.IsHideCard;
32 | set
33 | {
34 | if (Provider.IsHideCard != value)
35 | {
36 | Provider.IsHideCard = value;
37 | VisualStateManager.GoToState(this, value ? "HideCard" : "DisplayCard", true);
38 | }
39 | }
40 | }
41 |
42 | public BlurPage()
43 | {
44 | InitializeComponent();
45 | Provider = new BrushViewModel(Dispatcher) { SelectSource = MicaForUWP.Media.BackgroundSource.Backdrop };
46 | }
47 |
48 | protected override void OnNavigatedTo(NavigationEventArgs e)
49 | {
50 | base.OnNavigatedTo(e);
51 | ThemeHelper.UISettingChanged += OnUISettingChanged;
52 | token = BackdropBrush.RegisterPropertyChangedCallback(BackdropBlurBrush.TintColorProperty, OnTintColorPropertyChanged);
53 | OnTintColorPropertyChanged(BackdropBrush, BackdropBlurBrush.TintColorProperty);
54 | VisualStateManager.GoToState(this, "DisplayCard", false);
55 | }
56 |
57 | protected override void OnNavigatedFrom(NavigationEventArgs e)
58 | {
59 | base.OnNavigatedFrom(e);
60 | ThemeHelper.UISettingChanged -= OnUISettingChanged;
61 | BackdropBrush.UnregisterPropertyChangedCallback(BackdropBlurBrush.TintColorProperty, token);
62 | }
63 |
64 | private void Page_Loaded(object sender, RoutedEventArgs e)
65 | {
66 | _ = ThemeHelper.GetRootThemeAsync().ContinueWith(x => ThemeHelper.IsDarkTheme(x.Result)).ContinueWith(x => isDark = x.Result);
67 | Provider.CompactOverlay = this.IsAppWindow() ? (ICompactOverlay)new AppWindowCompactOverlay(this.GetWindowForElement()) : new CoreWindowCompactOverlay();
68 | }
69 |
70 | private async void OnUISettingChanged(bool theme)
71 | {
72 | if (isDark != theme)
73 | {
74 | await Dispatcher.ResumeForegroundAsync();
75 | TintColor.Color = ReversalColor(TintColor.Color);
76 | isDark = theme;
77 | }
78 |
79 | Color ReversalColor(in Color color)
80 | {
81 | return Color.FromArgb(color.A, (byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B));
82 | }
83 | }
84 |
85 | private void OnTintColorPropertyChanged(DependencyObject sender, DependencyProperty dp)
86 | {
87 | Color color = (Color)sender.GetValue(dp);
88 | bool isLight = color.IsColorLight();
89 | RequestedTheme = isLight ? ElementTheme.Light : ElementTheme.Dark;
90 | }
91 |
92 | private void TitleBar_BackRequested(object sender, RoutedEventArgs e)
93 | {
94 | if (Frame.CanGoBack) { Frame.GoBack(); }
95 | }
96 |
97 | private async void Button_Click(object sender, RoutedEventArgs e)
98 | {
99 | switch ((sender as FrameworkElement).Tag?.ToString())
100 | {
101 | case "NewWindow":
102 | _ = await WindowHelper.CreateWindowAsync(window =>
103 | {
104 | CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
105 | Frame _frame = new Frame();
106 | window.Content = _frame;
107 | ThemeHelper.Initialize(window);
108 | _ = _frame.Navigate(typeof(MainPage), null, new DrillInNavigationTransitionInfo());
109 | });
110 | break;
111 | case "NewAppWindow" when WindowHelper.IsAppWindowSupported:
112 | Tuple appWindow = await WindowHelper.CreateWindowAsync();
113 | appWindow.Item1.TitleBar.ExtendsContentIntoTitleBar = true;
114 | ThemeHelper.Initialize(appWindow.Item1);
115 | appWindow.Item2.Navigate(typeof(MainPage), null, new DrillInNavigationTransitionInfo());
116 | await appWindow.Item1.TryShowAsync();
117 | break;
118 | case "ChangeTheme":
119 | _ = ThemeHelper.IsDarkThemeAsync().ContinueWith(x => ThemeHelper.SetRootThemeAsync(x.Result ? ElementTheme.Light : ElementTheme.Dark));
120 | break;
121 | case "ChangeImage":
122 | _ = Provider.PickImageAsync();
123 | return;
124 | case "RemoveImage":
125 | Provider.BackgroundImage = null;
126 | break;
127 | case "HideSetting":
128 | IsHideCard = true;
129 | break;
130 | case "ShowSetting":
131 | IsHideCard = false;
132 | break;
133 | default:
134 | break;
135 | }
136 | }
137 |
138 | private void Grid_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
139 | {
140 | if (e?.Handled == true) { return; }
141 | IsHideCard = !IsHideCard;
142 | if (e != null) { e.Handled = true; }
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/MicaDemo/Pages/MicaPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using MicaDemo.Common;
2 | using MicaDemo.Helpers;
3 | using MicaDemo.ViewModels;
4 | using MicaForUWP.Media;
5 | using System;
6 | using Windows.ApplicationModel.Core;
7 | using Windows.UI;
8 | using Windows.UI.WindowManagement;
9 | using Windows.UI.Xaml;
10 | using Windows.UI.Xaml.Controls;
11 | using Windows.UI.Xaml.Input;
12 | using Windows.UI.Xaml.Media.Animation;
13 | using Windows.UI.Xaml.Navigation;
14 |
15 | // https://go.microsoft.com/fwlink/?LinkId=234238 上介绍了“空白页”项模板
16 |
17 | namespace MicaDemo.Pages
18 | {
19 | ///
20 | /// 可用于自身或导航至 Frame 内部的空白页。
21 | ///
22 | public sealed partial class MicaPage : Page
23 | {
24 | private readonly BrushViewModel Provider;
25 |
26 | private bool isDark;
27 | private long token;
28 |
29 | private bool IsHideCard
30 | {
31 | get => Provider.IsHideCard;
32 | set
33 | {
34 | if (Provider.IsHideCard != value)
35 | {
36 | Provider.IsHideCard = value;
37 | VisualStateManager.GoToState(this, value ? "HideCard" : "DisplayCard", true);
38 | }
39 | }
40 | }
41 |
42 | public MicaPage()
43 | {
44 | InitializeComponent();
45 | Provider = new BrushViewModel(Dispatcher) { SelectSource = MicaForUWP.Media.BackgroundSource.WallpaperBackdrop };
46 | }
47 |
48 | protected override void OnNavigatedTo(NavigationEventArgs e)
49 | {
50 | base.OnNavigatedTo(e);
51 | ThemeHelper.UISettingChanged += OnUISettingChanged;
52 | token = BackdropBrush.RegisterPropertyChangedCallback(BackdropMicaBrush.TintColorProperty, OnTintColorPropertyChanged);
53 | OnTintColorPropertyChanged(BackdropBrush, BackdropMicaBrush.TintColorProperty);
54 | VisualStateManager.GoToState(this, "DisplayCard", false);
55 | }
56 |
57 | protected override void OnNavigatedFrom(NavigationEventArgs e)
58 | {
59 | base.OnNavigatedFrom(e);
60 | ThemeHelper.UISettingChanged -= OnUISettingChanged;
61 | BackdropBrush.UnregisterPropertyChangedCallback(BackdropMicaBrush.TintColorProperty, token);
62 | }
63 |
64 | private void Page_Loaded(object sender, RoutedEventArgs e)
65 | {
66 | _ = ThemeHelper.GetRootThemeAsync().ContinueWith(x => ThemeHelper.IsDarkTheme(x.Result)).ContinueWith(x => isDark = x.Result);
67 | Provider.CompactOverlay = this.IsAppWindow() ? (ICompactOverlay)new AppWindowCompactOverlay(this.GetWindowForElement()) : new CoreWindowCompactOverlay();
68 | }
69 |
70 | private async void OnUISettingChanged(bool theme)
71 | {
72 | if (isDark != theme)
73 | {
74 | await Dispatcher.ResumeForegroundAsync();
75 | TintColor.Color = ReversalColor(TintColor.Color);
76 | isDark = theme;
77 | }
78 |
79 | Color ReversalColor(in Color color)
80 | {
81 | return Color.FromArgb(color.A, (byte)(255 - color.R), (byte)(255 - color.G), (byte)(255 - color.B));
82 | }
83 | }
84 |
85 | private void OnTintColorPropertyChanged(DependencyObject sender, DependencyProperty dp)
86 | {
87 | Color color = (Color)sender.GetValue(dp);
88 | bool isLight = color.IsColorLight();
89 | RequestedTheme = isLight ? ElementTheme.Light : ElementTheme.Dark;
90 | }
91 |
92 | private void TitleBar_BackRequested(object sender, RoutedEventArgs e)
93 | {
94 | if (Frame.CanGoBack) { Frame.GoBack(); }
95 | }
96 |
97 | private async void Button_Click(object sender, RoutedEventArgs e)
98 | {
99 | switch ((sender as FrameworkElement).Tag?.ToString())
100 | {
101 | case "NewWindow":
102 | _ = await WindowHelper.CreateWindowAsync(window =>
103 | {
104 | CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = true;
105 | Frame _frame = new Frame();
106 | window.Content = _frame;
107 | ThemeHelper.Initialize(window);
108 | _ = _frame.Navigate(typeof(MainPage), null, new DrillInNavigationTransitionInfo());
109 | });
110 | break;
111 | case "NewAppWindow" when WindowHelper.IsAppWindowSupported:
112 | Tuple appWindow = await WindowHelper.CreateWindowAsync();
113 | appWindow.Item1.TitleBar.ExtendsContentIntoTitleBar = true;
114 | ThemeHelper.Initialize(appWindow.Item1);
115 | appWindow.Item2.Navigate(typeof(MainPage), null, new DrillInNavigationTransitionInfo());
116 | await appWindow.Item1.TryShowAsync();
117 | break;
118 | case "ChangeTheme":
119 | _ = ThemeHelper.IsDarkThemeAsync().ContinueWith(x => ThemeHelper.SetRootThemeAsync(x.Result ? ElementTheme.Light : ElementTheme.Dark));
120 | break;
121 | case "ChangeImage":
122 | _ = Provider.PickImageAsync();
123 | return;
124 | case "RemoveImage":
125 | Provider.BackgroundImage = null;
126 | break;
127 | case "HideSetting":
128 | IsHideCard = true;
129 | break;
130 | case "ShowSetting":
131 | IsHideCard = false;
132 | break;
133 | default:
134 | break;
135 | }
136 | }
137 |
138 | private void Grid_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
139 | {
140 | if (e?.Handled == true) { return; }
141 | IsHideCard = !IsHideCard;
142 | if (e != null) { e.Handled = true; }
143 | }
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/MicaDemo/Common/WeakEvent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Reflection;
6 |
7 | namespace MicaDemo.Common
8 | {
9 | public class WeakEvent : IList>
10 | {
11 | private class Method : IEquatable, IEquatable>
12 | {
13 | private readonly bool _isStatic;
14 | private readonly WeakReference _reference;
15 | private readonly MethodInfo _method;
16 |
17 | public bool IsDead => !(_isStatic || _reference.IsAlive);
18 |
19 | public Method(Action callback)
20 | {
21 | _isStatic = callback.Target == null;
22 | _reference = new WeakReference(callback.Target);
23 | _method = callback.GetMethodInfo();
24 | }
25 |
26 | public void Invoke(TEventArgs arg)
27 | {
28 | if (!IsDead)
29 | {
30 | _method.Invoke(_reference.Target, new object[] { arg });
31 | }
32 | }
33 |
34 | public bool Equals(Method other) =>
35 | other != null
36 | && _reference.Target == other._reference.Target
37 | && _method == other._method;
38 |
39 | public bool Equals(Action callback) =>
40 | callback != null
41 | && _reference.Target == callback.Target
42 | && _method == callback.GetMethodInfo();
43 |
44 | public override bool Equals(object obj)
45 | {
46 | switch (obj)
47 | {
48 | case Method other:
49 | return Equals(other);
50 | case Action callback:
51 | return Equals(callback);
52 | default:
53 | return false;
54 | }
55 | }
56 |
57 | public override int GetHashCode() => new Tuple(_reference, _method).GetHashCode();
58 |
59 | public static implicit operator Method(Action callback) => new Method(callback);
60 |
61 | public static explicit operator Action(Method method) => method.IsDead ? null : method._method.CreateDelegate(typeof(Action), method._reference.Target) as Action;
62 | }
63 |
64 | private readonly List _list;
65 |
66 | public WeakEvent() => _list = new List();
67 |
68 | public WeakEvent(IEnumerable> collection) => _list = new List(collection.Select, Method>(x => x));
69 |
70 | public WeakEvent(int capacity) => _list = new List(capacity);
71 |
72 | public int Count => _list.Count;
73 |
74 | public bool IsReadOnly => ((ICollection)_list).IsReadOnly;
75 |
76 | public Action this[int index]
77 | {
78 | get => (Action)_list[index];
79 | set => _list[index] = value;
80 | }
81 |
82 | public void Invoke(TEventArgs arg)
83 | {
84 | for (int i = _list.Count; --i >= 0;)
85 | {
86 | if (_list[i].IsDead)
87 | {
88 | _list.RemoveAt(i);
89 | }
90 | else
91 | {
92 | _list[i].Invoke(arg);
93 | }
94 | }
95 | }
96 |
97 | public void Add(Action callback) => _list.Add(callback);
98 |
99 | public void AddRange(IEnumerable> collection) => _list.AddRange(collection.Select, Method>(x => x));
100 |
101 | public void Insert(int index, Action item) => _list.Insert(index, item);
102 |
103 | public void CopyTo(Action[] array, int arrayIndex) => Array.Copy(_list.Select(x => (Action)x).ToArray(), 0, array, arrayIndex, _list.Count);
104 |
105 | public void Remove(Action callback)
106 | {
107 | for (int i = _list.Count; --i >= 0;)
108 | {
109 | if (_list[i].IsDead)
110 | {
111 | _list.RemoveAt(i);
112 | }
113 | else if (_list[i].Equals(callback))
114 | {
115 | _list.RemoveAt(i);
116 | }
117 | }
118 | }
119 |
120 | bool ICollection>.Remove(Action callback)
121 | {
122 | for (int i = _list.Count; --i >= 0;)
123 | {
124 | if (_list[i].IsDead)
125 | {
126 | _list.RemoveAt(i);
127 | }
128 | else if (_list[i].Equals(callback))
129 | {
130 | _list.RemoveAt(i);
131 | return true;
132 | }
133 | }
134 | return false;
135 | }
136 |
137 | public void RemoveAt(int index) => _list.RemoveAt(index);
138 |
139 | public int RemoveAll(Predicate> predicate) => _list.RemoveAll(x => predicate((Action)x));
140 |
141 | public void Clear() => _list.Clear();
142 |
143 | public bool Contains(Action callback)
144 | {
145 | for (int i = _list.Count; --i >= 0;)
146 | {
147 | if (_list[i].IsDead)
148 | {
149 | _list.RemoveAt(i);
150 | }
151 | else if (_list[i].Equals(callback))
152 | {
153 | return true;
154 | }
155 | }
156 | return false;
157 | }
158 |
159 | public int IndexOf(Action callback)
160 | {
161 | for (int i = _list.Count; --i >= 0;)
162 | {
163 | if (_list[i].IsDead)
164 | {
165 | _list.RemoveAt(i);
166 | }
167 | else if (_list[i].Equals(callback))
168 | {
169 | return i;
170 | }
171 | }
172 | return -1;
173 | }
174 |
175 | public IEnumerator> GetEnumerator() => _list.Select(x => (Action)x).GetEnumerator();
176 |
177 | IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
178 |
179 | public static WeakEvent operator +(WeakEvent weakEvent, Action callback)
180 | {
181 | weakEvent.Add(callback);
182 | return weakEvent;
183 | }
184 |
185 | public static WeakEvent operator -(WeakEvent weakEvent, Action callback)
186 | {
187 | weakEvent.Remove(callback);
188 | return weakEvent;
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/MicaDemo/Common/ExceptionHandling.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using Windows.UI.Xaml.Controls;
4 |
5 | namespace MicaDemo.Common
6 | {
7 | ///
8 | /// Wrapper around a standard synchronization context, that catches any unhandled exceptions.
9 | /// Acts as a facade passing calls to the original SynchronizationContext.
10 | ///
11 | ///
12 | /// Set this up inside your App.xaml.cs file as follows:
13 | ///
14 | /// protected override void OnActivated(IActivatedEventArgs args)
15 | /// {
16 | /// EnsureSyncContext();
17 | /// ...
18 | /// }
19 | ///
20 | /// protected override void OnLaunched(LaunchActivatedEventArgs args)
21 | /// {
22 | /// EnsureSyncContext();
23 | /// ...
24 | /// }
25 | ///
26 | /// private void EnsureSyncContext()
27 | /// {
28 | /// var exceptionHandlingSynchronizationContext = ExceptionHandlingSynchronizationContext.Register();
29 | /// exceptionHandlingSynchronizationContext.UnhandledException += OnSynchronizationContextUnhandledException;
30 | /// }
31 | ///
32 | /// private void OnSynchronizationContextUnhandledException(object sender, UnhandledExceptionEventArgs args)
33 | /// {
34 | /// args.Handled = true;
35 | /// }
36 | ///
37 | ///
38 | public class ExceptionHandlingSynchronizationContext : SynchronizationContext
39 | {
40 | ///
41 | /// Registration method. Call this from OnLaunched and OnActivated inside the App.xaml.cs.
42 | ///
43 | /// The which registered.
44 | public static ExceptionHandlingSynchronizationContext Register()
45 | {
46 | SynchronizationContext syncContext = Current ?? throw new InvalidOperationException("Ensure a synchronization context exists before calling this method.");
47 |
48 | if (!(syncContext is ExceptionHandlingSynchronizationContext customSynchronizationContext))
49 | {
50 | customSynchronizationContext = new ExceptionHandlingSynchronizationContext(syncContext);
51 | SetSynchronizationContext(customSynchronizationContext);
52 | }
53 |
54 | return customSynchronizationContext;
55 | }
56 |
57 | ///
58 | /// Registration method with an event handler for unhandled exceptions.
59 | /// Call this from OnLaunched and OnActivated inside the App.xaml.cs.
60 | ///
61 | /// The which registered.
62 | /// Register handler only when synchronization context is not already registered.
63 | public static ExceptionHandlingSynchronizationContext RegisterForFrame(Frame rootFrame)
64 | {
65 | if (rootFrame == null) { throw new ArgumentNullException(nameof(rootFrame)); }
66 |
67 | ExceptionHandlingSynchronizationContext synchronizationContext = Register();
68 |
69 | rootFrame.Navigating += (sender, args) => EnsureContext(synchronizationContext);
70 | rootFrame.Loaded += (sender, args) => EnsureContext(synchronizationContext);
71 |
72 | return synchronizationContext;
73 | }
74 |
75 | ///
76 | /// Ensures that the specified synchronization context is the current one.
77 | ///
78 | /// The to ensure.
79 | private static void EnsureContext(SynchronizationContext context)
80 | {
81 | if (Current != context) { SetSynchronizationContext(context); }
82 | }
83 |
84 | ///
85 | /// The to wrap.
86 | ///
87 | private readonly SynchronizationContext _syncContext;
88 |
89 | ///
90 | /// Initializes a new instance of the class.
91 | ///
92 | /// The to wrap.
93 | public ExceptionHandlingSynchronizationContext(SynchronizationContext syncContext) => _syncContext = syncContext;
94 |
95 | ///
96 | public override SynchronizationContext CreateCopy() => new ExceptionHandlingSynchronizationContext(_syncContext.CreateCopy());
97 |
98 | ///
99 | public override void OperationCompleted() => _syncContext.OperationCompleted();
100 |
101 | ///
102 | public override void OperationStarted() => _syncContext.OperationStarted();
103 |
104 | ///
105 | public override void Post(SendOrPostCallback d, object state) => _syncContext.Post(WrapCallback(d), state);
106 |
107 | ///
108 | public override void Send(SendOrPostCallback d, object state) => _syncContext.Send(d, state);
109 |
110 | ///
111 | /// Pack the callback in a try-catch block to catch any unhandled exceptions.
112 | ///
113 | /// The callback to wrap.
114 | /// The wrapped callback.
115 | private SendOrPostCallback WrapCallback(SendOrPostCallback sendOrPostCallback) =>
116 | state =>
117 | {
118 | try
119 | {
120 | sendOrPostCallback(state);
121 | }
122 | catch (Exception ex)
123 | {
124 | if (!HandleException(ex)) { throw; }
125 | }
126 | };
127 |
128 | ///
129 | /// Handles the exception by raising the UnhandledException event.
130 | ///
131 | /// The exception to handle.
132 | /// if the exception was handled; otherwise, .
133 | private bool HandleException(Exception exception)
134 | {
135 | if (UnhandledException == null) { return false; }
136 |
137 | UnhandledExceptionEventArgs exWrapper = new UnhandledExceptionEventArgs(exception);
138 |
139 | UnhandledException(this, exWrapper);
140 |
141 | #if DEBUG && !DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION
142 | if (System.Diagnostics.Debugger.IsAttached) { System.Diagnostics.Debugger.Break(); }
143 | #endif
144 |
145 | return exWrapper.Handled;
146 | }
147 |
148 |
149 | ///
150 | /// Listen to this event to catch any unhandled exceptions and allow for handling them
151 | /// so they don't crash your application.
152 | ///
153 | public event EventHandler UnhandledException;
154 | }
155 |
156 | ///
157 | /// Provides data for the UnhandledException event.
158 | ///
159 | public class UnhandledExceptionEventArgs : EventArgs
160 | {
161 | ///
162 | /// Initializes a new instance of the class.
163 | ///
164 | /// The exception that was not handled.
165 | public UnhandledExceptionEventArgs(Exception exception) => Exception = exception;
166 |
167 | ///
168 | /// Gets or sets a value that indicates whether the exception is handled.
169 | ///
170 | /// to mark the exception as handled, which indicates that the event system should not process it further; otherwise, .
171 | public bool Handled { get; set; }
172 |
173 | ///
174 | /// Gets the HRESULT code associated with the unhandled exception.
175 | ///
176 | /// The HRESULT code (for Visual C++ component extensions (C++/CX)), or a mapped common language runtime (CLR) .
177 | public Exception Exception { get; }
178 |
179 | ///
180 | /// Gets the message string as passed by the originating unhandled exception.
181 | ///
182 | /// The message string, which may be useful for debugging.
183 | public string Message => Exception?.Message;
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | # but not Directory.Build.rsp, as it configures directory-level build defaults
86 | !Directory.Build.rsp
87 | *.sbr
88 | *.tlb
89 | *.tli
90 | *.tlh
91 | *.tmp
92 | *.tmp_proj
93 | *_wpftmp.csproj
94 | *.log
95 | *.tlog
96 | *.vspscc
97 | *.vssscc
98 | .builds
99 | *.pidb
100 | *.svclog
101 | *.scc
102 |
103 | # Chutzpah Test files
104 | _Chutzpah*
105 |
106 | # Visual C++ cache files
107 | ipch/
108 | *.aps
109 | *.ncb
110 | *.opendb
111 | *.opensdf
112 | *.sdf
113 | *.cachefile
114 | *.VC.db
115 | *.VC.VC.opendb
116 |
117 | # Visual Studio profiler
118 | *.psess
119 | *.vsp
120 | *.vspx
121 | *.sap
122 |
123 | # Visual Studio Trace Files
124 | *.e2e
125 |
126 | # TFS 2012 Local Workspace
127 | $tf/
128 |
129 | # Guidance Automation Toolkit
130 | *.gpState
131 |
132 | # ReSharper is a .NET coding add-in
133 | _ReSharper*/
134 | *.[Rr]e[Ss]harper
135 | *.DotSettings.user
136 |
137 | # TeamCity is a build add-in
138 | _TeamCity*
139 |
140 | # DotCover is a Code Coverage Tool
141 | *.dotCover
142 |
143 | # AxoCover is a Code Coverage Tool
144 | .axoCover/*
145 | !.axoCover/settings.json
146 |
147 | # Coverlet is a free, cross platform Code Coverage Tool
148 | coverage*.json
149 | coverage*.xml
150 | coverage*.info
151 |
152 | # Visual Studio code coverage results
153 | *.coverage
154 | *.coveragexml
155 |
156 | # NCrunch
157 | _NCrunch_*
158 | .*crunch*.local.xml
159 | nCrunchTemp_*
160 |
161 | # MightyMoose
162 | *.mm.*
163 | AutoTest.Net/
164 |
165 | # Web workbench (sass)
166 | .sass-cache/
167 |
168 | # Installshield output folder
169 | [Ee]xpress/
170 |
171 | # DocProject is a documentation generator add-in
172 | DocProject/buildhelp/
173 | DocProject/Help/*.HxT
174 | DocProject/Help/*.HxC
175 | DocProject/Help/*.hhc
176 | DocProject/Help/*.hhk
177 | DocProject/Help/*.hhp
178 | DocProject/Help/Html2
179 | DocProject/Help/html
180 |
181 | # Click-Once directory
182 | publish/
183 |
184 | # Publish Web Output
185 | *.[Pp]ublish.xml
186 | *.azurePubxml
187 | # Note: Comment the next line if you want to checkin your web deploy settings,
188 | # but database connection strings (with potential passwords) will be unencrypted
189 | *.pubxml
190 | *.publishproj
191 |
192 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
193 | # checkin your Azure Web App publish settings, but sensitive information contained
194 | # in these scripts will be unencrypted
195 | PublishScripts/
196 |
197 | # NuGet Packages
198 | *.nupkg
199 | # NuGet Symbol Packages
200 | *.snupkg
201 | # The packages folder can be ignored because of Package Restore
202 | **/[Pp]ackages/*
203 | # except build/, which is used as an MSBuild target.
204 | !**/[Pp]ackages/build/
205 | # Uncomment if necessary however generally it will be regenerated when needed
206 | #!**/[Pp]ackages/repositories.config
207 | # NuGet v3's project.json files produces more ignorable files
208 | *.nuget.props
209 | *.nuget.targets
210 |
211 | # Microsoft Azure Build Output
212 | csx/
213 | *.build.csdef
214 |
215 | # Microsoft Azure Emulator
216 | ecf/
217 | rcf/
218 |
219 | # Windows Store app package directories and files
220 | AppPackages/
221 | BundleArtifacts/
222 | Package.StoreAssociation.xml
223 | _pkginfo.txt
224 | *.appx
225 | *.appxbundle
226 | *.appxupload
227 |
228 | # Visual Studio cache files
229 | # files ending in .cache can be ignored
230 | *.[Cc]ache
231 | # but keep track of directories ending in .cache
232 | !?*.[Cc]ache/
233 |
234 | # Others
235 | ClientBin/
236 | ~$*
237 | *~
238 | *.dbmdl
239 | *.dbproj.schemaview
240 | *.jfm
241 | *.pfx
242 | *.publishsettings
243 | orleans.codegen.cs
244 |
245 | # Including strong name files can present a security risk
246 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
247 | #*.snk
248 |
249 | # Since there are multiple workflows, uncomment next line to ignore bower_components
250 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
251 | #bower_components/
252 |
253 | # RIA/Silverlight projects
254 | Generated_Code/
255 |
256 | # Backup & report files from converting an old project file
257 | # to a newer Visual Studio version. Backup files are not needed,
258 | # because we have git ;-)
259 | _UpgradeReport_Files/
260 | Backup*/
261 | UpgradeLog*.XML
262 | UpgradeLog*.htm
263 | ServiceFabricBackup/
264 | *.rptproj.bak
265 |
266 | # SQL Server files
267 | *.mdf
268 | *.ldf
269 | *.ndf
270 |
271 | # Business Intelligence projects
272 | *.rdl.data
273 | *.bim.layout
274 | *.bim_*.settings
275 | *.rptproj.rsuser
276 | *- [Bb]ackup.rdl
277 | *- [Bb]ackup ([0-9]).rdl
278 | *- [Bb]ackup ([0-9][0-9]).rdl
279 |
280 | # Microsoft Fakes
281 | FakesAssemblies/
282 |
283 | # GhostDoc plugin setting file
284 | *.GhostDoc.xml
285 |
286 | # Node.js Tools for Visual Studio
287 | .ntvs_analysis.dat
288 | node_modules/
289 |
290 | # Visual Studio 6 build log
291 | *.plg
292 |
293 | # Visual Studio 6 workspace options file
294 | *.opt
295 |
296 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
297 | *.vbw
298 |
299 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
300 | *.vbp
301 |
302 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
303 | *.dsw
304 | *.dsp
305 |
306 | # Visual Studio 6 technical files
307 | *.ncb
308 | *.aps
309 |
310 | # Visual Studio LightSwitch build output
311 | **/*.HTMLClient/GeneratedArtifacts
312 | **/*.DesktopClient/GeneratedArtifacts
313 | **/*.DesktopClient/ModelManifest.xml
314 | **/*.Server/GeneratedArtifacts
315 | **/*.Server/ModelManifest.xml
316 | _Pvt_Extensions
317 |
318 | # Paket dependency manager
319 | .paket/paket.exe
320 | paket-files/
321 |
322 | # FAKE - F# Make
323 | .fake/
324 |
325 | # CodeRush personal settings
326 | .cr/personal
327 |
328 | # Python Tools for Visual Studio (PTVS)
329 | __pycache__/
330 | *.pyc
331 |
332 | # Cake - Uncomment if you are using it
333 | # tools/**
334 | # !tools/packages.config
335 |
336 | # Tabs Studio
337 | *.tss
338 |
339 | # Telerik's JustMock configuration file
340 | *.jmconfig
341 |
342 | # BizTalk build output
343 | *.btp.cs
344 | *.btm.cs
345 | *.odx.cs
346 | *.xsd.cs
347 |
348 | # OpenCover UI analysis results
349 | OpenCover/
350 |
351 | # Azure Stream Analytics local run output
352 | ASALocalRun/
353 |
354 | # MSBuild Binary and Structured Log
355 | *.binlog
356 |
357 | # NVidia Nsight GPU debugger configuration file
358 | *.nvuser
359 |
360 | # MFractors (Xamarin productivity tool) working folder
361 | .mfractor/
362 |
363 | # Local History for Visual Studio
364 | .localhistory/
365 |
366 | # Visual Studio History (VSHistory) files
367 | .vshistory/
368 |
369 | # BeatPulse healthcheck temp database
370 | healthchecksdb
371 |
372 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
373 | MigrationBackup/
374 |
375 | # Ionide (cross platform F# VS Code tools) working folder
376 | .ionide/
377 |
378 | # Fody - auto-generated XML schema
379 | FodyWeavers.xsd
380 |
381 | # VS Code files for those working on multiple tools
382 | .vscode/*
383 | !.vscode/settings.json
384 | !.vscode/tasks.json
385 | !.vscode/launch.json
386 | !.vscode/extensions.json
387 | *.code-workspace
388 |
389 | # Local History for Visual Studio Code
390 | .history/
391 |
392 | # Windows Installer files from build outputs
393 | *.cab
394 | *.msi
395 | *.msix
396 | *.msm
397 | *.msp
398 |
399 | # JetBrains Rider
400 | *.sln.iml
--------------------------------------------------------------------------------
/MicaDemo/Helpers/UIElementHelper.cs:
--------------------------------------------------------------------------------
1 | using Windows.Foundation.Metadata;
2 | using Windows.System;
3 | using Windows.UI.Xaml;
4 | using Windows.UI.Xaml.Controls;
5 | using Windows.UI.Xaml.Controls.Primitives;
6 | using Windows.UI.Xaml.Input;
7 |
8 | namespace MicaDemo.Helpers
9 | {
10 | public static class UIElementHelper
11 | {
12 | #region ContextFlyout
13 |
14 | ///
15 | /// Gets the flyout associated with this element.
16 | ///
17 | /// The element from which to read the property value.
18 | /// The flyout associated with this element, if any; otherwise, . The default is .
19 | public static FlyoutBase GetContextFlyout(UIElement element)
20 | {
21 | return (FlyoutBase)element.GetValue(ContextFlyoutProperty);
22 | }
23 |
24 | ///
25 | /// Sets the flyout associated with this element.
26 | ///
27 | /// The element on which to set the attached property.
28 | /// The flyout associated with this element.
29 | public static void SetContextFlyout(UIElement element, FlyoutBase value)
30 | {
31 | element.SetValue(ContextFlyoutProperty, value);
32 | }
33 |
34 | ///
35 | /// Identifies the ContextFlyout dependency property.
36 | ///
37 | public static readonly DependencyProperty ContextFlyoutProperty =
38 | DependencyProperty.RegisterAttached(
39 | "ContextFlyout",
40 | typeof(FlyoutBase),
41 | typeof(UIElementHelper),
42 | new PropertyMetadata(null, OnContextFlyoutChanged));
43 |
44 | private static void OnContextFlyoutChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
45 | {
46 | UIElement element = (UIElement)d;
47 | if (ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "ContextFlyout"))
48 | {
49 | element.ContextFlyout = e.NewValue as FlyoutBase;
50 | }
51 | else if (element is FrameworkElement frameworkElement)
52 | {
53 | FlyoutBase.SetAttachedFlyout(frameworkElement, e.NewValue as FlyoutBase);
54 |
55 | element.KeyDown -= OnKeyDown;
56 | element.Holding -= OnHolding;
57 | element.RightTapped -= OnRightTapped;
58 |
59 | if (element != null)
60 | {
61 | element.KeyDown += OnKeyDown;
62 | element.Holding += OnHolding;
63 | element.RightTapped += OnRightTapped;
64 | }
65 | }
66 | }
67 |
68 | private static void OnKeyDown(object sender, KeyRoutedEventArgs e)
69 | {
70 | if (e?.Handled == true) { return; }
71 | if (e.Key == VirtualKey.Menu)
72 | {
73 | FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
74 | if (e != null) { e.Handled = true; }
75 | }
76 | }
77 |
78 | private static void OnHolding(object sender, HoldingRoutedEventArgs e)
79 | {
80 | if (e?.Handled == true || !(sender is FrameworkElement element)) { return; }
81 | FlyoutBase flyout = FlyoutBase.GetAttachedFlyout(element);
82 | if (flyout is MenuFlyout menu)
83 | {
84 | menu.ShowAt(element, e.GetPosition(element));
85 | }
86 | else
87 | {
88 | FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
89 | }
90 | if (e != null) { e.Handled = true; }
91 | }
92 |
93 | private static void OnRightTapped(object sender, RightTappedRoutedEventArgs e)
94 | {
95 | if (e?.Handled == true || !(sender is FrameworkElement element)) { return; }
96 | FlyoutBase flyout = FlyoutBase.GetAttachedFlyout(element);
97 | if (flyout is MenuFlyout menu)
98 | {
99 | menu.ShowAt(element, e.GetPosition(element));
100 | }
101 | else
102 | {
103 | FlyoutBase.ShowAttachedFlyout(sender as FrameworkElement);
104 | }
105 | if (e != null) { e.Handled = true; }
106 | }
107 |
108 | #endregion
109 |
110 | #region Icon
111 |
112 | ///
113 | /// Gets the graphic content of the menu flyout item.
114 | ///
115 | /// The element from which to read the property value.
116 | /// The graphic content of the menu flyout item.
117 | public static IconElement GetIcon(MenuFlyoutItemBase control)
118 | {
119 | return (IconElement)control.GetValue(IconProperty);
120 | }
121 |
122 | ///
123 | /// Sets the graphic content of the menu flyout item.
124 | ///
125 | /// The element on which to set the attached property.
126 | /// The property value to set.
127 | public static void SetIcon(MenuFlyoutItemBase control, IconElement value)
128 | {
129 | control.SetValue(IconProperty, value);
130 | }
131 |
132 | ///
133 | /// Identifies the Icon dependency property.
134 | ///
135 | public static readonly DependencyProperty IconProperty =
136 | DependencyProperty.RegisterAttached(
137 | "Icon",
138 | typeof(IconElement),
139 | typeof(UIElementHelper),
140 | new PropertyMetadata(null, OnIconChanged));
141 |
142 | private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
143 | {
144 | if (d is MenuFlyoutItem item)
145 | {
146 | if (ApiInformation.IsPropertyPresent("Windows.UI.Xaml.Controls.MenuFlyoutItem", "Icon"))
147 | {
148 | item.Icon = e.NewValue as IconElement;
149 | }
150 | }
151 | else if (d is MenuFlyoutSubItem subitem)
152 | {
153 | if (ApiInformation.IsPropertyPresent("Windows.UI.Xaml.Controls.MenuFlyoutSubItem", "Icon"))
154 | {
155 | subitem.Icon = e.NewValue as IconElement;
156 | }
157 | }
158 | else if (d is ToggleMenuFlyoutItem toggle)
159 | {
160 | if (ApiInformation.IsPropertyPresent("Windows.UI.Xaml.Controls.ToggleMenuFlyoutItem", "Icon"))
161 | {
162 | toggle.Icon = e.NewValue as IconElement;
163 | }
164 | }
165 | }
166 |
167 | #endregion
168 |
169 | #region BackgroundTransition
170 |
171 | ///
172 | /// Gets an instance of BrushTransition to automatically animate changes to the Background property.
173 | ///
174 | /// The element from which to read the property value.
175 | /// An instance of BrushTransition to automatically animate changes to the Background; otherwise, . The default is .
176 | public static bool GetBackgroundTransition(UIElement element)
177 | {
178 | return (bool)element.GetValue(BackgroundTransitionProperty);
179 | }
180 |
181 | ///
182 | /// Sets an instance of BrushTransition to automatically animate changes to the Background property.
183 | ///
184 | /// The element on which to set the attached property.
185 | /// The instance of BrushTransition to automatically animate changes to the Background property.
186 | public static void SetBackgroundTransition(UIElement element, bool value)
187 | {
188 | element.SetValue(BackgroundTransitionProperty, value);
189 | }
190 |
191 | ///
192 | /// Identifies the BackgroundTransition dependency property.
193 | ///
194 | public static readonly DependencyProperty BackgroundTransitionProperty =
195 | DependencyProperty.RegisterAttached(
196 | "BackgroundTransition",
197 | typeof(bool),
198 | typeof(UIElementHelper),
199 | new PropertyMetadata(false, OnBackgroundTransitionChanged));
200 |
201 | private static void OnBackgroundTransitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
202 | {
203 | if (ApiInformation.IsTypePresent("Windows.UI.Xaml.BrushTransition"))
204 | {
205 | switch (d)
206 | {
207 | case Panel panel:
208 | panel.BackgroundTransition = e.NewValue is true ? new BrushTransition() : null;
209 | break;
210 | case Border border:
211 | border.BackgroundTransition = e.NewValue is true ? new BrushTransition() : null;
212 | break;
213 | case ContentPresenter contentPresenter:
214 | contentPresenter.BackgroundTransition = e.NewValue is true ? new BrushTransition() : null;
215 | break;
216 | }
217 | }
218 | }
219 |
220 | #endregion
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/MicaDemo/ViewModels/BrushViewModel.cs:
--------------------------------------------------------------------------------
1 | using MicaDemo.Common;
2 | using MicaDemo.Helpers;
3 | using MicaForUWP.Media;
4 | using System;
5 | using System.ComponentModel;
6 | using System.Linq;
7 | using System.Runtime.CompilerServices;
8 | using System.Threading.Tasks;
9 | using Windows.Foundation.Metadata;
10 | using Windows.Graphics.Imaging;
11 | using Windows.Storage;
12 | using Windows.Storage.Pickers;
13 | using Windows.Storage.Streams;
14 | using Windows.UI.Core;
15 | using Windows.UI.ViewManagement;
16 | using Windows.UI.WindowManagement;
17 | using Windows.UI.Xaml;
18 | using Windows.UI.Xaml.Media;
19 | using Windows.UI.Xaml.Media.Imaging;
20 |
21 | namespace MicaDemo.ViewModels
22 | {
23 | public class BrushViewModel : INotifyPropertyChanged
24 | {
25 | private static readonly string[] imageTypes = new[] { ".jpg", ".jpeg", ".png", ".bmp", ".tiff", ".tif", ".heif", ".heic" };
26 |
27 | public Thickness ScrollViewerMargin { get; } = UIHelper.ScrollViewerMargin;
28 | public Array BackgroundSources { get; } = Enum.GetValues(typeof(BackgroundSource)).OfType().Where(x => ApiInformation.IsEnumNamedValuePresent("MicaForUWP.Media", x.ToString())).ToArray();
29 | public bool IsAppWindowSupported { get; } = WindowHelper.IsAppWindowSupported;
30 |
31 | public CoreDispatcher Dispatcher { get; }
32 |
33 | private ICompactOverlay compactOverlay;
34 | public ICompactOverlay CompactOverlay
35 | {
36 | get => compactOverlay;
37 | set
38 | {
39 | if (compactOverlay != value)
40 | {
41 | compactOverlay = value;
42 | RaisePropertyChangedEvent(nameof(IsSupportCompactOverlay), nameof(IsCompactOverlay));
43 | }
44 | }
45 | }
46 |
47 | public bool IsSupportCompactOverlay => CompactOverlay?.IsSupportCompactOverlay == true;
48 |
49 | public bool IsCompactOverlay
50 | {
51 | get => IsSupportCompactOverlay && CompactOverlay?.IsCompactOverlay == true;
52 | set
53 | {
54 | if (IsSupportCompactOverlay)
55 | {
56 | if (value)
57 | {
58 | CompactOverlay?.EnterCompactOverlay();
59 | }
60 | else
61 | {
62 | CompactOverlay?.ExitCompactOverlay();
63 | }
64 | RaisePropertyChangedEvent();
65 | }
66 | }
67 | }
68 |
69 | private int selectIndex;
70 | public int SelectIndex
71 | {
72 | get => selectIndex;
73 | set
74 | {
75 | if (selectIndex != value)
76 | {
77 | selectIndex = value;
78 | RaisePropertyChangedEvent(nameof(SelectIndex), nameof(SelectSource));
79 | }
80 | }
81 | }
82 |
83 | public BackgroundSource SelectSource
84 | {
85 | get => (BackgroundSource)selectIndex;
86 | set
87 | {
88 | int index = (int)value;
89 | if (selectIndex != index)
90 | {
91 | selectIndex = index;
92 | RaisePropertyChangedEvent(nameof(SelectIndex), nameof(SelectSource));
93 | }
94 | }
95 | }
96 |
97 | private ImageSource image;
98 | public ImageSource BackgroundImage
99 | {
100 | get => image;
101 | set
102 | {
103 | SetProperty(ref image, value);
104 | }
105 | }
106 |
107 | private bool isHideCard = false;
108 | public bool IsHideCard
109 | {
110 | get => isHideCard;
111 | set
112 | {
113 | SetProperty(ref isHideCard, value);
114 | }
115 | }
116 |
117 | public event PropertyChangedEventHandler PropertyChanged;
118 |
119 | protected async void RaisePropertyChangedEvent([CallerMemberName] string name = null)
120 | {
121 | if (name != null)
122 | {
123 | await Dispatcher.ResumeForegroundAsync();
124 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
125 | }
126 | }
127 |
128 | protected async void RaisePropertyChangedEvent(params string[] names)
129 | {
130 | if (names != null)
131 | {
132 | await Dispatcher.ResumeForegroundAsync();
133 | names.ForEach(name => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)));
134 | }
135 | }
136 |
137 | protected void SetProperty(ref TProperty property, TProperty value, [CallerMemberName] string name = null)
138 | {
139 | if (property == null ? value != null : !property.Equals(value))
140 | {
141 | property = value;
142 | RaisePropertyChangedEvent(name);
143 | }
144 | }
145 |
146 | public BrushViewModel(CoreDispatcher dispatcher)
147 | {
148 | Dispatcher = dispatcher;
149 | BackgroundImage = new BitmapImage(new Uri("ms-appx:///Assets/Photos/BigFourSummerHeat.jpg"));
150 | }
151 |
152 | public async Task PickImageAsync()
153 | {
154 | FileOpenPicker fileOpen = new FileOpenPicker();
155 | fileOpen.FileTypeFilter.AddRange(imageTypes);
156 | fileOpen.SuggestedStartLocation = PickerLocationId.ComputerFolder;
157 |
158 | StorageFile file = await fileOpen.PickSingleFileAsync();
159 | if (file != null)
160 | {
161 | using (IRandomAccessStreamWithContentType stream = await file.OpenReadAsync())
162 | {
163 | BitmapDecoder imageDecoder = await BitmapDecoder.CreateAsync(stream);
164 | SoftwareBitmap softwareImage = await imageDecoder.GetSoftwareBitmapAsync();
165 | try
166 | {
167 | WriteableBitmap writeableImage = new WriteableBitmap((int)imageDecoder.PixelWidth, (int)imageDecoder.PixelHeight);
168 | await writeableImage.SetSourceAsync(stream);
169 | BackgroundImage = writeableImage;
170 | }
171 | catch
172 | {
173 | try
174 | {
175 | using (InMemoryRandomAccessStream random = new InMemoryRandomAccessStream())
176 | {
177 | BitmapEncoder encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, random);
178 | encoder.SetSoftwareBitmap(softwareImage);
179 | await encoder.FlushAsync();
180 | WriteableBitmap writeableImage = new WriteableBitmap((int)imageDecoder.PixelWidth, (int)imageDecoder.PixelHeight);
181 | await writeableImage.SetSourceAsync(random);
182 | BackgroundImage = writeableImage;
183 | }
184 | }
185 | catch
186 | {
187 | BackgroundImage = null;
188 | }
189 | }
190 | }
191 | }
192 | }
193 | }
194 |
195 | public interface ICompactOverlay
196 | {
197 | bool IsSupportCompactOverlay { get; }
198 | bool IsCompactOverlay { get; }
199 | void EnterCompactOverlay();
200 | void ExitCompactOverlay();
201 | }
202 |
203 | public class CoreWindowCompactOverlay : ICompactOverlay
204 | {
205 | private static readonly bool isSupportCompactOverlay = ApiInformation.IsMethodPresent("Windows.UI.ViewManagement.ApplicationView", "IsViewModeSupported");
206 | private readonly ApplicationView view = ApplicationView.GetForCurrentView();
207 |
208 | public bool IsSupportCompactOverlay => isSupportCompactOverlay && view.IsViewModeSupported(ApplicationViewMode.CompactOverlay);
209 |
210 | public bool IsCompactOverlay =>
211 | IsSupportCompactOverlay && view.ViewMode == ApplicationViewMode.CompactOverlay;
212 |
213 | public void EnterCompactOverlay()
214 | {
215 | if (view.IsViewModeSupported(ApplicationViewMode.CompactOverlay))
216 | {
217 | _ = view.TryEnterViewModeAsync(ApplicationViewMode.CompactOverlay);
218 | }
219 | }
220 |
221 | public void ExitCompactOverlay()
222 | {
223 | if (view.IsViewModeSupported(ApplicationViewMode.Default))
224 | {
225 | _ = view.TryEnterViewModeAsync(ApplicationViewMode.Default);
226 | }
227 | }
228 | }
229 |
230 | public class AppWindowCompactOverlay : ICompactOverlay
231 | {
232 | private static readonly bool isSupportCompactOverlay = ApiInformation.IsMethodPresent("Windows.UI.WindowManagement.AppWindowPresenter", "IsPresentationSupported");
233 | private readonly AppWindow window;
234 |
235 | public AppWindowCompactOverlay(AppWindow window) => this.window = window;
236 |
237 | public bool IsSupportCompactOverlay => isSupportCompactOverlay && window.Presenter.IsPresentationSupported(AppWindowPresentationKind.CompactOverlay);
238 |
239 | public bool IsCompactOverlay =>
240 | IsSupportCompactOverlay && window.Presenter.GetConfiguration().Kind == AppWindowPresentationKind.CompactOverlay;
241 |
242 | public void EnterCompactOverlay()
243 | {
244 | if (window.Presenter.IsPresentationSupported(AppWindowPresentationKind.CompactOverlay))
245 | {
246 | _ = window.Presenter.RequestPresentation(AppWindowPresentationKind.CompactOverlay);
247 | }
248 | }
249 |
250 | public void ExitCompactOverlay()
251 | {
252 | if (window.Presenter.IsPresentationSupported(AppWindowPresentationKind.CompactOverlay))
253 | {
254 | _ = window.Presenter.RequestPresentation(AppWindowPresentationKind.Default);
255 | }
256 | }
257 | }
258 | }
259 |
--------------------------------------------------------------------------------
/MicaDemo/Common/ThreadSwitcher.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Runtime.CompilerServices;
4 | using System.Threading;
5 | using Windows.Foundation.Metadata;
6 | using Windows.System;
7 | using Windows.System.Threading;
8 | using Windows.UI.Core;
9 | using ThreadPool = Windows.System.Threading.ThreadPool;
10 |
11 | namespace MicaDemo.Common
12 | {
13 | ///
14 | /// The interface of helper type for switch thread.
15 | ///
16 | public interface IThreadSwitcher : INotifyCompletion
17 | {
18 | ///
19 | /// Gets a value that indicates whether the asynchronous operation has completed.
20 | ///
21 | bool IsCompleted { get; }
22 |
23 | ///
24 | /// Ends the await on the completed task.
25 | ///
26 | void GetResult();
27 |
28 | ///
29 | /// Gets an awaiter used to await this .
30 | ///
31 | /// An awaiter instance.
32 | IThreadSwitcher GetAwaiter();
33 | }
34 |
35 | ///
36 | /// The interface of helper type for switch thread.
37 | ///
38 | /// The type of the result of .
39 | public interface IThreadSwitcher : IThreadSwitcher
40 | {
41 | ///
42 | /// Gets an awaiter used to await .
43 | ///
44 | /// A awaiter instance.
45 | new T GetAwaiter();
46 | }
47 |
48 | ///
49 | /// A helper type for switch thread by . This type is not intended to be used directly from your code.
50 | ///
51 | [EditorBrowsable(EditorBrowsableState.Never)]
52 | public readonly struct CoreDispatcherThreadSwitcher : IThreadSwitcher
53 | {
54 | ///
55 | /// A whose foreground thread to switch execution to.
56 | ///
57 | private readonly CoreDispatcher dispatcher;
58 |
59 | ///
60 | /// Specifies the priority for event dispatch.
61 | ///
62 | private readonly CoreDispatcherPriority priority;
63 |
64 | ///
65 | /// Initializes a new instance of the struct.
66 | ///
67 | /// A whose foreground thread to switch execution to.
68 | /// Specifies the priority for event dispatch.
69 | public CoreDispatcherThreadSwitcher(CoreDispatcher dispatcher, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
70 | {
71 | this.dispatcher = dispatcher;
72 | this.priority = priority;
73 | }
74 |
75 | ///
76 | public bool IsCompleted => dispatcher?.HasThreadAccess != false;
77 |
78 | ///
79 | public void GetResult() { }
80 |
81 | ///
82 | public CoreDispatcherThreadSwitcher GetAwaiter() => this;
83 |
84 | ///
85 | IThreadSwitcher IThreadSwitcher.GetAwaiter() => this;
86 |
87 | ///
88 | public void OnCompleted(Action continuation) => _ = dispatcher.RunAsync(priority, continuation.Invoke);
89 | }
90 |
91 | ///
92 | /// A helper type for switch thread by . This type is not intended to be used directly from your code.
93 | ///
94 | [EditorBrowsable(EditorBrowsableState.Never)]
95 | public readonly struct DispatcherQueueThreadSwitcher : IThreadSwitcher
96 | {
97 | ///
98 | /// A whose foreground thread to switch execution to.
99 | ///
100 | private readonly DispatcherQueue dispatcher;
101 |
102 | ///
103 | /// Specifies the priority for event dispatch.
104 | ///
105 | private readonly DispatcherQueuePriority priority;
106 |
107 | ///
108 | /// Initializes a new instance of the struct.
109 | ///
110 | /// A whose foreground thread to switch execution to.
111 | /// Specifies the priority for event dispatch.
112 | public DispatcherQueueThreadSwitcher(DispatcherQueue dispatcher, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal)
113 | {
114 | this.dispatcher = dispatcher;
115 | this.priority = priority;
116 | }
117 |
118 | ///
119 | public bool IsCompleted => !(this.dispatcher is DispatcherQueue dispatcher)
120 | || (ThreadSwitcher.IsHasThreadAccessPropertyAvailable && dispatcher.HasThreadAccess);
121 |
122 | ///
123 | public void GetResult() { }
124 |
125 | ///
126 | public DispatcherQueueThreadSwitcher GetAwaiter() => this;
127 |
128 | ///
129 | IThreadSwitcher IThreadSwitcher.GetAwaiter() => this;
130 |
131 | ///
132 | public void OnCompleted(Action continuation) => _ = dispatcher.TryEnqueue(priority, continuation.Invoke);
133 | }
134 |
135 | ///
136 | /// A helper type for switch thread by . This type is not intended to be used directly from your code.
137 | ///
138 | [EditorBrowsable(EditorBrowsableState.Never)]
139 | public readonly struct SynchronizationContextThreadSwitcher : IThreadSwitcher
140 | {
141 | ///
142 | /// Specifies the priority for event dispatch.
143 | ///
144 | private readonly SynchronizationContext context;
145 |
146 | ///
147 | /// Initializes a new instance of the struct.
148 | ///
149 | /// A whose foreground thread to switch execution to.
150 | public SynchronizationContextThreadSwitcher(SynchronizationContext context) => this.context = context;
151 |
152 | ///
153 | public bool IsCompleted => !(this.context is SynchronizationContext context)
154 | || SynchronizationContext.Current == context;
155 |
156 | ///
157 | public void GetResult() { }
158 |
159 | ///
160 | public SynchronizationContextThreadSwitcher GetAwaiter() => this;
161 |
162 | ///
163 | IThreadSwitcher IThreadSwitcher.GetAwaiter() => this;
164 |
165 | ///
166 | public void OnCompleted(Action continuation) => context.Post(_ => continuation(), null);
167 | }
168 |
169 | ///
170 | /// A helper type for switch thread by . This type is not intended to be used directly from your code.
171 | ///
172 | [EditorBrowsable(EditorBrowsableState.Never)]
173 | public readonly struct ThreadPoolThreadSwitcher : IThreadSwitcher
174 | {
175 | ///
176 | /// Specifies the priority for event dispatch.
177 | ///
178 | private readonly WorkItemPriority priority;
179 |
180 | ///
181 | /// Initializes a new instance of the struct.
182 | ///
183 | /// Specifies the priority for event dispatch.
184 | public ThreadPoolThreadSwitcher(WorkItemPriority priority = WorkItemPriority.Normal) => this.priority = priority;
185 |
186 | ///
187 | public bool IsCompleted => SynchronizationContext.Current == null;
188 |
189 | ///
190 | public void GetResult() { }
191 |
192 | ///
193 | public ThreadPoolThreadSwitcher GetAwaiter() => this;
194 |
195 | ///
196 | IThreadSwitcher IThreadSwitcher.GetAwaiter() => this;
197 |
198 | ///
199 | public void OnCompleted(Action continuation) => _ = ThreadPool.RunAsync(_ => continuation(), priority);
200 | }
201 |
202 | ///
203 | /// The extensions for switching threads.
204 | ///
205 | public static class ThreadSwitcher
206 | {
207 | ///
208 | /// Gets is supported.
209 | ///
210 | public static bool IsHasThreadAccessPropertyAvailable { get; } = ApiInformation.IsMethodPresent("Windows.System.DispatcherQueue", "HasThreadAccess");
211 |
212 | ///
213 | /// A helper function—for use within a coroutine—that you can to switch execution to a specific foreground thread.
214 | ///
215 | /// A whose foreground thread to switch execution to.
216 | /// Specifies the priority for event dispatch.
217 | /// An object that you can .
218 | public static DispatcherQueueThreadSwitcher ResumeForegroundAsync(this DispatcherQueue dispatcher, DispatcherQueuePriority priority = DispatcherQueuePriority.Normal) => new DispatcherQueueThreadSwitcher(dispatcher, priority);
219 |
220 | ///
221 | /// A helper function—for use within a coroutine—that you can to switch execution to a specific foreground thread.
222 | ///
223 | /// A whose foreground thread to switch execution to.
224 | /// Specifies the priority for event dispatch.
225 | /// An object that you can .
226 | public static CoreDispatcherThreadSwitcher ResumeForegroundAsync(this CoreDispatcher dispatcher, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => new CoreDispatcherThreadSwitcher(dispatcher, priority);
227 |
228 | ///
229 | /// A helper function—for use within a coroutine—that you can to switch execution to a specific foreground thread.
230 | ///
231 | /// A whose foreground thread to switch execution to.
232 | /// An object that you can .
233 | public static SynchronizationContextThreadSwitcher ResumeForegroundAsync(this SynchronizationContext context) => new SynchronizationContextThreadSwitcher(context);
234 |
235 | ///
236 | /// A helper function—for use within a coroutine—that returns control to the caller, and then immediately resumes execution on a thread pool thread.
237 | ///
238 | /// Specifies the priority for event dispatch.
239 | /// An object that you can .
240 | public static ThreadPoolThreadSwitcher ResumeBackgroundAsync(WorkItemPriority priority = WorkItemPriority.Normal) => new ThreadPoolThreadSwitcher(priority);
241 | }
242 | }
--------------------------------------------------------------------------------
/MicaDemo/Helpers/ThemeHelper.cs:
--------------------------------------------------------------------------------
1 | using MicaDemo.Common;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Windows.ApplicationModel.Core;
7 | using Windows.Foundation.Metadata;
8 | using Windows.UI;
9 | using Windows.UI.ViewManagement;
10 | using Windows.UI.WindowManagement;
11 | using Windows.UI.Xaml;
12 |
13 | namespace MicaDemo.Helpers
14 | {
15 | ///
16 | /// Class providing functionality around switching and restoring theme settings
17 | ///
18 | public static class ThemeHelper
19 | {
20 | private static Window CurrentApplicationWindow;
21 |
22 | public static bool IsStatusBarSupported { get; } = ApiInformation.IsTypePresent("Windows.UI.ViewManagement.StatusBar");
23 |
24 | // Keep reference so it does not get optimized/garbage collected
25 | public static UISettings UISettings { get; } = new UISettings();
26 | public static AccessibilitySettings AccessibilitySettings { get; } = new AccessibilitySettings();
27 |
28 | #region UISettingChanged
29 |
30 | private static readonly WeakEvent actions = new WeakEvent();
31 |
32 | public static event Action UISettingChanged
33 | {
34 | add => actions.Add(value);
35 | remove => actions.Remove(value);
36 | }
37 |
38 | private static void InvokeUISettingChanged(bool value) => actions.Invoke(value);
39 |
40 | #endregion
41 |
42 | #region RootTheme
43 |
44 | public static Task GetRootThemeAsync() =>
45 | GetRootThemeAsync(Window.Current ?? CurrentApplicationWindow);
46 |
47 | public static async Task GetRootThemeAsync(Window window)
48 | {
49 | if (window == null)
50 | {
51 | return ElementTheme.Default;
52 | }
53 |
54 | await window.Dispatcher.ResumeForegroundAsync();
55 |
56 | return window.Content is FrameworkElement rootElement
57 | ? rootElement.RequestedTheme
58 | : ElementTheme.Default;
59 | }
60 |
61 | public static async Task SetRootThemeAsync(ElementTheme value)
62 | {
63 | await Task.WhenAll(WindowHelper.ActiveWindows.Values.Select(async window =>
64 | {
65 | await window.Dispatcher.ResumeForegroundAsync();
66 |
67 | if (window.Content is FrameworkElement rootElement)
68 | {
69 | rootElement.RequestedTheme = value;
70 | }
71 |
72 | if (WindowHelper.IsAppWindowSupported && WindowHelper.ActiveAppWindows.TryGetValue(window.Dispatcher, out Dictionary appWindows))
73 | {
74 | foreach (FrameworkElement element in appWindows.Keys.Select(x => x.Content).OfType())
75 | {
76 | element.RequestedTheme = value;
77 | }
78 | }
79 | }));
80 |
81 | UpdateSystemCaptionButtonColors();
82 | InvokeUISettingChanged(await IsDarkThemeAsync());
83 | }
84 |
85 | #endregion
86 |
87 | static ThemeHelper()
88 | {
89 | // Registering to color changes, thus we notice when user changes theme system wide
90 | UISettings.ColorValuesChanged += UISettings_ColorValuesChanged;
91 | }
92 |
93 | public static async void Initialize(Window window)
94 | {
95 | if (window == null) { return; }
96 | // Save reference as this might be null when the user is in another app
97 | if (CurrentApplicationWindow == null)
98 | { CurrentApplicationWindow = window; }
99 | if (window?.Content is FrameworkElement rootElement)
100 | { rootElement.RequestedTheme = await GetRootThemeAsync(CurrentApplicationWindow); }
101 | UpdateSystemCaptionButtonColors(window);
102 | }
103 |
104 | public static async void Initialize(AppWindow window)
105 | {
106 | if (window?.GetXamlRootForWindow() is FrameworkElement rootElement)
107 | { rootElement.RequestedTheme = await GetRootThemeAsync(CurrentApplicationWindow); }
108 | UpdateSystemCaptionButtonColors(window);
109 | }
110 |
111 | private static async void UISettings_ColorValuesChanged(UISettings sender, object args)
112 | {
113 | UpdateSystemCaptionButtonColors();
114 | InvokeUISettingChanged(await IsDarkThemeAsync());
115 | }
116 |
117 | public static Task IsDarkThemeAsync() => GetRootThemeAsync().ContinueWith(x => IsDarkTheme(x.Result));
118 |
119 | public static bool IsDarkTheme(ElementTheme actualTheme)
120 | {
121 | return Window.Current != null
122 | ? actualTheme == ElementTheme.Default
123 | ? Application.Current.RequestedTheme == ApplicationTheme.Dark
124 | : actualTheme == ElementTheme.Dark
125 | : actualTheme == ElementTheme.Default
126 | ? UISettings?.GetColorValue(UIColorType.Foreground).IsColorLight() == true
127 | : actualTheme == ElementTheme.Dark;
128 | }
129 |
130 | public static bool IsColorLight(this Color color) => ((5 * color.G) + (2 * color.R) + color.B) > (8 * 128);
131 |
132 | public static void UpdateExtendViewIntoTitleBar(bool isExtendsTitleBar)
133 | {
134 | WindowHelper.ActiveWindows.Values.ForEach(async window =>
135 | {
136 | await window.Dispatcher.ResumeForegroundAsync();
137 |
138 | CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar = isExtendsTitleBar;
139 |
140 | if (WindowHelper.IsAppWindowSupported && WindowHelper.ActiveAppWindows.TryGetValue(window.Dispatcher, out Dictionary appWindows))
141 | {
142 | foreach (AppWindow appWindow in appWindows.Values)
143 | {
144 | appWindow.TitleBar.ExtendsContentIntoTitleBar = isExtendsTitleBar;
145 | }
146 | }
147 | });
148 | }
149 |
150 | public static async void UpdateSystemCaptionButtonColors()
151 | {
152 | bool isDark = await IsDarkThemeAsync();
153 | bool isHighContrast = AccessibilitySettings.HighContrast;
154 |
155 | Color foregroundColor = isDark || isHighContrast ? Colors.White : Colors.Black;
156 | Color backgroundColor = isHighContrast ? Color.FromArgb(255, 0, 0, 0) : isDark ? Color.FromArgb(255, 32, 32, 32) : Color.FromArgb(255, 243, 243, 243);
157 |
158 | WindowHelper.ActiveWindows.Values.ForEach(async window =>
159 | {
160 | await window.Dispatcher.ResumeForegroundAsync();
161 |
162 | if (IsStatusBarSupported)
163 | {
164 | StatusBar statusBar = StatusBar.GetForCurrentView();
165 | statusBar.ForegroundColor = foregroundColor;
166 | statusBar.BackgroundColor = backgroundColor;
167 | statusBar.BackgroundOpacity = 0; // 透明度
168 | }
169 | else
170 | {
171 | bool extendViewIntoTitleBar = CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar;
172 | ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
173 | titleBar.ForegroundColor = titleBar.ButtonForegroundColor = foregroundColor;
174 | titleBar.BackgroundColor = titleBar.InactiveBackgroundColor = backgroundColor;
175 | titleBar.ButtonBackgroundColor = titleBar.ButtonInactiveBackgroundColor = extendViewIntoTitleBar ? Colors.Transparent : backgroundColor;
176 | }
177 |
178 | if (WindowHelper.IsAppWindowSupported && WindowHelper.ActiveAppWindows.TryGetValue(window.Dispatcher, out Dictionary appWindows))
179 | {
180 | foreach (AppWindow appWindow in appWindows.Values)
181 | {
182 | bool extendViewIntoTitleBar = appWindow.TitleBar.ExtendsContentIntoTitleBar;
183 | AppWindowTitleBar titleBar = appWindow.TitleBar;
184 | titleBar.ForegroundColor = titleBar.ButtonForegroundColor = foregroundColor;
185 | titleBar.BackgroundColor = titleBar.InactiveBackgroundColor = backgroundColor;
186 | titleBar.ButtonBackgroundColor = titleBar.ButtonInactiveBackgroundColor = extendViewIntoTitleBar ? Colors.Transparent : backgroundColor;
187 | }
188 | }
189 | });
190 | }
191 |
192 | public static async void UpdateSystemCaptionButtonColors(Window window)
193 | {
194 | await window.Dispatcher.ResumeForegroundAsync();
195 |
196 | bool isDark = window?.Content is FrameworkElement rootElement ? IsDarkTheme(rootElement.RequestedTheme) : await IsDarkThemeAsync();
197 | bool isHighContrast = AccessibilitySettings.HighContrast;
198 |
199 | Color foregroundColor = isDark || isHighContrast ? Colors.White : Colors.Black;
200 | Color backgroundColor = isHighContrast ? Color.FromArgb(255, 0, 0, 0) : isDark ? Color.FromArgb(255, 32, 32, 32) : Color.FromArgb(255, 243, 243, 243);
201 |
202 | if (IsStatusBarSupported)
203 | {
204 | StatusBar statusBar = StatusBar.GetForCurrentView();
205 | statusBar.ForegroundColor = foregroundColor;
206 | statusBar.BackgroundColor = backgroundColor;
207 | statusBar.BackgroundOpacity = 0; // 透明度
208 | }
209 | else
210 | {
211 | bool extendViewIntoTitleBar = CoreApplication.GetCurrentView().TitleBar.ExtendViewIntoTitleBar;
212 | ApplicationViewTitleBar titleBar = ApplicationView.GetForCurrentView().TitleBar;
213 | titleBar.ForegroundColor = titleBar.ButtonForegroundColor = foregroundColor;
214 | titleBar.BackgroundColor = titleBar.InactiveBackgroundColor = backgroundColor;
215 | titleBar.ButtonBackgroundColor = titleBar.ButtonInactiveBackgroundColor = extendViewIntoTitleBar ? Colors.Transparent : backgroundColor;
216 | }
217 | }
218 |
219 | public static async void UpdateSystemCaptionButtonColors(AppWindow window)
220 | {
221 | await window.DispatcherQueue.ResumeForegroundAsync();
222 |
223 | bool isDark = window.GetXamlRootForWindow() is FrameworkElement rootElement ? IsDarkTheme(rootElement.RequestedTheme) : await IsDarkThemeAsync();
224 | bool isHighContrast = AccessibilitySettings.HighContrast;
225 |
226 | Color foregroundColor = isDark || isHighContrast ? Colors.White : Colors.Black;
227 | Color backgroundColor = isHighContrast ? Color.FromArgb(255, 0, 0, 0) : isDark ? Color.FromArgb(255, 32, 32, 32) : Color.FromArgb(255, 243, 243, 243);
228 |
229 | bool extendViewIntoTitleBar = window.TitleBar.ExtendsContentIntoTitleBar;
230 | AppWindowTitleBar titleBar = window.TitleBar;
231 | titleBar.ForegroundColor = titleBar.ButtonForegroundColor = foregroundColor;
232 | titleBar.BackgroundColor = titleBar.InactiveBackgroundColor = backgroundColor;
233 | titleBar.ButtonBackgroundColor = titleBar.ButtonInactiveBackgroundColor = extendViewIntoTitleBar ? Colors.Transparent : backgroundColor;
234 | }
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/MicaDemo/MicaDemo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x86
7 | {6E6F491C-7B25-4BBC-AA5F-147E14A200C4}
8 | AppContainerExe
9 | Properties
10 | MicaDemo
11 | MicaDemo
12 | 7.3
13 | en-US
14 | UAP
15 | 10.0.22621.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 | true
20 | false
21 | True
22 | False
23 | False
24 | True
25 | Never
26 | 0
27 |
28 |
29 | true
30 | bin\x86\Debug\
31 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
32 | 10.0.10240.0
33 | ;2008
34 | full
35 | x86
36 | false
37 | prompt
38 | true
39 |
40 |
41 | bin\x86\Release\
42 | TRACE;NETFX_CORE;WINDOWS_UWP
43 | 10.0.10240.0
44 | true
45 | ;2008
46 | pdbonly
47 | x86
48 | false
49 | prompt
50 | true
51 | true
52 |
53 |
54 | true
55 | bin\ARM\Debug\
56 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
57 | 10.0.10240.0
58 | ;2008
59 | full
60 | ARM
61 | false
62 | prompt
63 | true
64 |
65 |
66 | bin\ARM\Release\
67 | TRACE;NETFX_CORE;WINDOWS_UWP
68 | 10.0.10240.0
69 | true
70 | ;2008
71 | pdbonly
72 | ARM
73 | false
74 | prompt
75 | true
76 | true
77 |
78 |
79 | true
80 | bin\ARM64\Debug\
81 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP;NETCORE463
82 | 10.0.16299.0
83 | ;2008
84 | full
85 | ARM64
86 | false
87 | prompt
88 | true
89 | true
90 |
91 |
92 | bin\ARM64\Release\
93 | TRACE;NETFX_CORE;WINDOWS_UWP;NETCORE463
94 | 10.0.16299.0
95 | true
96 | ;2008
97 | pdbonly
98 | ARM64
99 | false
100 | prompt
101 | true
102 | true
103 |
104 |
105 | true
106 | bin\x64\Debug\
107 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
108 | 10.0.10240.0
109 | ;2008
110 | full
111 | x64
112 | false
113 | prompt
114 | true
115 |
116 |
117 | bin\x64\Release\
118 | TRACE;NETFX_CORE;WINDOWS_UWP
119 | 10.0.10240.0
120 | true
121 | ;2008
122 | pdbonly
123 | x64
124 | false
125 | prompt
126 | true
127 | true
128 |
129 |
130 | PackageReference
131 |
132 |
133 |
134 | App.xaml
135 |
136 |
137 |
138 | ColorPickerEx.xaml
139 |
140 |
141 | TitleBar.xaml
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | BlurPage.xaml
155 |
156 |
157 | MainPage.xaml
158 |
159 |
160 | MicaPage.xaml
161 |
162 |
163 |
164 |
165 |
166 |
167 | Designer
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | MSBuild:Compile
228 | Designer
229 |
230 |
231 | Designer
232 | MSBuild:Compile
233 |
234 |
235 | MSBuild:Compile
236 | Designer
237 |
238 |
239 | Designer
240 | MSBuild:Compile
241 |
242 |
243 | MSBuild:Compile
244 | Designer
245 |
246 |
247 | Designer
248 | MSBuild:Compile
249 |
250 |
251 | MSBuild:Compile
252 | Designer
253 |
254 |
255 |
256 |
257 | 6.2.14
258 |
259 |
260 |
261 |
262 | Windows Mobile Extensions for the UWP
263 |
264 |
265 |
266 |
267 | {50913772-1182-44a9-8157-0410895e0db3}
268 | MicaForUWP
269 |
270 |
271 |
272 | 14.0
273 |
274 |
275 |
282 |
--------------------------------------------------------------------------------
/MicaDemo/Pages/BlurPage.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
52 |
53 |
54 |
55 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
73 |
74 |
75 |
76 |
77 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
94 |
95 |
96 |
97 |
98 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
120 |
121 |
122 |
123 |
124 |
125 |
134 |
139 |
140 |
147 |
154 |
174 |
181 |
203 |
204 |
205 |
206 |
207 |
208 |
213 |
220 |
225 | HostBackdrop
226 | Backdrop
227 | WallpaperBackdrop
228 |
229 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
--------------------------------------------------------------------------------
/MicaDemo/Pages/MicaPage.xaml:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
74 |
75 |
76 |
77 |
78 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
95 |
96 |
97 |
98 |
99 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
121 |
122 |
123 |
124 |
125 |
126 |
135 |
140 |
141 |
148 |
155 |
175 |
182 |
204 |
205 |
206 |
207 |
208 |
209 |
216 |
223 |
228 |
233 | HostBackdrop
234 | Backdrop
235 | WallpaperBackdrop
236 |
237 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
--------------------------------------------------------------------------------