├── .gitattributes ├── .gitignore ├── Directory.Build.props ├── LICENSE.md ├── ModernWpf Community Toolkit.sln ├── ModernWpf.Toolkit.SampleApp ├── App.xaml ├── App.xaml.cs ├── Assets │ ├── NotificationAssets │ │ └── Sunny-Square.png │ └── Photos │ │ └── WestSeattleView.jpg ├── EmojiUIElementInline.cs ├── InitialContent.md ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── ModernWpf.Toolkit.SampleApp.csproj ├── Properties │ ├── AssemblyInfo.cs │ └── DesignTimeResources.xaml └── app.manifest ├── ModernWpf.Toolkit.UI.Controls.Markdown ├── CodeBlockFormatter.cs ├── Inlines │ ├── CodeUIElementInline.cs │ └── IUIElementInline.cs ├── MarkdownTextBlock │ ├── CodeBlockResolvingEventArgs.cs │ ├── EmojiInlineResolvingEventArgs.cs │ ├── ImageResolvingDeferral.cs │ ├── ImageResolvingEventArgs.cs │ ├── LinkClickedEventArgs.cs │ ├── MarkdownRenderedEventArgs.cs │ ├── MarkdownTextBlock.Dimensions.cs │ ├── MarkdownTextBlock.Events.cs │ ├── MarkdownTextBlock.Methods.cs │ ├── MarkdownTextBlock.Properties.cs │ ├── MarkdownTextBlock.cs │ └── MarkdownTextBlock.xaml ├── ModernWpf.Toolkit.UI.Controls.Markdown.csproj ├── Properties │ └── AssemblyInfo.cs ├── Render │ ├── BlockCollectionRenderContext.cs │ ├── ICodeBlockResolver.cs │ ├── IEmojiInlineResolver.cs │ ├── IImageResolver.cs │ ├── ILinkRegister.cs │ ├── InlineRenderContext.cs │ ├── MarkdownRenderer.Blocks.cs │ ├── MarkdownRenderer.Dimensions.cs │ ├── MarkdownRenderer.Inlines.cs │ ├── MarkdownRenderer.Properties.cs │ ├── MarkdownRenderer.cs │ ├── RenderContext.cs │ └── RenderContextIncorrectException.cs ├── SelectableTextBlock.cs └── Themes │ └── Generic.xaml ├── ModernWpf.Toolkit.UI.Controls ├── Eyedropper │ ├── Eyedropper.Logic.cs │ ├── Eyedropper.Properties.cs │ ├── Eyedropper.cs │ ├── Eyedropper.xaml │ ├── EyedropperColorChangedEventArgs.cs │ ├── EyedropperToolButton.Properties.cs │ ├── EyedropperToolButton.cs │ └── EyedropperToolButton.xaml ├── FontIconEx.cs ├── ModernWpf.Toolkit.UI.Controls.csproj ├── Properties │ └── AssemblyInfo.cs ├── SimpleWrapPanel │ ├── SimpleWrapPanel.Data.cs │ ├── SimpleWrapPanel.cs │ └── StretchChild.cs └── Themes │ └── Generic.xaml ├── ModernWpf.Toolkit.UI ├── Converters │ ├── BoolNegationConverter.cs │ ├── BoolToObjectConverter.cs │ ├── BoolToVisibilityConverter.cs │ ├── CollectionVisibilityConverter.cs │ ├── ConverterTools.cs │ ├── DoubleToObjectConverter.cs │ ├── DoubleToVisibilityConverter.cs │ ├── EmptyCollectionToObjectConverter.cs │ ├── EmptyObjectToObjectConverter.cs │ ├── EmptyStringToObjectConverter.cs │ ├── FileSizeToFriendlyStringConverter.cs │ ├── FormatStringConverter.cs │ ├── StringFormatConverter.cs │ ├── StringVisibilityConverter.cs │ ├── TypeToObjectConverter.cs │ └── VisibilityToBoolConverter.cs ├── Deferred │ └── TypedEventHandlerExtensions.cs ├── DependencyPropertyChangedCallback.cs ├── Extensions │ ├── DependencyObjectExtensions.cs │ ├── DispatcherTimerExtensions.cs │ ├── FrameworkElement │ │ └── FrameworkElementExtensions.RelativeAncestor.cs │ ├── Markup │ │ ├── Abstract │ │ │ └── TextIconExtension.cs │ │ ├── BitmapIconExtension.cs │ │ ├── BitmapIconSourceExtension.cs │ │ ├── EnumValuesExtension.cs │ │ ├── FontIconExtension.cs │ │ ├── FontIconSourceExtension.cs │ │ ├── NullableBool.cs │ │ ├── SymbolIconExtension.cs │ │ └── SymbolIconSourceExtension.cs │ ├── Media │ │ ├── MatrixExtensions.cs │ │ ├── MatrixHelperEx.cs │ │ ├── RotateTransformExtensions.cs │ │ ├── ScaleTransformExtensions.cs │ │ ├── SkewTransformExtensions.cs │ │ └── TranslateTransformExtensions.cs │ ├── ScrollViewer │ │ ├── Enums │ │ │ ├── Axis.cs │ │ │ └── VisualProperty.cs │ │ ├── ScrollViewerExtensions.Properties.cs │ │ └── ScrollViewerExtensions.cs │ ├── TextBoxMask │ │ ├── TextBoxMask.Properties.cs │ │ └── TextBoxMask.cs │ ├── TextBoxRegEx │ │ ├── TextBoxRegex.Data.cs │ │ ├── TextBoxRegex.Properties.cs │ │ └── TextBoxRegex.cs │ └── Tree │ │ ├── LogicalTree.cs │ │ └── VisualTree.cs ├── Helpers │ ├── BindableValueHolder.cs │ ├── CompositionTargetHelper.cs │ ├── DependencyPropertyWatcher.cs │ └── GraphicsHelper.cs ├── ModernWpf.Toolkit.UI.csproj ├── Properties │ └── AssemblyInfo.cs └── ThemeResources │ ├── Dark.xaml │ ├── HighContrast.xaml │ ├── Light.xaml │ └── ToolkitThemeDictionary.cs ├── ModernWpf.Toolkit ├── Converters.cs ├── Deferred │ ├── DeferredCancelEventArgs.cs │ ├── DeferredEventArgs.cs │ ├── EventDeferral.cs │ └── EventHandlerExtensions.cs ├── Extensions │ ├── PointExtensions.cs │ ├── SizeExtensions.cs │ └── StringExtensions.cs ├── Helpers │ ├── ColorHelper.cs │ └── WeakEventListener.cs ├── ModernWpf.Toolkit.csproj ├── Properties │ └── AssemblyInfo.cs └── Structures │ ├── HslColor.cs │ └── HsvColor.cs └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 0.1.0 4 | ModernWpf.Toolkit 5 | MIT 6 | https://github.com/ModernWpf-Community/ModernWpfCommunityToolkit 7 | https://github.com/ModernWpf-Community/ModernWpfCommunityToolkit 8 | MIT 9 | git 10 | $(MSBuildThisFileDirectory)localpackages 11 | 12 | 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) .NET Foundation and Contributors 4 | All rights reserved. 5 | 6 | Copyright (c) 2020 Shankar 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in all 16 | copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | SOFTWARE. 25 | -------------------------------------------------------------------------------- /ModernWpf Community Toolkit.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30128.36 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernWpf.Toolkit.SampleApp", "ModernWpf.Toolkit.SampleApp\ModernWpf.Toolkit.SampleApp.csproj", "{C9D2DBC9-FAD7-4923-9A70-44435C6F31E2}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernWpf.Toolkit.UI.Controls", "ModernWpf.Toolkit.UI.Controls\ModernWpf.Toolkit.UI.Controls.csproj", "{5A197E07-36CE-41C6-AB80-B4886D9FAB14}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernWpf.Toolkit", "ModernWpf.Toolkit\ModernWpf.Toolkit.csproj", "{E094D380-B238-4252-99E0-BA2F10EDEB51}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernWpf.Toolkit.UI", "ModernWpf.Toolkit.UI\ModernWpf.Toolkit.UI.csproj", "{DB1F7DC6-5FC7-4987-816E-65E66BAD7154}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModernWpf.Toolkit.UI.Controls.Markdown", "ModernWpf.Toolkit.UI.Controls.Markdown\ModernWpf.Toolkit.UI.Controls.Markdown.csproj", "{EE62AF2F-FB8B-472D-AF17-3F62F588A41F}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {C9D2DBC9-FAD7-4923-9A70-44435C6F31E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {C9D2DBC9-FAD7-4923-9A70-44435C6F31E2}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {C9D2DBC9-FAD7-4923-9A70-44435C6F31E2}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {C9D2DBC9-FAD7-4923-9A70-44435C6F31E2}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {5A197E07-36CE-41C6-AB80-B4886D9FAB14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {5A197E07-36CE-41C6-AB80-B4886D9FAB14}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {5A197E07-36CE-41C6-AB80-B4886D9FAB14}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {5A197E07-36CE-41C6-AB80-B4886D9FAB14}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {E094D380-B238-4252-99E0-BA2F10EDEB51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {E094D380-B238-4252-99E0-BA2F10EDEB51}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {E094D380-B238-4252-99E0-BA2F10EDEB51}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {E094D380-B238-4252-99E0-BA2F10EDEB51}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {DB1F7DC6-5FC7-4987-816E-65E66BAD7154}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {DB1F7DC6-5FC7-4987-816E-65E66BAD7154}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {DB1F7DC6-5FC7-4987-816E-65E66BAD7154}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {DB1F7DC6-5FC7-4987-816E-65E66BAD7154}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {EE62AF2F-FB8B-472D-AF17-3F62F588A41F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {EE62AF2F-FB8B-472D-AF17-3F62F588A41F}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {EE62AF2F-FB8B-472D-AF17-3F62F588A41F}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {EE62AF2F-FB8B-472D-AF17-3F62F588A41F}.Release|Any CPU.Build.0 = Release|Any CPU 42 | EndGlobalSection 43 | GlobalSection(SolutionProperties) = preSolution 44 | HideSolutionNode = FALSE 45 | EndGlobalSection 46 | GlobalSection(ExtensibilityGlobals) = postSolution 47 | SolutionGuid = {4D2E5882-F819-4EB6-BE25-227B22BE1804} 48 | EndGlobalSection 49 | EndGlobal 50 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/App.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace ModernWpf.Toolkit.SampleApp 4 | { 5 | public partial class App : Application 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/Assets/NotificationAssets/Sunny-Square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModernWpf-Community/ModernWpfCommunityToolkit/8bbe2231087575df182a7740839b92e917fa711b/ModernWpf.Toolkit.SampleApp/Assets/NotificationAssets/Sunny-Square.png -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/Assets/Photos/WestSeattleView.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModernWpf-Community/ModernWpfCommunityToolkit/8bbe2231087575df182a7740839b92e917fa711b/ModernWpf.Toolkit.SampleApp/Assets/Photos/WestSeattleView.jpg -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/EmojiUIElementInline.cs: -------------------------------------------------------------------------------- 1 | using Emoji.Wpf; 2 | using ModernWpf.Toolkit.UI.Controls.Markdown.Inlines; 3 | 4 | namespace ModernWpf.Toolkit.SampleApp 5 | { 6 | public class EmojiUIElementInline : EmojiInline, IUIElementInline 7 | { 8 | public string GetUIContentString() => Text; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 12 | 13 | 14 | 15 | 16 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using ModernWpf.Toolkit.UI.Controls; 2 | using System; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Windows; 6 | using System.Windows.Documents; 7 | using System.Windows.Media; 8 | 9 | namespace ModernWpf.Toolkit.SampleApp 10 | { 11 | public partial class MainWindow : Window 12 | { 13 | public MainWindow() 14 | { 15 | InitializeComponent(); 16 | Loaded += MainWindow_Loaded; 17 | MDbox.LinkClicked += MDbox_LinkClicked; 18 | MDbox.ImageClicked += MDbox_ImageClicked; 19 | MDbox.CodeBlockResolving += MDbox_CodeBlockResolving; 20 | MDbox.EmojiInlineResolving += MDbox_EmojiInlineResolving; 21 | MDbox.MarkdownRendered += MDbox_MarkdownRendered; 22 | } 23 | 24 | private void MDbox_MarkdownRendered(object sender, MarkdownRenderedEventArgs e) 25 | { 26 | if (e.Exception == null && MDbox.Text != null) 27 | { 28 | Debug.WriteLine("Rendered yay!"); 29 | } 30 | } 31 | 32 | private void MDbox_EmojiInlineResolving(object sender, EmojiInlineResolvingEventArgs e) 33 | { 34 | try 35 | { 36 | double fontSize = Math.Max(16.0, MDbox.FontSize); 37 | e.EmojiInline = new EmojiUIElementInline { Text = e.EmojiString, FontSize = fontSize, FallbackBrush = MDbox.Foreground }; 38 | e.Handled = true; 39 | } 40 | catch 41 | { 42 | e.EmojiInline = null; 43 | e.Handled = false; 44 | } 45 | } 46 | 47 | private void MDbox_CodeBlockResolving(object sender, CodeBlockResolvingEventArgs e) 48 | { 49 | if (e.CodeLanguage == "CUSTOM") 50 | { 51 | e.Handled = true; 52 | e.InlineCollection.Add(new Run { Foreground = new SolidColorBrush(Colors.Red), Text = e.Text, FontWeight = FontWeights.Bold }); 53 | } 54 | } 55 | 56 | private void MDbox_ImageClicked(object sender, LinkClickedEventArgs e) 57 | { 58 | if (!Uri.TryCreate(e.Link, UriKind.Absolute, out Uri result)) 59 | { 60 | MessageBox.Show("Masked relative Images needs to be manually handled."); 61 | } 62 | else 63 | { 64 | var psi = new ProcessStartInfo() 65 | { 66 | FileName = e.Link, 67 | UseShellExecute = true 68 | }; 69 | Process.Start(psi); 70 | } 71 | } 72 | 73 | private void MDbox_LinkClicked(object sender, LinkClickedEventArgs e) 74 | { 75 | if (!Uri.TryCreate(e.Link, UriKind.Absolute, out Uri result)) 76 | { 77 | MessageBox.Show("Masked relative links needs to be manually handled."); 78 | } 79 | else 80 | { 81 | var psi = new ProcessStartInfo() 82 | { 83 | FileName = e.Link, 84 | UseShellExecute = true 85 | }; 86 | Process.Start(psi); 87 | } 88 | } 89 | 90 | private void MainWindow_Loaded(object sender, RoutedEventArgs e) 91 | { 92 | string initialmd = GetInitialMD(); 93 | EditorBox.Text = initialmd; 94 | } 95 | 96 | private string GetInitialMD() 97 | { 98 | return File.ReadAllText("InitialContent.md"); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/ModernWpf.Toolkit.SampleApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net5.0-windows10.0.18362.0;netcoreapp3.1;net462 6 | true 7 | latest 8 | app.manifest 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Always 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | MSBuild:Compile 28 | Designer 29 | True 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Always 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/Properties/DesignTimeResources.xaml: -------------------------------------------------------------------------------- 1 |  4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.SampleApp/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | PerMonitor 56 | true 57 | 58 | 59 | 60 | 61 | 62 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Inlines/CodeUIElementInline.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Controls; 3 | using System.Windows.Documents; 4 | 5 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Inlines 6 | { 7 | internal class CodeUIElementInline : InlineUIContainer, IUIElementInline 8 | { 9 | public CodeUIElementInline() 10 | { 11 | } 12 | 13 | /// 14 | /// Redeclare the Child property to prevent it from being serialized. 15 | /// 16 | public new Border Child 17 | { 18 | get => base.Child as Border; 19 | internal set => base.Child = value; 20 | } 21 | 22 | public string Text 23 | { 24 | get => (string)GetValue(TextProperty); 25 | set => SetValue(TextProperty, value); 26 | } 27 | 28 | public static readonly DependencyProperty TextProperty = 29 | DependencyProperty.Register( 30 | nameof(Text), 31 | typeof(string), 32 | typeof(CodeUIElementInline), 33 | new PropertyMetadata("")); 34 | 35 | protected override bool ShouldSerializeProperty(DependencyProperty dp) 36 | => dp.Name == nameof(Text) && base.ShouldSerializeProperty(dp); 37 | 38 | protected bool ShouldSerializeChild() => false; 39 | 40 | public string GetUIContentString() => Text; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Inlines/IUIElementInline.cs: -------------------------------------------------------------------------------- 1 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Inlines 2 | { 3 | public interface IUIElementInline 4 | { 5 | string GetUIContentString(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/CodeBlockResolvingEventArgs.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 System.Windows.Documents; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls 9 | { 10 | /// 11 | /// Arguments for the event when a Code Block is being rendered. 12 | /// 13 | public class CodeBlockResolvingEventArgs : EventArgs 14 | { 15 | internal CodeBlockResolvingEventArgs(InlineCollection inlineCollection, string text, string codeLanguage) 16 | { 17 | InlineCollection = inlineCollection; 18 | Text = text; 19 | CodeLanguage = codeLanguage; 20 | } 21 | 22 | /// 23 | /// Gets the language of the Code Block, as specified by ```{Language} on the first line of the block, 24 | /// e.g. 25 | /// ```C# 26 | /// public void Method(); 27 | /// ``` 28 | /// 29 | public string CodeLanguage { get; } 30 | 31 | /// 32 | /// Gets the raw code block text 33 | /// 34 | public string Text { get; } 35 | 36 | /// 37 | /// Gets Collection to add formatted Text to. 38 | /// 39 | public InlineCollection InlineCollection { get; } 40 | 41 | /// 42 | /// Gets or sets a value indicating whether this event was handled successfully. 43 | /// 44 | public bool Handled { get; set; } = false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/EmojiInlineResolvingEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Documents; 3 | 4 | namespace ModernWpf.Toolkit.UI.Controls 5 | { 6 | /// 7 | /// Arguments for the event which is called when a emoji needs to be resolved to a . 8 | /// 9 | public class EmojiInlineResolvingEventArgs : EventArgs 10 | { 11 | internal EmojiInlineResolvingEventArgs(string emojiString) 12 | { 13 | EmojiString = emojiString; 14 | } 15 | 16 | /// 17 | /// Gets the emoji string in the markdown document. 18 | /// 19 | public string EmojiString { get; } 20 | 21 | /// 22 | /// Gets or sets a value indicating whether this event was handled successfully. 23 | /// 24 | public bool Handled { get; set; } 25 | 26 | /// 27 | /// Gets or sets the emoji inline to display in the . 28 | /// 29 | public Inline EmojiInline { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/ImageResolvingDeferral.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace ModernWpf.Toolkit.UI.Controls 4 | { 5 | public sealed class ImageResolvingDeferral 6 | { 7 | private readonly Action _handler; 8 | 9 | internal ImageResolvingDeferral(Action handler) 10 | { 11 | _handler = handler ?? throw new ArgumentNullException(nameof(handler)); 12 | } 13 | 14 | public void Complete() 15 | { 16 | _handler(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/ImageResolvingEventArgs.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 System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | using System.Windows.Media; 10 | 11 | namespace ModernWpf.Toolkit.UI.Controls 12 | { 13 | /// 14 | /// Arguments for the event which is called when a url needs to be resolved to a . 15 | /// 16 | public class ImageResolvingEventArgs : EventArgs 17 | { 18 | private readonly IList> _deferrals; 19 | 20 | internal ImageResolvingEventArgs(string url, string tooltip) 21 | { 22 | _deferrals = new List>(); 23 | Url = url; 24 | Tooltip = tooltip; 25 | } 26 | 27 | /// 28 | /// Gets the url of the image in the markdown document. 29 | /// 30 | public string Url { get; } 31 | 32 | /// 33 | /// Gets the tooltip of the image in the markdown document. 34 | /// 35 | public string Tooltip { get; } 36 | 37 | /// 38 | /// Gets or sets a value indicating whether this event was handled successfully. 39 | /// 40 | public bool Handled { get; set; } 41 | 42 | /// 43 | /// Gets or sets the image to display in the . 44 | /// 45 | public ImageSource Image { get; set; } 46 | 47 | /// 48 | /// Informs the that the event handler might run asynchronously. 49 | /// 50 | /// Deferral 51 | public ImageResolvingDeferral GetDeferral() 52 | { 53 | var task = new TaskCompletionSource(); 54 | _deferrals.Add(task); 55 | 56 | return new ImageResolvingDeferral(() => 57 | { 58 | task.SetResult(null); 59 | }); 60 | } 61 | 62 | /// 63 | /// Returns a that completes when all s have completed. 64 | /// 65 | /// A representing the asynchronous operation. 66 | internal Task WaitForDeferrals() 67 | { 68 | return Task.WhenAll(_deferrals.Select(f => f.Task)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/LinkClickedEventArgs.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 | 7 | namespace ModernWpf.Toolkit.UI.Controls 8 | { 9 | /// 10 | /// Arguments for the OnLinkClicked event which is fired then the user presses a link. 11 | /// 12 | public class LinkClickedEventArgs : EventArgs 13 | { 14 | internal LinkClickedEventArgs(string link) 15 | { 16 | Link = link; 17 | } 18 | 19 | /// 20 | /// Gets the link that was tapped. 21 | /// 22 | public string Link { get; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/MarkdownRenderedEventArgs.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 | 7 | namespace ModernWpf.Toolkit.UI.Controls 8 | { 9 | /// 10 | /// Arguments for the OnMarkdownRendered event which indicates when the markdown has been 11 | /// rendered. 12 | /// 13 | public class MarkdownRenderedEventArgs : EventArgs 14 | { 15 | internal MarkdownRenderedEventArgs(Exception ex) 16 | { 17 | Exception = ex; 18 | } 19 | 20 | /// 21 | /// Gets the exception if there was one. If the exception is null there was no error. 22 | /// 23 | public Exception Exception { get; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/MarkdownTextBlock.Events.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows; 8 | using System.Windows.Documents; 9 | 10 | namespace ModernWpf.Toolkit.UI.Controls 11 | { 12 | /// 13 | /// An efficient and extensible control that can parse and render markdown. 14 | /// 15 | public partial class MarkdownTextBlock 16 | { 17 | /// 18 | /// Calls OnPropertyChanged. 19 | /// 20 | private static void OnPropertyChangedStatic(DependencyObject d, DependencyPropertyChangedEventArgs e) 21 | { 22 | var instance = d as MarkdownTextBlock; 23 | 24 | // Defer to the instance method. 25 | instance?.OnPropertyChanged(d, e.Property); 26 | } 27 | 28 | /// 29 | /// Fired when the value of a DependencyProperty is changed. 30 | /// 31 | private void OnPropertyChanged(DependencyObject d, DependencyProperty e) 32 | { 33 | RenderMarkdown(); 34 | } 35 | 36 | /// 37 | /// Fired when a user taps one of the link elements 38 | /// 39 | private void Hyperlink_Click(object sender, RoutedEventArgs args) 40 | { 41 | Hyperlink hyperlink = (Hyperlink)sender; 42 | LinkHandled((string)hyperlink.GetValue(HyperlinkUrlProperty), true); 43 | } 44 | 45 | /// 46 | /// Fired when a user taps one of the image elements 47 | /// 48 | private void NewImagelink_Click(object sender, RoutedEventArgs e) 49 | { 50 | string hyperLink = (string)(sender as HyperlinkButton).GetValue(HyperlinkUrlProperty); 51 | bool isHyperLink = (bool)(sender as HyperlinkButton).GetValue(IsHyperlinkProperty); 52 | LinkHandled(hyperLink, isHyperLink); 53 | } 54 | 55 | /// 56 | /// Fired when the text is done parsing and formatting. Fires each time the markdown is rendered. 57 | /// 58 | public event EventHandler MarkdownRendered; 59 | 60 | /// 61 | /// Fired when a link element in the markdown was tapped. 62 | /// 63 | public event EventHandler LinkClicked; 64 | 65 | /// 66 | /// Fired when an image element in the markdown was tapped. 67 | /// 68 | public event EventHandler ImageClicked; 69 | 70 | /// 71 | /// Fired when an image from the markdown document needs to be resolved. 72 | /// The default implementation is basically new BitmapImage(new Uri(e.Url));. 73 | /// You must set to true in order to process your changes. 74 | /// 75 | public event EventHandler ImageResolving; 76 | 77 | /// 78 | /// Fired when an emoji from the markdown document needs to be resolved. 79 | /// The default implementation is to output the EmojiInline as Plain Text. 80 | /// You must set to true in order to process your changes. 81 | /// 82 | public event EventHandler EmojiInlineResolving; 83 | 84 | /// 85 | /// Fired when a Code Block is being Rendered. 86 | /// The default implementation is to output the CodeBlock as Plain Text. 87 | /// You must set to true in order to process your changes. 88 | /// 89 | public event EventHandler CodeBlockResolving; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/MarkdownTextBlock/MarkdownTextBlock.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 ModernWpf.Toolkit.UI.Controls.Markdown.Render; 6 | using ModernWpf.Toolkit.UI.Extensions; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | 10 | namespace ModernWpf.Toolkit.UI.Controls 11 | { 12 | /// 13 | /// An efficient and extensible control that can parse and render markdown. 14 | /// 15 | public partial class MarkdownTextBlock : Control, ILinkRegister, IImageResolver, ICodeBlockResolver, IEmojiInlineResolver 16 | { 17 | private long _fontSizePropertyToken; 18 | private long _flowDirectionPropertyToken; 19 | private long _backgroundPropertyToken; 20 | private long _borderBrushPropertyToken; 21 | private long _borderThicknessPropertyToken; 22 | private long _fontFamilyPropertyToken; 23 | private long _fontStretchPropertyToken; 24 | private long _fontStylePropertyToken; 25 | private long _fontWeightPropertyToken; 26 | private long _foregroundPropertyToken; 27 | private long _paddingPropertyToken; 28 | 29 | /// 30 | /// Initializes a new instance of the class. 31 | /// 32 | public MarkdownTextBlock() 33 | { 34 | DefaultStyleKey = typeof(MarkdownTextBlock); 35 | Loaded += OnLoaded; 36 | Unloaded += OnUnloaded; 37 | } 38 | 39 | private void OnLoaded(object sender, RoutedEventArgs e) 40 | { 41 | HookListeners(); 42 | ThemeManager.AddActualThemeChangedHandler(this, OnActualThemeChanged); 43 | 44 | // Register for property callbacks that are owned by our parent class. 45 | _fontSizePropertyToken = this.RegisterPropertyChangedCallback(FontSizeProperty, OnPropertyChanged); 46 | _flowDirectionPropertyToken = this.RegisterPropertyChangedCallback(FlowDirectionProperty, OnPropertyChanged); 47 | _backgroundPropertyToken = this.RegisterPropertyChangedCallback(BackgroundProperty, OnPropertyChanged); 48 | _borderBrushPropertyToken = this.RegisterPropertyChangedCallback(BorderBrushProperty, OnPropertyChanged); 49 | _borderThicknessPropertyToken = this.RegisterPropertyChangedCallback(BorderThicknessProperty, OnPropertyChanged); 50 | _fontFamilyPropertyToken = this.RegisterPropertyChangedCallback(FontFamilyProperty, OnPropertyChanged); 51 | _fontStretchPropertyToken = this.RegisterPropertyChangedCallback(FontStretchProperty, OnPropertyChanged); 52 | _fontStylePropertyToken = this.RegisterPropertyChangedCallback(FontStyleProperty, OnPropertyChanged); 53 | _fontWeightPropertyToken = this.RegisterPropertyChangedCallback(FontWeightProperty, OnPropertyChanged); 54 | _foregroundPropertyToken = this.RegisterPropertyChangedCallback(ForegroundProperty, OnPropertyChanged); 55 | _paddingPropertyToken = this.RegisterPropertyChangedCallback(PaddingProperty, OnPropertyChanged); 56 | } 57 | 58 | private void OnUnloaded(object sender, RoutedEventArgs e) 59 | { 60 | ThemeManager.RemoveActualThemeChangedHandler(this, OnActualThemeChanged); 61 | 62 | // Unregister property callbacks 63 | this.UnregisterPropertyChangedCallback(FontSizeProperty, _fontSizePropertyToken); 64 | this.UnregisterPropertyChangedCallback(FlowDirectionProperty, _flowDirectionPropertyToken); 65 | this.UnregisterPropertyChangedCallback(BackgroundProperty, _backgroundPropertyToken); 66 | this.UnregisterPropertyChangedCallback(BorderBrushProperty, _borderBrushPropertyToken); 67 | this.UnregisterPropertyChangedCallback(BorderThicknessProperty, _borderThicknessPropertyToken); 68 | this.UnregisterPropertyChangedCallback(FontFamilyProperty, _fontFamilyPropertyToken); 69 | this.UnregisterPropertyChangedCallback(FontStretchProperty, _fontStretchPropertyToken); 70 | this.UnregisterPropertyChangedCallback(FontStyleProperty, _fontStylePropertyToken); 71 | this.UnregisterPropertyChangedCallback(FontWeightProperty, _fontWeightPropertyToken); 72 | this.UnregisterPropertyChangedCallback(ForegroundProperty, _foregroundPropertyToken); 73 | this.UnregisterPropertyChangedCallback(PaddingProperty, _paddingPropertyToken); 74 | } 75 | 76 | private void OnActualThemeChanged(object sender, RoutedEventArgs e) 77 | { 78 | RenderMarkdown(); 79 | } 80 | 81 | /// 82 | public override void OnApplyTemplate() 83 | { 84 | _rootElement = GetTemplateChild("RootElement") as Border; 85 | 86 | RenderMarkdown(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/ModernWpf.Toolkit.UI.Controls.Markdown.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0-windows10.0.18362.0;netcoreapp3.1;net462 5 | true 6 | latest 7 | ModernWpf Community Toolkit Controls Markdown 8 | 9 | This library provides a XAML MarkdownTextBlock control, an efficient and extensible control that can parse and render markdown. It is part of the ModernWpf Community Toolkit. 10 | 11 | WPF ModernWpf Toolkit Windows Controls XAML Markdown MarkdownTextBlock 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Markup; 3 | 4 | [assembly: ThemeInfo( 5 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 6 | //(used if a resource is not found in the page, 7 | // or application resource dictionaries) 8 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 9 | //(used if a resource is not found in the page, 10 | // app, or any theme specific resource dictionaries) 11 | )] 12 | 13 | [assembly: XmlnsPrefix("http://schemas.modernwpf.com/toolkit/controls", "controls")] 14 | [assembly: XmlnsDefinition("http://schemas.modernwpf.com/toolkit/controls", "ModernWpf.Toolkit.UI.Controls")] 15 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/BlockCollectionRenderContext.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 Microsoft.Toolkit.Parsers.Markdown.Render; 6 | using System.Windows.Documents; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 9 | { 10 | /// 11 | /// The Context of the Current Document Rendering. 12 | /// 13 | public class BlockCollectionRenderContext : RenderContext 14 | { 15 | internal BlockCollectionRenderContext(BlockCollection blockCollection) 16 | { 17 | BlockCollection = blockCollection; 18 | } 19 | 20 | internal BlockCollectionRenderContext(BlockCollection blockCollection, IRenderContext context) 21 | : this(blockCollection) 22 | { 23 | TrimLeadingWhitespace = context.TrimLeadingWhitespace; 24 | Parent = context.Parent; 25 | 26 | if (context is RenderContext localcontext) 27 | { 28 | Foreground = localcontext.Foreground; 29 | OverrideForeground = localcontext.OverrideForeground; 30 | } 31 | } 32 | 33 | /// 34 | /// Gets or sets the list to add to. 35 | /// 36 | public BlockCollection BlockCollection { get; set; } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/ICodeBlockResolver.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.Windows.Documents; 6 | 7 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 8 | { 9 | /// 10 | /// A Parser to parse code strings into Syntax Highlighted text. 11 | /// 12 | public interface ICodeBlockResolver 13 | { 14 | /// 15 | /// Parses Code Block text into Rich text. 16 | /// 17 | /// Block to add formatted Text to. 18 | /// The raw code block text 19 | /// The language of the Code Block, as specified by ```{Language} on the first line of the block, 20 | /// e.g. 21 | /// ```C# 22 | /// public void Method(); 23 | /// ``` 24 | /// 25 | /// Parsing was handled Successfully 26 | bool ParseSyntax(InlineCollection inlineCollection, string text, string codeLanguage); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/IEmojiInlineResolver.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Documents; 2 | 3 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 4 | { 5 | /// 6 | /// An interface used to resolve emoji inlines. 7 | /// 8 | public interface IEmojiInlineResolver 9 | { 10 | /// 11 | /// Resolves an Emoji inline from a emoji sting. 12 | /// 13 | /// Emoji string to Resolve. 14 | /// Image 15 | Inline ResolveEmojiInline(string emoji); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/IImageResolver.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.Threading.Tasks; 6 | using System.Windows.Media; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 9 | { 10 | /// 11 | /// An interface used to resolve images in the markdown. 12 | /// 13 | public interface IImageResolver 14 | { 15 | /// 16 | /// Resolves an Image from a Url. 17 | /// 18 | /// Url to Resolve. 19 | /// Tooltip for Image. 20 | /// Image 21 | Task ResolveImageAsync(string url, string tooltip); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/ILinkRegister.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 ModernWpf.Controls; 6 | using System.Windows.Documents; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 9 | { 10 | /// 11 | /// An interface used to handle links in the markdown. 12 | /// 13 | public interface ILinkRegister 14 | { 15 | /// 16 | /// Registers a Hyperlink with a LinkUrl. 17 | /// 18 | /// Hyperlink to Register. 19 | /// Url to Register. 20 | void RegisterNewHyperLink(Hyperlink newHyperlink, string linkUrl); 21 | 22 | /// 23 | /// Registers a Hyperlink with a LinkUrl. 24 | /// 25 | /// ImageLink to Register. 26 | /// Url to Register. 27 | /// Is Image an IsHyperlink. 28 | void RegisterNewHyperLink(HyperlinkButton newImagelink, string linkUrl, bool isHyperLink); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/InlineRenderContext.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 Microsoft.Toolkit.Parsers.Markdown.Render; 6 | using System.Windows.Documents; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 9 | { 10 | /// 11 | /// The Context of the Current Document Rendering. 12 | /// 13 | public class InlineRenderContext : RenderContext 14 | { 15 | internal InlineRenderContext(InlineCollection inlineCollection, IRenderContext context) 16 | { 17 | InlineCollection = inlineCollection; 18 | TrimLeadingWhitespace = context.TrimLeadingWhitespace; 19 | Parent = context.Parent; 20 | 21 | if (context is RenderContext localcontext) 22 | { 23 | Foreground = localcontext.Foreground; 24 | OverrideForeground = localcontext.OverrideForeground; 25 | } 26 | 27 | if (context is InlineRenderContext inlinecontext) 28 | { 29 | WithinBold = inlinecontext.WithinBold; 30 | WithinItalics = inlinecontext.WithinItalics; 31 | WithinHyperlink = inlinecontext.WithinHyperlink; 32 | } 33 | } 34 | 35 | /// 36 | /// Gets or sets a value indicating whether the Current Element is being rendered inside an Italics Run. 37 | /// 38 | public bool WithinItalics { get; set; } 39 | 40 | /// 41 | /// Gets or sets a value indicating whether the Current Element is being rendered inside a Bold Run. 42 | /// 43 | public bool WithinBold { get; set; } 44 | 45 | /// 46 | /// Gets or sets a value indicating whether the Current Element is being rendered inside a Link. 47 | /// 48 | public bool WithinHyperlink { get; set; } 49 | 50 | /// 51 | /// Gets or sets the list to add to. 52 | /// 53 | public InlineCollection InlineCollection { get; set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/RenderContext.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 Microsoft.Toolkit.Parsers.Markdown.Render; 6 | using System.Windows.Media; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 9 | { 10 | /// 11 | /// The Context of the Current Position 12 | /// 13 | public abstract class RenderContext : IRenderContext 14 | { 15 | /// 16 | /// Gets or sets the Foreground of the Current Context. 17 | /// 18 | public Brush Foreground { get; set; } 19 | 20 | /// 21 | public bool TrimLeadingWhitespace { get; set; } 22 | 23 | /// 24 | public object Parent { get; set; } 25 | 26 | /// 27 | /// Gets or sets a value indicating whether to override the Foreground Property. 28 | /// 29 | public bool OverrideForeground { get; set; } 30 | 31 | /// 32 | public IRenderContext Clone() 33 | { 34 | return (IRenderContext)MemberwiseClone(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Render/RenderContextIncorrectException.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 | 7 | namespace ModernWpf.Toolkit.UI.Controls.Markdown.Render 8 | { 9 | /// 10 | /// An Exception that occurs when the Render Context is Incorrect. 11 | /// 12 | public class RenderContextIncorrectException : Exception 13 | { 14 | internal RenderContextIncorrectException() 15 | : base("Markdown Render Context missing or incorrect.") 16 | { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/SelectableTextBlock.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Windows; 4 | using System.Windows.Controls; 5 | 6 | namespace ModernWpf.Toolkit.UI.Controls 7 | { 8 | internal class TextEditorWrapper 9 | { 10 | #if NETFRAMEWORK 11 | private static readonly Type TextEditorType = Type.GetType("System.Windows.Documents.TextEditor, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); 12 | #else 13 | private static readonly Type TextEditorType = Type.GetType("System.Windows.Documents.TextEditor, PresentationFramework"); 14 | #endif 15 | private static readonly PropertyInfo IsReadOnlyProp = TextEditorType.GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 16 | private static readonly PropertyInfo TextViewProp = TextEditorType.GetProperty("TextView", BindingFlags.Instance | BindingFlags.NonPublic); 17 | 18 | private static readonly MethodInfo RegisterMethod = TextEditorType.GetMethod("RegisterCommandHandlers", 19 | BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(Type), typeof(bool), typeof(bool), typeof(bool) }, null); 20 | 21 | #if NETFRAMEWORK 22 | private static readonly Type TextContainerType = Type.GetType("System.Windows.Documents.ITextContainer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); 23 | #else 24 | private static readonly Type TextContainerType = Type.GetType("System.Windows.Documents.ITextContainer, PresentationFramework"); 25 | #endif 26 | private static readonly PropertyInfo TextContainerTextViewProp = TextContainerType.GetProperty("TextView"); 27 | 28 | private static readonly PropertyInfo TextContainerProp = typeof(TextBlock).GetProperty("TextContainer", BindingFlags.Instance | BindingFlags.NonPublic); 29 | 30 | public static void RegisterCommandHandlers(Type controlType, bool acceptsRichContent, bool readOnly, bool registerEventListeners) 31 | { 32 | RegisterMethod.Invoke(null, new object[] { controlType, acceptsRichContent, readOnly, registerEventListeners }); 33 | } 34 | 35 | public static TextEditorWrapper CreateFor(TextBlock tb) 36 | { 37 | var textContainer = TextContainerProp.GetValue(tb); 38 | 39 | var editor = new TextEditorWrapper(textContainer, tb, false); 40 | IsReadOnlyProp.SetValue(editor._editor, true); 41 | TextViewProp.SetValue(editor._editor, TextContainerTextViewProp.GetValue(textContainer)); 42 | 43 | return editor; 44 | } 45 | 46 | private readonly object _editor; 47 | 48 | public TextEditorWrapper(object textContainer, FrameworkElement uiScope, bool isUndoEnabled) 49 | { 50 | _editor = Activator.CreateInstance(TextEditorType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, 51 | null, new[] { textContainer, uiScope, isUndoEnabled }, null); 52 | } 53 | } 54 | 55 | internal class SelectableTextBlock : TextBlock 56 | { 57 | static SelectableTextBlock() 58 | { 59 | FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true)); 60 | TextEditorWrapper.RegisterCommandHandlers(typeof(SelectableTextBlock), true, true, true); 61 | } 62 | 63 | public SelectableTextBlock() 64 | { 65 | _ = TextEditorWrapper.CreateFor(this); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls.Markdown/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Eyedropper/Eyedropper.Logic.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 ModernWpf.Toolkit.Extensions; 6 | using ModernWpf.Toolkit.UI.Helpers; 7 | using System; 8 | using System.Diagnostics; 9 | using System.Windows; 10 | using System.Windows.Media; 11 | using System.Windows.Media.Imaging; 12 | 13 | namespace ModernWpf.Toolkit.UI.Controls 14 | { 15 | /// 16 | /// The control can pick up a color from anywhere in your application. 17 | /// 18 | public partial class Eyedropper 19 | { 20 | private void UpdateEyedropper(Point position) 21 | { 22 | if (_appScreenshot == null) 23 | { 24 | return; 25 | } 26 | 27 | #region Updating Layout Transform 28 | 29 | // Updating Y values 30 | if (position.Y > _rootGrid.ActualHeight / 2) 31 | { 32 | _layoutTransform.Y = position.Y - ActualHeight; 33 | } 34 | else 35 | { 36 | _layoutTransform.Y = position.Y; 37 | } 38 | 39 | // Updating X values 40 | if (position.X > _rootGrid.ActualWidth - (ActualWidth / 2) - 15) 41 | { 42 | _layoutTransform.X = _rootGrid.ActualWidth - ActualWidth - 15; 43 | } 44 | else if (position.X < (ActualWidth / 2) + 15) 45 | { 46 | _layoutTransform.X = 15; 47 | } 48 | else 49 | { 50 | _layoutTransform.X = position.X - (ActualWidth / 2); 51 | } 52 | 53 | #endregion 54 | 55 | var x = (int)Math.Ceiling(Math.Min(_appScreenshot.PixelWidth - 1, Math.Max(position.X, 0))); 56 | var y = (int)Math.Ceiling(Math.Min(_appScreenshot.PixelHeight - 1, Math.Max(position.Y, 0))); 57 | Color = _appScreenshot.GetPixelColor(x, y); 58 | UpdatePreview(x, y); 59 | } 60 | 61 | private void UpdateWorkArea() 62 | { 63 | if (_targetGrid == null) 64 | { 65 | return; 66 | } 67 | 68 | var content = (FrameworkElement)OwnerWindow.Content; 69 | if (WorkArea == default) 70 | { 71 | _targetGrid.Margin = default; 72 | } 73 | else 74 | { 75 | var left = WorkArea.Left; 76 | var top = WorkArea.Top; 77 | double right = content.ActualWidth - WorkArea.Right; 78 | double bottom = content.ActualHeight - WorkArea.Bottom; 79 | 80 | _targetGrid.Margin = new Thickness(left, top, right, bottom); 81 | } 82 | } 83 | 84 | private void UpdatePreview(int centerX, int centerY) 85 | { 86 | var halfPixelCountPerRow = (PixelCountPerRow - 1) / 2; 87 | var startX = centerX - halfPixelCountPerRow; 88 | var startY = centerY - halfPixelCountPerRow; 89 | var endX = centerX + halfPixelCountPerRow + 1; 90 | var endY = centerY + halfPixelCountPerRow + 1; 91 | 92 | var size = new Size(PreviewPixelsPerRawPixel, PreviewPixelsPerRawPixel); 93 | Point startPoint = new Point(0, 0); 94 | 95 | var brush = Brushes.Transparent; 96 | var drawingGroup = new DrawingGroup(); 97 | 98 | for (var y = startY; y < endY; y++) 99 | { 100 | startPoint.X = 0; 101 | for (var x = startX; x < endX; x++) 102 | { 103 | var rectangleGeometry = new RectangleGeometry() { Rect = startPoint.ToRect(size) }; 104 | var geometryDrawing = new GeometryDrawing(_appScreenshot.GetPixelBrush(x, y), new Pen(brush, 1.0), rectangleGeometry); 105 | drawingGroup.Children.Add(geometryDrawing); 106 | 107 | startPoint.X += PreviewPixelsPerRawPixel; 108 | } 109 | 110 | startPoint.Y += PreviewPixelsPerRawPixel; 111 | } 112 | 113 | var drawingImage = new DrawingImage(drawingGroup); 114 | drawingImage.Freeze(); 115 | Preview = drawingImage; 116 | } 117 | 118 | internal void UpdateAppScreenshot() 119 | { 120 | FrameworkElement content = (FrameworkElement)OwnerWindow.Content; 121 | int width = (int)Math.Ceiling(content.ActualWidth); 122 | int height = (int)Math.Ceiling(content.ActualHeight); 123 | 124 | try 125 | { 126 | var renderTargetBitmap = new RenderTargetBitmap( 127 | width, height, 128 | 96, 96, PixelFormats.Pbgra32); 129 | renderTargetBitmap.Render(content); 130 | 131 | _appScreenshot = BitmapFrame.Create(renderTargetBitmap); 132 | _appScreenshot.Freeze(); 133 | } 134 | catch (OutOfMemoryException ex) 135 | { 136 | Debug.WriteLine(ex); 137 | } 138 | } 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Eyedropper/Eyedropper.Properties.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.Windows; 6 | using System.Windows.Media; 7 | 8 | namespace ModernWpf.Toolkit.UI.Controls 9 | { 10 | /// 11 | /// The control can pick up a color from anywhere in your application. 12 | /// 13 | public partial class Eyedropper 14 | { 15 | /// 16 | /// Identifies the dependency property. 17 | /// 18 | public static readonly DependencyProperty ColorProperty = 19 | DependencyProperty.Register(nameof(Color), typeof(Color), typeof(Eyedropper), new PropertyMetadata(default(Color), OnColorChanged)); 20 | 21 | /// 22 | /// Identifies the dependency property. 23 | /// 24 | public static readonly DependencyProperty PreviewProperty = 25 | DependencyProperty.Register(nameof(Preview), typeof(ImageSource), typeof(Eyedropper), new PropertyMetadata(default(ImageSource))); 26 | 27 | /// 28 | /// Identifies the dependency property. 29 | /// 30 | public static readonly DependencyProperty WorkAreaProperty = 31 | DependencyProperty.Register(nameof(WorkArea), typeof(Rect), typeof(Eyedropper), new PropertyMetadata(default(Rect), OnWorkAreaChanged)); 32 | 33 | /// 34 | /// Identifies the dependency property. 35 | /// 36 | public static readonly DependencyProperty OwnerWindowProperty = 37 | DependencyProperty.Register(nameof(OwnerWindow), typeof(Window), typeof(Eyedropper), new PropertyMetadata(null, OnOwnerWindowChanged)); 38 | 39 | /// 40 | /// Gets the current color value. 41 | /// 42 | public Color Color 43 | { 44 | get => (Color)GetValue(ColorProperty); 45 | private set => SetValue(ColorProperty, value); 46 | } 47 | 48 | /// 49 | /// Gets the enlarged pixelated preview image. 50 | /// 51 | public ImageSource Preview 52 | { 53 | get => (ImageSource)GetValue(PreviewProperty); 54 | private set => SetValue(PreviewProperty, value); 55 | } 56 | 57 | /// 58 | /// Gets or sets the working area of the eyedropper. 59 | /// 60 | public Rect WorkArea 61 | { 62 | get => (Rect)GetValue(WorkAreaProperty); 63 | set => SetValue(WorkAreaProperty, value); 64 | } 65 | 66 | /// 67 | /// Gets or sets the owner window of the eyedropper. 68 | /// 69 | public Window OwnerWindow 70 | { 71 | get => (Window)GetValue(OwnerWindowProperty); 72 | set => SetValue(OwnerWindowProperty, value); 73 | } 74 | 75 | private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 76 | { 77 | if (d is Eyedropper eyedropper) 78 | { 79 | eyedropper.ColorChanged?.Invoke(eyedropper, new EyedropperColorChangedEventArgs { OldColor = (Color)e.OldValue, NewColor = (Color)e.NewValue }); 80 | } 81 | } 82 | 83 | private static void OnWorkAreaChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 84 | { 85 | if (d is Eyedropper eyedropper) 86 | { 87 | eyedropper.UpdateWorkArea(); 88 | } 89 | } 90 | 91 | private static void OnOwnerWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 92 | { 93 | if (d is Eyedropper eyedropper) 94 | { 95 | eyedropper.UpdateOwnerWindow((Window)e.OldValue); 96 | 97 | if (e.NewValue == null) 98 | { 99 | eyedropper.OwnerWindow = Application.Current?.MainWindow; 100 | return; 101 | } 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Eyedropper/Eyedropper.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Eyedropper/EyedropperColorChangedEventArgs.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.Windows.Media; 6 | 7 | namespace ModernWpf.Toolkit.UI.Controls 8 | { 9 | /// 10 | /// Provides event data for the ColorChanged event. 11 | /// 12 | public sealed class EyedropperColorChangedEventArgs 13 | { 14 | /// 15 | /// Gets the color that is currently selected in the control. 16 | /// 17 | public Color NewColor { get; internal set; } 18 | 19 | /// 20 | /// Gets the color that was previously selected in the control. 21 | /// 22 | public Color OldColor { get; internal set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Eyedropper/EyedropperToolButton.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 ModernWpf.Toolkit.Extensions; 6 | using System; 7 | using System.Windows; 8 | using System.Windows.Controls.Primitives; 9 | 10 | namespace ModernWpf.Toolkit.UI.Controls 11 | { 12 | /// 13 | /// The control helps use in view. 14 | /// 15 | public partial class EyedropperToolButton : ButtonBase 16 | { 17 | private readonly Eyedropper _eyedropper; 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | public EyedropperToolButton() 23 | { 24 | DefaultStyleKey = typeof(EyedropperToolButton); 25 | _eyedropper = new Eyedropper(); 26 | 27 | OwnerWindow = Window.GetWindow(this); 28 | 29 | Loaded += EyedropperToolButton_Loaded; 30 | } 31 | 32 | /// 33 | /// Occurs when the Color property has changed. 34 | /// 35 | public event TypedEventHandler ColorChanged; 36 | 37 | /// 38 | /// Occurs when the eyedropper begins to take color. 39 | /// 40 | public event TypedEventHandler PickStarted; 41 | 42 | /// 43 | /// Occurs when the eyedropper stops to take color. 44 | /// 45 | public event TypedEventHandler PickCompleted; 46 | 47 | private void HookUpEvents() 48 | { 49 | Click -= EyedropperToolButton_Click; 50 | Click += EyedropperToolButton_Click; 51 | Unloaded -= EyedropperToolButton_Unloaded; 52 | Unloaded += EyedropperToolButton_Unloaded; 53 | ThemeManager.RemoveActualThemeChangedHandler(this, EyedropperToolButton_ActualThemeChanged); 54 | ThemeManager.AddActualThemeChangedHandler(this, EyedropperToolButton_ActualThemeChanged); 55 | 56 | _eyedropper.ColorChanged -= Eyedropper_ColorChanged; 57 | _eyedropper.ColorChanged += Eyedropper_ColorChanged; 58 | _eyedropper.PickStarted -= Eyedropper_PickStarted; 59 | _eyedropper.PickStarted += Eyedropper_PickStarted; 60 | _eyedropper.PickCompleted -= Eyedropper_PickCompleted; 61 | _eyedropper.PickCompleted += Eyedropper_PickCompleted; 62 | } 63 | 64 | private void UnhookEvents() 65 | { 66 | Click -= EyedropperToolButton_Click; 67 | Unloaded -= EyedropperToolButton_Unloaded; 68 | 69 | ThemeManager.RemoveActualThemeChangedHandler(this, EyedropperToolButton_ActualThemeChanged); 70 | 71 | _eyedropper.ColorChanged -= Eyedropper_ColorChanged; 72 | _eyedropper.PickStarted -= Eyedropper_PickStarted; 73 | _eyedropper.PickCompleted -= Eyedropper_PickCompleted; 74 | if (TargetElement != null) 75 | { 76 | TargetElement = null; 77 | } 78 | 79 | if (EyedropperEnabled) 80 | { 81 | EyedropperEnabled = false; 82 | } 83 | } 84 | 85 | private void EyedropperToolButton_Loaded(object sender, RoutedEventArgs e) 86 | { 87 | HookUpEvents(); 88 | } 89 | 90 | private void EyedropperToolButton_Unloaded(object sender, RoutedEventArgs e) 91 | { 92 | UnhookEvents(); 93 | } 94 | 95 | private void EyedropperToolButton_ActualThemeChanged(object sender, RoutedEventArgs e) 96 | { 97 | ThemeManager.SetRequestedTheme(_eyedropper, ThemeManager.GetActualTheme(this)); 98 | } 99 | 100 | private void Eyedropper_PickStarted(Eyedropper sender, EventArgs args) 101 | { 102 | PickStarted?.Invoke(this, args); 103 | } 104 | 105 | private void Eyedropper_PickCompleted(Eyedropper sender, EventArgs args) 106 | { 107 | EyedropperEnabled = false; 108 | PickCompleted?.Invoke(this, args); 109 | } 110 | 111 | private void Eyedropper_ColorChanged(Eyedropper sender, EyedropperColorChangedEventArgs args) 112 | { 113 | Color = args.NewColor; 114 | ColorChanged?.Invoke(this, args); 115 | } 116 | 117 | private void EyedropperToolButton_Click(object sender, RoutedEventArgs e) 118 | { 119 | EyedropperEnabled = !EyedropperEnabled; 120 | } 121 | 122 | private void UpdateEyedropperWorkAreaAsync() 123 | { 124 | OwnerWindow ??= Window.GetWindow(this); 125 | if (TargetElement != null && OwnerWindow != null) 126 | { 127 | UIElement content = (UIElement)OwnerWindow.Content; 128 | 129 | var transform = TargetElement.TransformToVisual(content); 130 | var position = transform.Transform(default); 131 | _eyedropper.WorkArea = position.ToRect(new Size(TargetElement.ActualWidth, TargetElement.ActualHeight)); 132 | 133 | _eyedropper.UpdateAppScreenshot(); 134 | } 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/FontIconEx.cs: -------------------------------------------------------------------------------- 1 | using ModernWpf.Controls; 2 | using System; 3 | using System.Reflection; 4 | using System.Windows; 5 | using System.Windows.Controls; 6 | 7 | namespace ModernWpf.Toolkit.UI.Controls 8 | { 9 | /// 10 | /// Represents an icon that uses a glyph from the specified font by specifying either a glyph code or a 's name. 11 | /// 12 | public class FontIconEx : FontIcon 13 | { 14 | static FontIconEx() 15 | { 16 | GlyphProperty.OverrideMetadata(typeof(FontIconEx), new FrameworkPropertyMetadata(OnGlyphChanged)); 17 | } 18 | 19 | /// 20 | /// Initializes a new instance of the FontIconEx class. 21 | /// 22 | public FontIconEx() 23 | { 24 | Loaded += FontIconEx_Loaded; 25 | } 26 | 27 | private static void OnGlyphChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 28 | { 29 | var fontIconEx = (FontIconEx)d; 30 | if (fontIconEx._textBlock2 != null) 31 | { 32 | fontIconEx._textBlock2.Text = GetGlyph((string)e.NewValue); 33 | } 34 | } 35 | 36 | private TextBlock _textBlock2; 37 | 38 | private void FontIconEx_Loaded(object sender, RoutedEventArgs e) 39 | { 40 | if (_textBlock2 == null) 41 | { 42 | _textBlock2 = (TextBlock)typeof(FontIcon).GetField("_textBlock", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(this); 43 | } 44 | 45 | _textBlock2.Text = GetGlyph(Glyph); 46 | } 47 | 48 | private static string GetGlyph(string value) 49 | { 50 | if (Enum.TryParse(value, true, out Symbol symbol)) 51 | { 52 | return ConvertToString(symbol); 53 | } 54 | else 55 | { 56 | return value; 57 | } 58 | } 59 | 60 | private static string ConvertToString(Symbol symbol) 61 | { 62 | return char.ConvertFromUtf32((int)symbol).ToString(); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/ModernWpf.Toolkit.UI.Controls.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0-windows10.0.18362.0;netcoreapp3.1;net462 5 | true 6 | latest 7 | ModernWpf Community Toolkit Controls 8 | 9 | This library provides XAML templated controls. It is part of the ModernWpf Community Toolkit. 10 | 11 | WPF ModernWpf Windows Controls XAML 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Markup; 3 | 4 | [assembly: ThemeInfo( 5 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 6 | //(used if a resource is not found in the page, 7 | // or application resource dictionaries) 8 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 9 | //(used if a resource is not found in the page, 10 | // app, or any theme specific resource dictionaries) 11 | )] 12 | 13 | [assembly: XmlnsPrefix("http://schemas.modernwpf.com/toolkit/controls", "controls")] 14 | [assembly: XmlnsDefinition("http://schemas.modernwpf.com/toolkit/controls", "ModernWpf.Toolkit.UI.Controls")] 15 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/SimpleWrapPanel/SimpleWrapPanel.Data.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 System.Collections.Generic; 7 | using System.Windows; 8 | using System.Windows.Controls; 9 | 10 | namespace ModernWpf.Toolkit.UI.Controls 11 | { 12 | /// 13 | /// SimpleWrapPanel is a panel that position child control vertically or horizontally based on the orientation and when max width/ max height is received a new row(in case of horizontal) or column (in case of vertical) is created to fit new controls. 14 | /// 15 | public partial class SimpleWrapPanel 16 | { 17 | [System.Diagnostics.DebuggerDisplay("U = {U} V = {V}")] 18 | private struct UvMeasure 19 | { 20 | internal static UvMeasure Zero => default; 21 | 22 | internal double U { get; set; } 23 | 24 | internal double V { get; set; } 25 | 26 | public UvMeasure(Orientation orientation, Size size) 27 | : this(orientation, size.Width, size.Height) 28 | { 29 | } 30 | 31 | public UvMeasure(Orientation orientation, double width, double height) 32 | { 33 | if (orientation == Orientation.Horizontal) 34 | { 35 | U = width; 36 | V = height; 37 | } 38 | else 39 | { 40 | U = height; 41 | V = width; 42 | } 43 | } 44 | 45 | public UvMeasure Add(double u, double v) 46 | => new UvMeasure { U = U + u, V = V + v }; 47 | 48 | public UvMeasure Add(UvMeasure measure) 49 | => Add(measure.U, measure.V); 50 | 51 | public Size ToSize(Orientation orientation) 52 | => orientation == Orientation.Horizontal ? new Size(U, V) : new Size(V, U); 53 | } 54 | 55 | private struct UvRect 56 | { 57 | public UvMeasure Position { get; set; } 58 | 59 | public UvMeasure Size { get; set; } 60 | 61 | public Rect ToRect(Orientation orientation) => orientation switch 62 | { 63 | Orientation.Vertical => new Rect(Position.V, Position.U, Size.V, Size.U), 64 | Orientation.Horizontal => new Rect(Position.U, Position.V, Size.U, Size.V), 65 | _ => throw new NotSupportedException("Unsupported Orientation"), 66 | }; 67 | } 68 | 69 | private struct Row 70 | { 71 | public Row(List childrenRects, UvMeasure size) 72 | { 73 | ChildrenRects = childrenRects; 74 | Size = size; 75 | } 76 | 77 | public List ChildrenRects { get; } 78 | 79 | public UvMeasure Size { get; set; } 80 | 81 | public UvRect Rect => ChildrenRects.Count > 0 ? 82 | new UvRect { Position = ChildrenRects[0].Position, Size = Size } : 83 | new UvRect { Position = UvMeasure.Zero, Size = Size }; 84 | 85 | public void Add(UvMeasure position, UvMeasure size) 86 | { 87 | ChildrenRects.Add(new UvRect { Position = position, Size = size }); 88 | Size = new UvMeasure 89 | { 90 | U = position.U + size.U, 91 | V = Math.Max(Size.V, size.V), 92 | }; 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/SimpleWrapPanel/StretchChild.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 | namespace ModernWpf.Toolkit.UI.Controls 6 | { 7 | /// 8 | /// Options for how to calculate the layout of items. 9 | /// 10 | public enum StretchChild 11 | { 12 | /// 13 | /// Don't apply any additional stretching logic 14 | /// 15 | None, 16 | 17 | /// 18 | /// Make the last child stretch to fill the available space 19 | /// 20 | Last 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI.Controls/Themes/Generic.xaml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/BoolNegationConverter.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 System.Globalization; 7 | using System.Windows.Data; 8 | 9 | namespace ModernWpf.Toolkit.UI.Converters 10 | { 11 | /// 12 | /// Value converter that applies NOT operator to a value. 13 | /// 14 | public class BoolNegationConverter : IValueConverter 15 | { 16 | /// 17 | /// Convert a boolean value to its negation. 18 | /// 19 | /// The value to negate. 20 | /// The type of the target property, as a type reference. 21 | /// Optional parameter. Not used. 22 | /// The language of the conversion. Not used 23 | /// The value to be passed to the target dependency property. 24 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 25 | { 26 | return !(value is bool boolean && boolean); 27 | } 28 | 29 | /// 30 | /// Convert back a boolean value to its negation. 31 | /// 32 | /// The value to negate. 33 | /// The type of the target property, as a type reference. 34 | /// Optional parameter. Not used. 35 | /// The language of the conversion. Not used 36 | /// The value to be passed to the target dependency property. 37 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 38 | { 39 | return !(value is bool boolean && boolean); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/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 System.Globalization; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace ModernWpf.Toolkit.UI.Converters 11 | { 12 | /// 13 | /// This class converts a boolean value into an other object. 14 | /// Can be used to convert true/false to visibility, a couple of colors, couple of images, etc. 15 | /// 16 | public class BoolToObjectConverter : DependencyObject, IValueConverter 17 | { 18 | /// 19 | /// Identifies the property. 20 | /// 21 | public static readonly DependencyProperty TrueValueProperty = 22 | DependencyProperty.Register(nameof(TrueValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null)); 23 | 24 | /// 25 | /// Identifies the property. 26 | /// 27 | public static readonly DependencyProperty FalseValueProperty = 28 | DependencyProperty.Register(nameof(FalseValue), typeof(object), typeof(BoolToObjectConverter), new PropertyMetadata(null)); 29 | 30 | /// 31 | /// Gets or sets the value to be returned when the boolean is true 32 | /// 33 | public object TrueValue 34 | { 35 | get { return GetValue(TrueValueProperty); } 36 | set { SetValue(TrueValueProperty, value); } 37 | } 38 | 39 | /// 40 | /// Gets or sets the value to be returned when the boolean is false 41 | /// 42 | public object FalseValue 43 | { 44 | get { return GetValue(FalseValueProperty); } 45 | set { SetValue(FalseValueProperty, value); } 46 | } 47 | 48 | /// 49 | /// Convert a boolean value to an other object. 50 | /// 51 | /// The source data being passed to the target. 52 | /// The type of the target property, as a type reference. 53 | /// An optional parameter to be used to invert the converter logic. 54 | /// The language of the conversion. 55 | /// The value to be passed to the target dependency property. 56 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 57 | { 58 | bool boolValue = value is bool boolean && boolean; 59 | 60 | // Negate if needed 61 | if (ConverterTools.TryParseBool(parameter)) 62 | { 63 | boolValue = !boolValue; 64 | } 65 | 66 | return ConverterTools.Convert(boolValue ? TrueValue : FalseValue, targetType); 67 | } 68 | 69 | /// 70 | /// Convert back the value to a boolean 71 | /// 72 | /// If the parameter is a reference type, must match its reference to return true. 73 | /// The target data being passed to the source. 74 | /// 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)). 75 | /// An optional parameter to be used to invert the converter logic. 76 | /// The language of the conversion. 77 | /// The value to be passed to the source object. 78 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 79 | { 80 | bool result = Equals(value, ConverterTools.Convert(TrueValue, value.GetType())); 81 | 82 | if (ConverterTools.TryParseBool(parameter)) 83 | { 84 | result = !result; 85 | } 86 | 87 | return result; 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/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 System.Windows; 6 | 7 | namespace ModernWpf.Toolkit.UI.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 | } 24 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/CollectionVisibilityConverter.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.Windows; 6 | 7 | namespace ModernWpf.Toolkit.UI.Converters 8 | { 9 | /// 10 | /// This class converts a collection size to visibility. 11 | /// 12 | public class CollectionVisibilityConverter : EmptyCollectionToObjectConverter 13 | { 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | public CollectionVisibilityConverter() 18 | { 19 | NotEmptyValue = Visibility.Visible; 20 | EmptyValue = Visibility.Collapsed; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/ConverterTools.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 | 7 | namespace ModernWpf.Toolkit.UI.Converters 8 | { 9 | /// 10 | /// Static class used to provide internal tools 11 | /// 12 | internal static class ConverterTools 13 | { 14 | /// 15 | /// Helper method to safely cast an object to a boolean 16 | /// 17 | /// Parameter to cast to a boolean 18 | /// Bool value or false if cast failed 19 | internal static bool TryParseBool(object parameter) 20 | { 21 | var parsed = false; 22 | if (parameter != null) 23 | { 24 | bool.TryParse(parameter.ToString(), out parsed); 25 | } 26 | 27 | return parsed; 28 | } 29 | 30 | /// 31 | /// Helper method to convert a value from a source type to a target type. 32 | /// 33 | /// The value to convert 34 | /// The target type 35 | /// The converted value 36 | internal static object Convert(object value, Type targetType) 37 | { 38 | if (targetType.IsInstanceOfType(value)) 39 | { 40 | return value; 41 | } 42 | else 43 | { 44 | return value; 45 | } 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/DoubleToVisibilityConverter.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.ComponentModel; 6 | using System.Windows; 7 | 8 | namespace ModernWpf.Toolkit.UI.Converters 9 | { 10 | /// 11 | /// This class converts a double value into a Visibility enumeration. 12 | /// 13 | [Bindable(true)] 14 | public class DoubleToVisibilityConverter : DoubleToObjectConverter 15 | { 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | public DoubleToVisibilityConverter() 20 | { 21 | TrueValue = Visibility.Visible; 22 | FalseValue = Visibility.Collapsed; 23 | NullValue = Visibility.Collapsed; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/EmptyCollectionToObjectConverter.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.Collections; 6 | 7 | namespace ModernWpf.Toolkit.UI.Converters 8 | { 9 | /// 10 | /// This class converts a collection size into an other object. 11 | /// Can be used to convert to bind a visibility, a color or an image to the size of the collection. 12 | /// 13 | public class EmptyCollectionToObjectConverter : EmptyObjectToObjectConverter 14 | { 15 | /// 16 | /// Checks collection for emptiness. 17 | /// 18 | /// Value to be checked. 19 | /// True if value is an empty collection or does not implement IEnumerable, false otherwise. 20 | protected override bool CheckValueIsEmpty(object value) 21 | { 22 | bool isEmpty = true; 23 | if (value is IEnumerable collection) 24 | { 25 | var enumerator = collection.GetEnumerator(); 26 | isEmpty = !enumerator.MoveNext(); 27 | } 28 | 29 | return isEmpty; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/EmptyObjectToObjectConverter.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 System.Globalization; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace ModernWpf.Toolkit.UI.Converters 11 | { 12 | /// 13 | /// This class converts an object value into a an object (if the value is null returns the false value). 14 | /// Can be used to bind a visibility, a color or an image to the value of an object. 15 | /// 16 | public class EmptyObjectToObjectConverter : DependencyObject, IValueConverter 17 | { 18 | /// 19 | /// Identifies the property. 20 | /// 21 | public static readonly DependencyProperty NotEmptyValueProperty = 22 | DependencyProperty.Register(nameof(NotEmptyValue), typeof(object), typeof(EmptyObjectToObjectConverter), new PropertyMetadata(null)); 23 | 24 | /// 25 | /// Identifies the property. 26 | /// 27 | public static readonly DependencyProperty EmptyValueProperty = 28 | DependencyProperty.Register(nameof(EmptyValue), typeof(object), typeof(EmptyObjectToObjectConverter), new PropertyMetadata(null)); 29 | 30 | /// 31 | /// Gets or sets the value to be returned when the object is neither null nor empty 32 | /// 33 | public object NotEmptyValue 34 | { 35 | get { return GetValue(NotEmptyValueProperty); } 36 | set { SetValue(NotEmptyValueProperty, value); } 37 | } 38 | 39 | /// 40 | /// Gets or sets the value to be returned when the object is either null or empty 41 | /// 42 | public object EmptyValue 43 | { 44 | get { return GetValue(EmptyValueProperty); } 45 | set { SetValue(EmptyValueProperty, value); } 46 | } 47 | 48 | /// 49 | /// Convert a boolean value to an other object. 50 | /// 51 | /// The source data being passed to the target. 52 | /// The type of the target property, as a type reference. 53 | /// An optional parameter to be used to invert the converter logic. 54 | /// The language of the conversion. 55 | /// The value to be passed to the target dependency property. 56 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 57 | { 58 | var isEmpty = CheckValueIsEmpty(value); 59 | 60 | // Negate if needed 61 | if (ConverterTools.TryParseBool(parameter)) 62 | { 63 | isEmpty = !isEmpty; 64 | } 65 | 66 | return ConverterTools.Convert(isEmpty ? EmptyValue : NotEmptyValue, targetType); 67 | } 68 | 69 | /// 70 | /// Not implemented 71 | /// 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, CultureInfo culture) 78 | { 79 | throw new NotImplementedException(); 80 | } 81 | 82 | /// 83 | /// Checks value for emptiness. 84 | /// 85 | /// Value to be checked. 86 | /// True if value is null, false otherwise. 87 | protected virtual bool CheckValueIsEmpty(object value) 88 | { 89 | return value == null; 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/EmptyStringToObjectConverter.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 | namespace ModernWpf.Toolkit.UI.Converters 6 | { 7 | /// 8 | /// This class converts a string value into a an object (if the value is null or empty returns the false value). 9 | /// Can be used to bind a visibility, a color or an image to the value of a string. 10 | /// 11 | public class EmptyStringToObjectConverter : EmptyObjectToObjectConverter 12 | { 13 | /// 14 | /// Checks string for emptiness. 15 | /// 16 | /// Value to be checked. 17 | /// True if value is null or empty string, false otherwise. 18 | protected override bool CheckValueIsEmpty(object value) 19 | { 20 | return string.IsNullOrEmpty(value?.ToString()); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/FileSizeToFriendlyStringConverter.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 System.Globalization; 7 | using System.Windows.Data; 8 | 9 | namespace ModernWpf.Toolkit.UI.Converters 10 | { 11 | /// 12 | /// Converts a file size in bytes to a more human-readable friendly format using 13 | /// 14 | public class FileSizeToFriendlyStringConverter : IValueConverter 15 | { 16 | /// 17 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 18 | { 19 | if (value is long size) 20 | { 21 | return Toolkit.Converters.ToFileSizeString(size); 22 | } 23 | 24 | return string.Empty; 25 | } 26 | 27 | /// 28 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 29 | { 30 | throw new NotImplementedException(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/FormatStringConverter.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 System.Globalization; 7 | using System.Windows.Data; 8 | 9 | namespace ModernWpf.Toolkit.UI.Converters 10 | { 11 | /// 12 | /// Value converter that converts an to a formatted . 13 | /// The string format needs to be passed as the converter parameter. 14 | /// 15 | public class FormatStringConverter : IValueConverter 16 | { 17 | /// 18 | /// Convert an value to a formatted . 19 | /// 20 | /// The source data being passed to the target. 21 | /// The type of the target property, as a type reference. 22 | /// The format string. 23 | /// The language of the conversion. Not used. 24 | /// The formatted string. 25 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | if (!(value is IFormattable formattableValue) || !(parameter is string format)) 28 | { 29 | return value; 30 | } 31 | 32 | return formattableValue.ToString(format, null); 33 | } 34 | 35 | /// 36 | /// Not implemented. 37 | /// 38 | /// The source data being passed to the target. 39 | /// The type of the target property, as a type reference. 40 | /// Optional parameter. Not used. 41 | /// The language of the conversion. Not used. 42 | /// The value to be passed to the target dependency property. 43 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 44 | { 45 | throw new NotImplementedException(); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/StringFormatConverter.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 System.Globalization; 7 | using System.Windows.Data; 8 | 9 | namespace ModernWpf.Toolkit.UI.Converters 10 | { 11 | /// 12 | /// This class provides a binding converter to display formatted strings 13 | /// 14 | public class StringFormatConverter : IValueConverter 15 | { 16 | /// 17 | /// Return the formatted string version of the source object. 18 | /// 19 | /// Object to transform to string. 20 | /// The type of the target property, as a type reference 21 | /// An optional parameter to be used in the string.Format method. 22 | /// The language of the conversion (not used). 23 | /// Formatted string. 24 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 25 | { 26 | if (value == null) 27 | { 28 | return null; 29 | } 30 | 31 | if (parameter == null) 32 | { 33 | return value; 34 | } 35 | 36 | try 37 | { 38 | return string.Format((string)parameter, value); 39 | } 40 | catch 41 | { 42 | } 43 | 44 | return value; 45 | } 46 | 47 | /// 48 | /// Not implemented. 49 | /// 50 | /// The target data being passed to the source. 51 | /// 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)). 52 | /// An optional parameter to be used in the converter logic. 53 | /// The language of the conversion. 54 | /// The value to be passed to the source object. 55 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 56 | { 57 | throw new NotImplementedException(); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/StringVisibilityConverter.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.Windows; 6 | 7 | namespace ModernWpf.Toolkit.UI.Converters 8 | { 9 | /// 10 | /// This class converts a string value into a Visibility value (if the value is null or empty returns a collapsed value). 11 | /// 12 | public class StringVisibilityConverter : EmptyStringToObjectConverter 13 | { 14 | /// 15 | /// Initializes a new instance of the class. 16 | /// 17 | public StringVisibilityConverter() 18 | { 19 | NotEmptyValue = Visibility.Visible; 20 | EmptyValue = Visibility.Collapsed; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/TypeToObjectConverter.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 System.Globalization; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace ModernWpf.Toolkit.UI.Converters 11 | { 12 | /// 13 | /// This class returns an object or another, depending on whether the type of the provided value matches another provided Type. 14 | /// 15 | public class TypeToObjectConverter : DependencyObject, IValueConverter 16 | { 17 | /// 18 | /// Identifies the property. 19 | /// 20 | public static readonly DependencyProperty TrueValueProperty = 21 | DependencyProperty.Register(nameof(TrueValue), typeof(object), typeof(TypeToObjectConverter), new PropertyMetadata(null)); 22 | 23 | /// 24 | /// Identifies the property. 25 | /// 26 | public static readonly DependencyProperty FalseValueProperty = 27 | DependencyProperty.Register(nameof(FalseValue), typeof(object), typeof(TypeToObjectConverter), new PropertyMetadata(null)); 28 | 29 | /// 30 | /// Identifies the property. 31 | /// 32 | public static readonly DependencyProperty TypeProperty = 33 | DependencyProperty.Register(nameof(Type), typeof(Type), typeof(TypeToObjectConverter), new PropertyMetadata(typeof(object))); 34 | 35 | /// 36 | /// Gets or sets the value to be returned when the type of the provided value matches . 37 | /// 38 | public object TrueValue 39 | { 40 | get { return GetValue(TrueValueProperty); } 41 | set { SetValue(TrueValueProperty, value); } 42 | } 43 | 44 | /// 45 | /// Gets or sets the value to be returned when the type of the provided value does not match . 46 | /// 47 | public object FalseValue 48 | { 49 | get { return GetValue(FalseValueProperty); } 50 | set { SetValue(FalseValueProperty, value); } 51 | } 52 | 53 | /// 54 | /// Gets or sets the Type used to compare the type of the provided value. 55 | /// 56 | public Type Type 57 | { 58 | get { return (Type)GetValue(TypeProperty); } 59 | set { SetValue(TypeProperty, value); } 60 | } 61 | 62 | /// 63 | /// Convert the 's Type to an other object. 64 | /// 65 | /// The source data being passed to the target. 66 | /// The type of the target property, as a type reference. 67 | /// An optional parameter to be used to invert the converter logic. 68 | /// The language of the conversion. 69 | /// The value to be passed to the target dependency property. 70 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 71 | { 72 | var typeMatches = value != null && Type.Equals(value.GetType()); 73 | 74 | // Negate if needed 75 | if (ConverterTools.TryParseBool(parameter)) 76 | { 77 | typeMatches = !typeMatches; 78 | } 79 | 80 | return ConverterTools.Convert(typeMatches ? TrueValue : FalseValue, targetType); 81 | } 82 | 83 | /// 84 | /// Not implemented. 85 | /// 86 | /// The source data being passed to the target. 87 | /// The type of the target property, as a type reference. 88 | /// Optional parameter. Not used. 89 | /// The language of the conversion. Not used. 90 | /// The value to be passed to the target dependency property. 91 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 92 | { 93 | throw new NotImplementedException(); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Converters/VisibilityToBoolConverter.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 System.Globalization; 7 | using System.Windows; 8 | using System.Windows.Data; 9 | 10 | namespace ModernWpf.Toolkit.UI.Converters 11 | { 12 | /// 13 | /// This class converts a Visibility enumeration to a boolean value. 14 | /// 15 | public class VisibilityToBoolConverter : IValueConverter 16 | { 17 | /// 18 | /// Convert a value to boolean. 19 | /// 20 | /// The value to convert. 21 | /// The type of the target property, as a type reference. 22 | /// Optional parameter. Not used. 23 | /// The language of the conversion. Not used 24 | /// The value to be passed to the target dependency property. 25 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 26 | { 27 | return value is Visibility visibility && visibility == Visibility.Visible; 28 | } 29 | 30 | /// 31 | /// Convert back a boolean value to . 32 | /// 33 | /// The value to convert back. 34 | /// The type of the target property, as a type reference. 35 | /// Optional parameter. Not used. 36 | /// The language of the conversion. Not used 37 | /// The value to be passed to the target dependency property. 38 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 39 | { 40 | return (value is bool bl && bl) ? Visibility.Visible : Visibility.Collapsed; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Deferred/TypedEventHandlerExtensions.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 System.Linq; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace ModernWpf.Toolkit.Deferred 11 | { 12 | /// 13 | /// Extensions to for Deferred Events. 14 | /// 15 | public static class TypedEventHandlerExtensions 16 | { 17 | /// 18 | /// Use to invoke an async using . 19 | /// 20 | /// Type of sender. 21 | /// type. 22 | /// to be invoked. 23 | /// Sender of the event. 24 | /// instance. 25 | /// to wait on deferred event handler. 26 | public static Task InvokeAsync(this TypedEventHandler eventHandler, S sender, R eventArgs) 27 | where R : DeferredEventArgs 28 | { 29 | return InvokeAsync(eventHandler, sender, eventArgs, CancellationToken.None); 30 | } 31 | 32 | /// 33 | /// Use to invoke an async using with a . 34 | /// 35 | /// Type of sender. 36 | /// type. 37 | /// to be invoked. 38 | /// Sender of the event. 39 | /// instance. 40 | /// option. 41 | /// to wait on deferred event handler. 42 | public static Task InvokeAsync(this TypedEventHandler eventHandler, S sender, R eventArgs, CancellationToken cancellationToken) 43 | where R : DeferredEventArgs 44 | { 45 | if (eventHandler == null) 46 | { 47 | return Task.CompletedTask; 48 | } 49 | 50 | var tasks = eventHandler.GetInvocationList() 51 | .OfType>() 52 | .Select(invocationDelegate => 53 | { 54 | cancellationToken.ThrowIfCancellationRequested(); 55 | 56 | invocationDelegate(sender, eventArgs); 57 | 58 | var deferral = eventArgs.GetCurrentDeferralAndReset(); 59 | 60 | return deferral?.WaitForCompletion(cancellationToken) ?? Task.CompletedTask; 61 | }) 62 | .ToArray(); 63 | 64 | return Task.WhenAll(tasks); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/DependencyPropertyChangedCallback.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace ModernWpf 4 | { 5 | public delegate void DependencyPropertyChangedCallback(DependencyObject sender, DependencyProperty dp); 6 | } 7 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/DependencyObjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Windows; 5 | 6 | namespace ModernWpf.Toolkit.UI.Extensions 7 | { 8 | public static class DependencyObjectExtensions 9 | { 10 | private static Dictionary descriptors = new Dictionary(); 11 | 12 | public static long RegisterPropertyChangedCallback(this DependencyObject dependencyObject, DependencyProperty dependencyProperty, DependencyPropertyChangedCallback callback) 13 | { 14 | long token = descriptors.Count + 1; 15 | var descriptor = DependencyPropertyDescriptor.FromProperty(dependencyProperty, dependencyObject.GetType()); 16 | EventHandler handler = (s, e) => 17 | { 18 | callback.Invoke(dependencyObject, dependencyProperty); 19 | }; 20 | 21 | descriptors.Add(token, (descriptor, handler)); 22 | 23 | descriptor.AddValueChanged(dependencyObject, handler); 24 | return token; 25 | } 26 | 27 | public static void UnregisterPropertyChangedCallback(this DependencyObject dependencyObject, DependencyProperty dependencyProperty, long token) 28 | { 29 | if (descriptors.TryGetValue(token, out (DependencyPropertyDescriptor Descriptor, EventHandler Handler) value)) 30 | { 31 | value.Descriptor.RemoveValueChanged(dependencyObject, value.Handler); 32 | descriptors.Remove(token); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/DispatcherTimerExtensions.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 System.Collections.Concurrent; 7 | using System.Windows.Threading; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | /// 12 | /// Set of extention methods for using . 13 | /// 14 | public static class DispatcherTimerExtensions 15 | { 16 | private static ConcurrentDictionary _debounceInstances = new ConcurrentDictionary(); 17 | 18 | /// 19 | /// Used to debounce (rate-limit) an event. The action will be postponed and executed after the interval has elapsed. At the end of the interval, the function will be called with the arguments that were passed most recently to the debounced function. 20 | /// Use this method to control the timer instead of calling Start/Interval/Stop manually. 21 | /// A scheduled debounce can still be stopped by calling the stop method on the timer instance. 22 | /// Each timer can only have one debounced function limited at a time. 23 | /// 24 | /// Timer instance, only one debounced function can be used per timer. 25 | /// Action to execute at the end of the interval. 26 | /// Interval to wait before executing the action. 27 | /// Determines if the action execute on the leading edge instead of trailing edge. 28 | /// 29 | /// 30 | /// private DispatcherTimer _typeTimer = new DispatcherTimer(); 31 | /// 32 | /// _typeTimer.Debounce(async () => 33 | /// { 34 | /// // Only executes this code after 0.3 seconds have elapsed since last trigger. 35 | /// }, TimeSpan.FromSeconds(0.3)); 36 | /// 37 | /// 38 | public static void Debounce(this DispatcherTimer timer, Action action, TimeSpan interval, bool immediate = false) 39 | { 40 | // Check and stop any existing timer 41 | var timeout = timer.IsEnabled; 42 | if (timeout) 43 | { 44 | timer.Stop(); 45 | } 46 | 47 | // Reset timer parameters 48 | timer.Tick -= Timer_Tick; 49 | timer.Interval = interval; 50 | 51 | if (immediate) 52 | { 53 | // If we're in immediate mode then we only execute if the timer wasn't running beforehand 54 | if (!timeout) 55 | { 56 | action.Invoke(); 57 | } 58 | } 59 | else 60 | { 61 | // If we're not in immediate mode, then we'll execute when the current timer expires. 62 | timer.Tick += Timer_Tick; 63 | 64 | // Store/Update function 65 | _debounceInstances.AddOrUpdate(timer, action, (k, v) => v); 66 | } 67 | 68 | // Start the timer to keep track of the last call here. 69 | timer.Start(); 70 | } 71 | 72 | private static void Timer_Tick(object sender, object e) 73 | { 74 | // This event is only registered/run if we weren't in immediate mode above 75 | if (sender is DispatcherTimer timer) 76 | { 77 | timer.Tick -= Timer_Tick; 78 | timer.Stop(); 79 | 80 | if (_debounceInstances.TryRemove(timer, out Action action)) 81 | { 82 | action?.Invoke(); 83 | } 84 | } 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/FrameworkElement/FrameworkElementExtensions.RelativeAncestor.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 System.Windows; 7 | 8 | namespace ModernWpf.Toolkit.UI.Extensions 9 | { 10 | /// 11 | /// Provides attached dependency properties for the 12 | /// 13 | public static partial class FrameworkElementExtensions 14 | { 15 | /// 16 | /// Retrieves the parent object of this framework element found of the given . 17 | /// 18 | /// FrameworkElement 19 | /// Parent object 20 | public static object GetAncestor(DependencyObject obj) 21 | { 22 | return obj.GetValue(AncestorProperty); 23 | } 24 | 25 | /// 26 | /// Sets the parent object of the framework element (internal). 27 | /// 28 | /// Parent object 29 | /// FrameworkElement 30 | public static void SetAncestor(DependencyObject obj, object value) 31 | { 32 | obj.SetValue(AncestorProperty, value); 33 | } 34 | 35 | /// 36 | /// Attached for retrieving a parent for the 37 | /// 38 | public static readonly DependencyProperty AncestorProperty = 39 | DependencyProperty.RegisterAttached("Ancestor", typeof(object), typeof(FrameworkElementExtensions), new PropertyMetadata(null)); 40 | 41 | /// 42 | /// Gets the Type of Ancestor to look for from this element. 43 | /// 44 | /// Type of Ancestor to look for from this element 45 | public static Type GetAncestorType(DependencyObject obj) 46 | { 47 | return (Type)obj.GetValue(AncestorTypeProperty); 48 | } 49 | 50 | /// 51 | /// Sets the to look for from this element and place in the . 52 | /// 53 | public static void SetAncestorType(DependencyObject obj, Type value) 54 | { 55 | obj.SetValue(AncestorTypeProperty, value); 56 | } 57 | 58 | /// 59 | /// Attached for retrieving a parent for the based on the provided in the . 60 | /// 61 | public static readonly DependencyProperty AncestorTypeProperty = 62 | DependencyProperty.RegisterAttached("AncestorType", typeof(Type), typeof(FrameworkElementExtensions), new PropertyMetadata(null, AncestorType_PropertyChanged)); 63 | 64 | private static void AncestorType_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) 65 | { 66 | if (obj is FrameworkElement fe) 67 | { 68 | fe.Loaded -= FrameworkElement_Loaded; 69 | 70 | if (args.NewValue != null) 71 | { 72 | fe.Loaded += FrameworkElement_Loaded; 73 | if (fe.Parent != null) 74 | { 75 | FrameworkElement_Loaded(fe, null); 76 | } 77 | } 78 | } 79 | } 80 | 81 | private static void FrameworkElement_Loaded(object sender, RoutedEventArgs e) 82 | { 83 | if (sender is FrameworkElement fe) 84 | { 85 | SetAncestor(fe, fe.FindAscendant(GetAncestorType(fe))); 86 | } 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/Abstract/TextIconExtension.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 System.Windows; 7 | using System.Windows.Markup; 8 | using System.Windows.Media; 9 | 10 | namespace ModernWpf.Toolkit.UI.Extensions 11 | { 12 | /// 13 | /// An abstract which to produce text-based icons. 14 | /// 15 | public abstract class TextIconExtension : MarkupExtension 16 | { 17 | /// 18 | /// Gets or sets the size of the icon to display. 19 | /// 20 | public double FontSize { get; set; } 21 | 22 | [ThreadStatic] 23 | private static FontFamily segoeMDL2AssetsFontFamily; 24 | 25 | /// 26 | /// Gets the reusable "Segoe MDL2 Assets" instance. 27 | /// 28 | protected static FontFamily SegoeMDL2AssetsFontFamily 29 | { 30 | get => segoeMDL2AssetsFontFamily ??= new FontFamily("Segoe MDL2 Assets"); 31 | } 32 | 33 | /// 34 | /// Gets or sets the thickness of the icon glyph. 35 | /// 36 | public FontWeight FontWeight { get; set; } = FontWeights.Normal; 37 | 38 | /// 39 | /// Gets or sets the font style for the icon glyph. 40 | /// 41 | public FontStyle FontStyle { get; set; } = FontStyles.Normal; 42 | 43 | /// 44 | /// Gets or sets the foreground for the icon. 45 | /// 46 | public Brush Foreground { get; set; } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/BitmapIconExtension.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows.Markup; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | /// 12 | /// Custom which can provide values. 13 | /// 14 | [MarkupExtensionReturnType(typeof(BitmapIcon))] 15 | public sealed class BitmapIconExtension : MarkupExtension 16 | { 17 | /// 18 | /// Gets or sets the representing the image to display. 19 | /// 20 | public Uri Source { get; set; } 21 | 22 | /// 23 | /// Gets or sets a value indicating whether to display the icon as monochrome. 24 | /// 25 | public bool ShowAsMonochrome { get; set; } 26 | 27 | /// 28 | public override object ProvideValue(IServiceProvider serviceProvider) 29 | { 30 | return new BitmapIcon 31 | { 32 | ShowAsMonochrome = ShowAsMonochrome, 33 | UriSource = Source 34 | }; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/BitmapIconSourceExtension.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows.Markup; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | /// 12 | /// Custom which can provide values. 13 | /// 14 | [MarkupExtensionReturnType(typeof(BitmapIconSource))] 15 | public sealed class BitmapIconSourceExtension : MarkupExtension 16 | { 17 | /// 18 | /// Gets or sets the representing the image to display. 19 | /// 20 | public Uri Source { get; set; } 21 | 22 | /// 23 | /// Gets or sets a value indicating whether to display the icon as monochrome. 24 | /// 25 | public bool ShowAsMonochrome { get; set; } 26 | 27 | /// 28 | public override object ProvideValue(IServiceProvider serviceProvider) 29 | { 30 | return new BitmapIconSource 31 | { 32 | ShowAsMonochrome = ShowAsMonochrome, 33 | UriSource = Source 34 | }; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/EnumValuesExtension.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 System.Windows.Markup; 7 | 8 | namespace ModernWpf.Toolkit.UI.Extensions 9 | { 10 | /// 11 | /// A markup extension that returns a collection of values of a specific 12 | /// 13 | [MarkupExtensionReturnType(typeof(Array))] 14 | public sealed class EnumValuesExtension : MarkupExtension 15 | { 16 | /// 17 | /// Gets or sets the of the target 18 | /// 19 | public Type Type { get; set; } 20 | 21 | /// 22 | public override object ProvideValue(IServiceProvider serviceProvider) => Enum.GetValues(Type); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/FontIconExtension.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows.Markup; 8 | using System.Windows.Media; 9 | 10 | namespace ModernWpf.Toolkit.UI.Extensions 11 | { 12 | /// 13 | /// Custom which can provide values. 14 | /// 15 | [MarkupExtensionReturnType(typeof(FontIcon))] 16 | public class FontIconExtension : TextIconExtension 17 | { 18 | /// 19 | /// Gets or sets the value representing the icon to display. 20 | /// 21 | public string Glyph { get; set; } 22 | 23 | /// 24 | /// Gets or sets the font family to use to display the icon. If , "Segoe MDL2 Assets" will be used. 25 | /// 26 | public FontFamily FontFamily { get; set; } 27 | 28 | /// 29 | public override object ProvideValue(IServiceProvider serviceProvider) 30 | { 31 | var fontIcon = new FontIcon 32 | { 33 | Glyph = Glyph, 34 | FontFamily = FontFamily ?? SegoeMDL2AssetsFontFamily, 35 | FontWeight = FontWeight, 36 | FontStyle = FontStyle 37 | }; 38 | 39 | if (FontSize > 0) 40 | { 41 | fontIcon.FontSize = FontSize; 42 | } 43 | 44 | if (Foreground != null) 45 | { 46 | fontIcon.Foreground = Foreground; 47 | } 48 | 49 | return fontIcon; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/FontIconSourceExtension.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows.Markup; 8 | using System.Windows.Media; 9 | 10 | namespace ModernWpf.Toolkit.UI.Extensions 11 | { 12 | /// 13 | /// Custom which can provide values. 14 | /// 15 | [MarkupExtensionReturnType(typeof(FontIconSource))] 16 | public class FontIconSourceExtension : TextIconExtension 17 | { 18 | /// 19 | /// Gets or sets the value representing the icon to display. 20 | /// 21 | public string Glyph { get; set; } 22 | 23 | /// 24 | /// Gets or sets the font family to use to display the icon. If , "Segoe MDL2 Assets" will be used. 25 | /// 26 | public FontFamily FontFamily { get; set; } 27 | 28 | /// 29 | public override object ProvideValue(IServiceProvider serviceProvider) 30 | { 31 | var fontIcon = new FontIconSource 32 | { 33 | Glyph = Glyph, 34 | FontFamily = FontFamily ?? SegoeMDL2AssetsFontFamily, 35 | FontWeight = FontWeight, 36 | FontStyle = FontStyle 37 | }; 38 | 39 | if (FontSize > 0) 40 | { 41 | fontIcon.FontSize = FontSize; 42 | } 43 | 44 | if (Foreground != null) 45 | { 46 | fontIcon.Foreground = Foreground; 47 | } 48 | 49 | return fontIcon; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/NullableBool.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 System.ComponentModel; 7 | using System.Windows.Markup; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | /// 12 | /// Custom which can provide nullable bool values. 13 | /// See https://wpdev.uservoice.com/forums/110705-universal-windows-platform/suggestions/17767198-nullable-dependency-properties. 14 | /// 15 | [Bindable(true)] 16 | [MarkupExtensionReturnType(typeof(bool?))] 17 | public class NullableBool : MarkupExtension 18 | { 19 | /// 20 | /// Gets or sets a value indicating whether the value of the Boolean is true. Ignored if is true. 21 | /// 22 | public bool Value { get; set; } 23 | 24 | /// 25 | /// Gets or sets a value indicating whether the value should be null. Overrides the property. 26 | /// 27 | public bool IsNull { get; set; } 28 | 29 | /// 30 | public override object ProvideValue(IServiceProvider serviceProvider) 31 | { 32 | if (IsNull) 33 | { 34 | return null; 35 | } 36 | 37 | return Value; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/SymbolIconExtension.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows.Markup; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | /// 12 | /// Custom which can provide symbol-based values. 13 | /// 14 | [MarkupExtensionReturnType(typeof(SymbolIcon))] 15 | public class SymbolIconExtension : TextIconExtension 16 | { 17 | /// 18 | /// Gets or sets the value representing the icon to display. 19 | /// 20 | public Symbol Symbol { get; set; } 21 | 22 | /// 23 | public override object ProvideValue(IServiceProvider serviceProvider) 24 | { 25 | var fontIcon = new FontIcon 26 | { 27 | Glyph = unchecked((char)Symbol).ToString(), 28 | FontFamily = SegoeMDL2AssetsFontFamily, 29 | FontWeight = FontWeight, 30 | FontStyle = FontStyle 31 | }; 32 | 33 | if (FontSize > 0) 34 | { 35 | fontIcon.FontSize = FontSize; 36 | } 37 | 38 | if (Foreground != null) 39 | { 40 | fontIcon.Foreground = Foreground; 41 | } 42 | 43 | return fontIcon; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Markup/SymbolIconSourceExtension.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 ModernWpf.Controls; 6 | using System; 7 | using System.Windows.Markup; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | /// 12 | /// Custom which can provide symbol-based values. 13 | /// 14 | [MarkupExtensionReturnType(typeof(FontIconSource))] 15 | public class SymbolIconSourceExtension : TextIconExtension 16 | { 17 | /// 18 | /// Gets or sets the value representing the icon to display. 19 | /// 20 | public Symbol Symbol { get; set; } 21 | 22 | /// 23 | public override object ProvideValue(IServiceProvider serviceProvider) 24 | { 25 | var fontIcon = new FontIconSource 26 | { 27 | Glyph = unchecked((char)Symbol).ToString(), 28 | FontFamily = SegoeMDL2AssetsFontFamily, 29 | FontWeight = FontWeight, 30 | FontStyle = FontStyle 31 | }; 32 | 33 | if (FontSize > 0) 34 | { 35 | fontIcon.FontSize = FontSize; 36 | } 37 | 38 | if (Foreground != null) 39 | { 40 | fontIcon.Foreground = Foreground; 41 | } 42 | 43 | return fontIcon; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Media/MatrixHelperEx.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 System.Windows; 7 | using System.Windows.Media; 8 | 9 | namespace ModernWpf.Toolkit.UI.Extensions 10 | { 11 | // TODO: Check if we can make these static extension methods of the MatrixHelper in C#8 or move to an operator extension. 12 | 13 | /// 14 | /// Static helper methods for . 15 | /// 16 | public static class MatrixHelperEx 17 | { 18 | /// 19 | /// Implements WPF's Matrix.Multiply. 20 | /// 21 | /// The left matrix. 22 | /// The right matrix. 23 | /// The product of the two matrices. 24 | public static Matrix Multiply(Matrix matrix1, Matrix matrix2) 25 | { 26 | // WPF equivalent of following code: 27 | // return Matrix.Multiply(matrix1, matrix2); 28 | return new Matrix( 29 | (matrix1.M11 * matrix2.M11) + (matrix1.M12 * matrix2.M21), 30 | (matrix1.M11 * matrix2.M12) + (matrix1.M12 * matrix2.M22), 31 | (matrix1.M21 * matrix2.M11) + (matrix1.M22 * matrix2.M21), 32 | (matrix1.M21 * matrix2.M12) + (matrix1.M22 * matrix2.M22), 33 | (matrix1.OffsetX * matrix2.M11) + (matrix1.OffsetY * matrix2.M21) + matrix2.OffsetX, 34 | (matrix1.OffsetX * matrix2.M12) + (matrix1.OffsetY * matrix2.M22) + matrix2.OffsetY); 35 | } 36 | 37 | /// 38 | /// Rounds the non-offset elements of a matrix to avoid issues due to floating point imprecision and returns the result. 39 | /// 40 | /// The matrix to round. 41 | /// The number of decimals after the round. 42 | /// The rounded matrix. 43 | public static Matrix Round(Matrix matrix, int decimalsAfterRound) 44 | { 45 | return new Matrix( 46 | Math.Round(matrix.M11, decimalsAfterRound), 47 | Math.Round(matrix.M12, decimalsAfterRound), 48 | Math.Round(matrix.M21, decimalsAfterRound), 49 | Math.Round(matrix.M22, decimalsAfterRound), 50 | matrix.OffsetX, 51 | matrix.OffsetY); 52 | } 53 | 54 | /// 55 | /// Implement WPF's Rect.Transform. 56 | /// 57 | /// The rectangle to transform. 58 | /// The matrix to use to transform the rectangle. 59 | /// 60 | /// The transformed rectangle. 61 | public static Rect RectTransform(Rect rectangle, Matrix matrix) 62 | { 63 | // WPF equivalent of following code: 64 | // var rectTransformed = Rect.Transform(rect, matrix); 65 | Point leftTop = matrix.Transform(new Point(rectangle.Left, rectangle.Top)); 66 | Point rightTop = matrix.Transform(new Point(rectangle.Right, rectangle.Top)); 67 | Point leftBottom = matrix.Transform(new Point(rectangle.Left, rectangle.Bottom)); 68 | Point rightBottom = matrix.Transform(new Point(rectangle.Right, rectangle.Bottom)); 69 | double left = Math.Min(Math.Min(leftTop.X, rightTop.X), Math.Min(leftBottom.X, rightBottom.X)); 70 | double top = Math.Min(Math.Min(leftTop.Y, rightTop.Y), Math.Min(leftBottom.Y, rightBottom.Y)); 71 | double right = Math.Max(Math.Max(leftTop.X, rightTop.X), Math.Max(leftBottom.X, rightBottom.X)); 72 | double bottom = Math.Max(Math.Max(leftTop.Y, rightTop.Y), Math.Max(leftBottom.Y, rightBottom.Y)); 73 | Rect rectTransformed = new Rect(left, top, right - left, bottom - top); 74 | return rectTransformed; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Media/RotateTransformExtensions.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.Windows.Media; 6 | 7 | namespace ModernWpf.Toolkit.UI.Extensions 8 | { 9 | /// 10 | /// Extension methods for . 11 | /// 12 | public static class RotateTransformExtensions 13 | { 14 | /// 15 | /// Gets the matrix that represents this transform. 16 | /// Implements WPF's SkewTransform.Value. 17 | /// 18 | /// Extended SkewTranform. 19 | /// Matrix representing transform. 20 | public static Matrix GetMatrix(this RotateTransform transform) 21 | { 22 | var I = Matrix.Identity; 23 | I.RotateAt(transform.Angle, transform.CenterX, transform.CenterY); 24 | return I; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Media/ScaleTransformExtensions.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.Windows.Media; 6 | 7 | namespace ModernWpf.Toolkit.UI.Extensions 8 | { 9 | /// 10 | /// Extension methods for . 11 | /// 12 | public static class ScaleTransformExtensions 13 | { 14 | /// 15 | /// Gets the matrix that represents this transform. 16 | /// Implements WPF's SkewTransform.Value. 17 | /// 18 | /// Extended SkewTransform. 19 | /// Matrix representing transform. 20 | public static Matrix GetMatrix(this ScaleTransform transform) 21 | { 22 | var I = Matrix.Identity; 23 | I.ScaleAt(transform.ScaleX, transform.ScaleY, transform.CenterX, transform.CenterY); 24 | return I; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Media/SkewTransformExtensions.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.Windows.Media; 6 | 7 | namespace ModernWpf.Toolkit.UI.Extensions 8 | { 9 | /// 10 | /// Extension methods for . 11 | /// 12 | public static class SkewTransformExtensions 13 | { 14 | /// 15 | /// Gets the matrix that represents this transform. 16 | /// Implements WPF's SkewTransform.Value. 17 | /// 18 | /// Extended SkewTranform. 19 | /// Matrix representing transform. 20 | public static Matrix GetMatrix(this SkewTransform transform) 21 | { 22 | Matrix matrix = Matrix.Identity; 23 | 24 | var angleX = transform.AngleX; 25 | var angleY = transform.AngleY; 26 | var centerX = transform.CenterX; 27 | var centerY = transform.CenterY; 28 | 29 | bool hasCenter = centerX != 0 || centerY != 0; 30 | 31 | if (hasCenter) 32 | { 33 | // If we have a center, translate matrix before/after skewing. 34 | matrix.Translate(-centerX, -centerY); 35 | matrix.Skew(angleX, angleY); 36 | matrix.Translate(centerX, centerY); 37 | } 38 | else 39 | { 40 | matrix.Skew(angleX, angleY); 41 | } 42 | 43 | return matrix; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/Media/TranslateTransformExtensions.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.Windows.Media; 6 | 7 | namespace ModernWpf.Toolkit.UI.Extensions 8 | { 9 | /// 10 | /// Extension methods for . 11 | /// 12 | public static class TranslateTransformExtensions 13 | { 14 | /// 15 | /// Gets the matrix that represents this transform. 16 | /// Implements WPF's TranslateTransform.Value. 17 | /// 18 | /// Extended TranslateTranform. 19 | /// Matrix representing transform. 20 | public static Matrix GetMatrix(this TranslateTransform transform) 21 | { 22 | var I = Matrix.Identity; 23 | I.Translate(transform.X, transform.Y); 24 | return I; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/ScrollViewer/Enums/Axis.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 | namespace ModernWpf.Toolkit.UI.Extensions 6 | { 7 | /// 8 | /// Indicates an axis in the 2D space 9 | /// 10 | public enum Axis 11 | { 12 | /// 13 | /// The X axis (horizontal) 14 | /// 15 | X, 16 | 17 | /// 18 | /// The Y axis (vertical) 19 | /// 20 | Y 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/ScrollViewer/Enums/VisualProperty.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 | namespace ModernWpf.Toolkit.UI.Extensions 6 | { 7 | /// 8 | /// Indicates a property of a object. 9 | /// 10 | public enum VisualProperty 11 | { 12 | /// 13 | /// The offset property of a object. 14 | /// 15 | Offset, 16 | 17 | /// 18 | /// The translation property of a object. 19 | /// 20 | Translation 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/ScrollViewer/ScrollViewerExtensions.Properties.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.Windows; 6 | 7 | namespace ModernWpf.Toolkit.UI.Extensions 8 | { 9 | /// 10 | /// Provides attached dependency properties and methods for the control. 11 | /// 12 | public partial class ScrollViewerExtensions 13 | { 14 | #pragma warning disable CS0419 // Ambiguous reference in cref attribute 15 | 16 | /// 17 | /// Attached for binding a for the horizontal of a 18 | /// 19 | public static readonly DependencyProperty HorizontalScrollBarMarginProperty = DependencyProperty.RegisterAttached("HorizontalScrollBarMargin", typeof(Thickness), typeof(ScrollViewerExtensions), new PropertyMetadata(null, OnHorizontalScrollBarMarginPropertyChanged)); 20 | 21 | /// 22 | /// Attached for binding a for the vertical of a 23 | /// 24 | public static readonly DependencyProperty VerticalScrollBarMarginProperty = DependencyProperty.RegisterAttached("VerticalScrollBarMargin", typeof(Thickness), typeof(ScrollViewerExtensions), new PropertyMetadata(null, OnVerticalScrollBarMarginPropertyChanged)); 25 | 26 | /// 27 | /// Gets the associated with the specified vertical of a 28 | /// 29 | /// The to get the associated from 30 | /// The associated with the 31 | public static Thickness GetVerticalScrollBarMargin(FrameworkElement obj) 32 | { 33 | return (Thickness)obj.GetValue(VerticalScrollBarMarginProperty); 34 | } 35 | 36 | /// 37 | /// Sets the associated with the specified vertical of a 38 | /// 39 | /// The to associate the with 40 | /// The for binding to the 41 | public static void SetVerticalScrollBarMargin(FrameworkElement obj, Thickness value) 42 | { 43 | obj.SetValue(VerticalScrollBarMarginProperty, value); 44 | } 45 | 46 | /// 47 | /// Gets the associated with the specified horizontal of a 48 | /// 49 | /// The to get the associated from 50 | /// The associated with the 51 | public static Thickness GetHorizontalScrollBarMargin(FrameworkElement obj) 52 | { 53 | return (Thickness)obj.GetValue(HorizontalScrollBarMarginProperty); 54 | } 55 | 56 | /// 57 | /// Sets the associated with the specified horizontal of a 58 | /// 59 | /// The to associate the with 60 | /// The for binding to the 61 | public static void SetHorizontalScrollBarMargin(FrameworkElement obj, Thickness value) 62 | { 63 | obj.SetValue(HorizontalScrollBarMarginProperty, value); 64 | } 65 | 66 | #pragma warning restore CS0419 // Ambiguous reference in cref attribute 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/ScrollViewer/ScrollViewerExtensions.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.Linq; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Controls.Primitives; 9 | 10 | namespace ModernWpf.Toolkit.UI.Extensions 11 | { 12 | /// 13 | /// Provides attached dependency properties and methods for the control. 14 | /// 15 | public static partial class ScrollViewerExtensions 16 | { 17 | private static void OnHorizontalScrollBarMarginPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) 18 | { 19 | if (sender is FrameworkElement baseElement) 20 | { 21 | // If it didn't work it means that we need to wait for the component to be loaded before getting its ScrollViewer 22 | if (ChangeHorizontalScrollBarMarginProperty(sender as FrameworkElement)) 23 | { 24 | return; 25 | } 26 | 27 | // We need to wait for the component to be loaded before getting its ScrollViewer 28 | baseElement.Loaded -= ChangeHorizontalScrollBarMarginProperty; 29 | 30 | if (HorizontalScrollBarMarginProperty != null) 31 | { 32 | baseElement.Loaded += ChangeHorizontalScrollBarMarginProperty; 33 | } 34 | } 35 | } 36 | 37 | private static bool ChangeHorizontalScrollBarMarginProperty(FrameworkElement sender) 38 | { 39 | if (sender == null) 40 | { 41 | return false; 42 | } 43 | 44 | var scrollViewer = sender as ScrollViewer ?? sender.FindDescendant(); 45 | 46 | // Last scrollbar with "HorizontalScrollBar" as name is our target to set its margin and avoid it overlapping the header 47 | var scrollBar = scrollViewer?.FindDescendants().LastOrDefault(bar => bar.Name == "HorizontalScrollBar"); 48 | 49 | if (scrollBar == null) 50 | { 51 | return false; 52 | } 53 | 54 | var newMargin = GetHorizontalScrollBarMargin(sender); 55 | 56 | scrollBar.Margin = newMargin; 57 | 58 | return true; 59 | } 60 | 61 | private static void ChangeHorizontalScrollBarMarginProperty(object sender, RoutedEventArgs routedEventArgs) 62 | { 63 | if (sender is FrameworkElement baseElement) 64 | { 65 | ChangeHorizontalScrollBarMarginProperty(baseElement); 66 | 67 | // Handling Loaded event is only required the first time the property is set, so we can stop handling it now 68 | baseElement.Loaded -= ChangeHorizontalScrollBarMarginProperty; 69 | } 70 | } 71 | 72 | private static void OnVerticalScrollBarMarginPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args) 73 | { 74 | if (sender is FrameworkElement baseElement) 75 | { 76 | // We try to update the value, if it works we may exit 77 | if (ChangeVerticalScrollBarMarginProperty(sender as FrameworkElement)) 78 | { 79 | return; 80 | } 81 | 82 | // If it didn't work it means that we need to wait for the component to be loaded before getting its ScrollViewer 83 | baseElement.Loaded -= ChangeVerticalScrollBarMarginProperty; 84 | 85 | if (VerticalScrollBarMarginProperty != null) 86 | { 87 | baseElement.Loaded += ChangeVerticalScrollBarMarginProperty; 88 | } 89 | } 90 | } 91 | 92 | private static bool ChangeVerticalScrollBarMarginProperty(FrameworkElement sender) 93 | { 94 | if (sender == null) 95 | { 96 | return false; 97 | } 98 | 99 | var scrollViewer = sender as ScrollViewer ?? sender.FindDescendant(); 100 | 101 | // Last scrollbar with "HorizontalScrollBar" as name is our target to set its margin and avoid it overlapping the header 102 | var scrollBar = scrollViewer?.FindDescendants().LastOrDefault(bar => bar.Name == "VerticalScrollBar"); 103 | 104 | if (scrollBar == null) 105 | { 106 | return false; 107 | } 108 | 109 | var newMargin = GetVerticalScrollBarMargin(sender); 110 | 111 | scrollBar.Margin = newMargin; 112 | 113 | return true; 114 | } 115 | 116 | private static void ChangeVerticalScrollBarMarginProperty(object sender, RoutedEventArgs routedEventArgs) 117 | { 118 | ChangeVerticalScrollBarMarginProperty(sender as FrameworkElement); 119 | 120 | if (sender is FrameworkElement baseElement) 121 | { 122 | ChangeVerticalScrollBarMarginProperty(baseElement); 123 | 124 | // Handling Loaded event is only required the first time the property is set, so we can stop handling it now 125 | baseElement.Loaded -= ChangeVerticalScrollBarMarginProperty; 126 | } 127 | } 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/TextBoxMask/TextBoxMask.Properties.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.Collections.Generic; 6 | using System.Windows; 7 | 8 | namespace ModernWpf.Toolkit.UI.Extensions 9 | { 10 | /// 11 | /// TextBox mask property allows a user to more easily enter fixed width text in TextBox control 12 | /// where you would like them to enter the data in a certain format 13 | /// 14 | public partial class TextBoxMask 15 | { 16 | /// 17 | /// Represents a mask/format for the textbox that the user must follow 18 | /// 19 | public static readonly DependencyProperty MaskProperty = DependencyProperty.RegisterAttached("Mask", typeof(string), typeof(TextBoxMask), new PropertyMetadata(null, InitTextBoxMask)); 20 | 21 | /// 22 | /// Represents the mask place holder which represents the variable character that the user can edit in the textbox 23 | /// 24 | public static readonly DependencyProperty PlaceHolderProperty = DependencyProperty.RegisterAttached("PlaceHolder", typeof(string), typeof(TextBoxMask), new PropertyMetadata(DefaultPlaceHolder, InitTextBoxMask)); 25 | 26 | /// 27 | /// Represents the custom mask that the user can create to add his own variable characters based on regex expression 28 | /// 29 | public static readonly DependencyProperty CustomMaskProperty = DependencyProperty.RegisterAttached("CustomMask", typeof(string), typeof(TextBoxMask), new PropertyMetadata(null, InitTextBoxMask)); 30 | 31 | private static readonly DependencyProperty RepresentationDictionaryProperty = DependencyProperty.RegisterAttached("RepresentationDictionary", typeof(Dictionary), typeof(TextBoxMask), new PropertyMetadata(null)); 32 | private static readonly DependencyProperty OldTextProperty = DependencyProperty.RegisterAttached("OldText", typeof(string), typeof(TextBoxMask), new PropertyMetadata(null)); 33 | private static readonly DependencyProperty DefaultDisplayTextProperty = DependencyProperty.RegisterAttached("DefaultDisplayText", typeof(string), typeof(TextBoxMask), new PropertyMetadata(null)); 34 | private static readonly DependencyProperty OldSelectionLengthProperty = DependencyProperty.RegisterAttached("OldSelectionLength", typeof(int), typeof(TextBoxMask), new PropertyMetadata(0)); 35 | private static readonly DependencyProperty OldSelectionStartProperty = DependencyProperty.RegisterAttached("OldSelectionStart", typeof(int), typeof(TextBoxMask), new PropertyMetadata(0)); 36 | 37 | private static readonly DependencyProperty EscapedMaskProperty = DependencyProperty.RegisterAttached("EscapedMask", typeof(string), typeof(TextBoxMask), new PropertyMetadata(null)); 38 | private static readonly DependencyProperty EscapedCharacterIndicesProperty = DependencyProperty.RegisterAttached("MaskEscapedCharacters", typeof(List), typeof(TextBoxMask), new PropertyMetadata(null)); 39 | 40 | /// 41 | /// Gets mask value 42 | /// 43 | /// TextBox control 44 | /// mask value 45 | public static string GetMask(DependencyObject obj) 46 | { 47 | return (string)obj.GetValue(MaskProperty); 48 | } 49 | 50 | /// 51 | /// Sets textbox mask property which represents mask/format for the textbox that the user must follow 52 | /// 53 | /// TextBox Control 54 | /// Mask Value 55 | public static void SetMask(DependencyObject obj, string value) 56 | { 57 | obj.SetValue(MaskProperty, value); 58 | } 59 | 60 | /// 61 | /// Gets placeholder value 62 | /// 63 | /// TextBox control 64 | /// placeholder value 65 | public static string GetPlaceHolder(DependencyObject obj) 66 | { 67 | return (string)obj.GetValue(PlaceHolderProperty); 68 | } 69 | 70 | /// 71 | /// Sets placeholder property which represents the variable character that the user can edit in the textbox 72 | /// 73 | /// TextBox Control 74 | /// placeholder Value 75 | public static void SetPlaceHolder(DependencyObject obj, string value) 76 | { 77 | obj.SetValue(PlaceHolderProperty, value); 78 | } 79 | 80 | /// 81 | /// Gets CustomMask value 82 | /// 83 | /// TextBox control 84 | /// CustomMask value 85 | public static string GetCustomMask(DependencyObject obj) 86 | { 87 | return (string)obj.GetValue(CustomMaskProperty); 88 | } 89 | 90 | /// 91 | /// Sets CustomMask property which represents the custom mask that the user can create to add his own variable characters based on certain regex expression 92 | /// 93 | /// TextBox Control 94 | /// CustomMask Value 95 | public static void SetCustomMask(DependencyObject obj, string value) 96 | { 97 | obj.SetValue(CustomMaskProperty, value); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/TextBoxRegEx/TextBoxRegex.Data.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 | namespace ModernWpf.Toolkit.UI.Extensions 6 | { 7 | /// 8 | /// TextBoxRegex allows text validation using a regular expression. 9 | /// 10 | /// 11 | /// If is set to Normal then IsValid will be set according to whether the regex is valid. 12 | /// If is set to Forced then IsValid will be set according to whether the regex is valid, when TextBox lose focus and in case the textbox is invalid clear its value. 13 | /// If is set to Dynamic then IsValid will be set according to whether the regex is valid. If the newest charachter is invalid, only invalid character of the Textbox will be deleted. 14 | /// 15 | public partial class TextBoxRegex 16 | { 17 | /// 18 | /// Regex validation mode 19 | /// 20 | public enum ValidationMode 21 | { 22 | /// 23 | /// Update IsValid property with validation result at text changed 24 | /// 25 | Normal, 26 | 27 | /// 28 | /// Update IsValid property with validation result and in case the textbox is not valid clear its value when the TextBox lose focus 29 | /// 30 | Forced, 31 | 32 | /// 33 | /// Update IsValid property with validation result at text changed and clear the newest character at input which is not valid 34 | /// 35 | Dynamic 36 | } 37 | 38 | /// 39 | /// Specify the type of validation required 40 | /// 41 | public enum ValidationType 42 | { 43 | /// 44 | /// The default validation that required property Regex to be setted 45 | /// 46 | Custom, 47 | 48 | /// 49 | /// Email validation 50 | /// 51 | Email, 52 | 53 | /// 54 | /// Number validation 55 | /// 56 | Number, 57 | 58 | /// 59 | /// Decimal validation 60 | /// 61 | Decimal, 62 | 63 | /// 64 | /// Text only validation 65 | /// 66 | Characters, 67 | 68 | /// 69 | /// Phone number validation 70 | /// 71 | PhoneNumber 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Extensions/TextBoxRegEx/TextBoxRegex.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 ModernWpf.Toolkit.Extensions; 6 | using System.Diagnostics; 7 | using System.Text.RegularExpressions; 8 | using System.Windows; 9 | using System.Windows.Controls; 10 | 11 | namespace ModernWpf.Toolkit.UI.Extensions 12 | { 13 | /// 14 | /// TextBoxRegex allows text validation using a regular expression. 15 | /// 16 | /// 17 | /// If is set to Normal then IsValid will be set according to whether the regex is valid. 18 | /// If is set to Forced then IsValid will be set according to whether the regex is valid, when TextBox lose focus and in case the TextBox is invalid clear its value. 19 | /// If is set to Dynamic then IsValid will be set according to whether the regex is valid. If the newest character is invalid, only invalid character of the TextBox will be deleted. 20 | /// 21 | public partial class TextBoxRegex 22 | { 23 | private static void TextBoxRegexPropertyOnChange(DependencyObject sender, DependencyPropertyChangedEventArgs e) 24 | { 25 | if (!(sender is TextBox textBox)) 26 | { 27 | return; 28 | } 29 | 30 | ValidateTextBox(textBox, false); 31 | 32 | textBox.Loaded -= TextBox_Loaded; 33 | textBox.LostFocus -= TextBox_LostFocus; 34 | textBox.TextChanged -= TextBox_TextChanged; 35 | textBox.Loaded += TextBox_Loaded; 36 | textBox.LostFocus += TextBox_LostFocus; 37 | textBox.TextChanged += TextBox_TextChanged; 38 | } 39 | 40 | private static void TextBox_TextChanged(object sender, TextChangedEventArgs e) 41 | { 42 | var textBox = (TextBox)sender; 43 | var validationMode = (ValidationMode)textBox.GetValue(ValidationModeProperty); 44 | ValidateTextBox(textBox, validationMode == ValidationMode.Dynamic); 45 | } 46 | 47 | private static void TextBox_Loaded(object sender, RoutedEventArgs e) 48 | { 49 | var textBox = (TextBox)sender; 50 | ValidateTextBox(textBox); 51 | } 52 | 53 | private static void TextBox_LostFocus(object sender, RoutedEventArgs e) 54 | { 55 | var textBox = (TextBox)sender; 56 | ValidateTextBox(textBox); 57 | } 58 | 59 | private static void ValidateTextBox(TextBox textBox, bool force = true) 60 | { 61 | var validationType = (ValidationType)textBox.GetValue(ValidationTypeProperty); 62 | string regex; 63 | bool regexMatch; 64 | switch (validationType) 65 | { 66 | default: 67 | regex = textBox.GetValue(RegexProperty) as string; 68 | if (string.IsNullOrWhiteSpace(regex)) 69 | { 70 | Debug.WriteLine("Regex property can't be null or empty when custom mode is selected"); 71 | return; 72 | } 73 | 74 | regexMatch = Regex.IsMatch(textBox.Text, regex); 75 | break; 76 | 77 | case ValidationType.Decimal: 78 | regexMatch = textBox.Text.IsDecimal(); 79 | break; 80 | 81 | case ValidationType.Email: 82 | regexMatch = textBox.Text.IsEmail(); 83 | break; 84 | 85 | case ValidationType.Number: 86 | regexMatch = textBox.Text.IsNumeric(); 87 | break; 88 | 89 | case ValidationType.PhoneNumber: 90 | regexMatch = textBox.Text.IsPhoneNumber(); 91 | break; 92 | 93 | case ValidationType.Characters: 94 | regexMatch = textBox.Text.IsCharacterString(); 95 | break; 96 | } 97 | 98 | if (!regexMatch && force) 99 | { 100 | if (!string.IsNullOrEmpty(textBox.Text)) 101 | { 102 | var validationModel = (ValidationMode)textBox.GetValue(ValidationModeProperty); 103 | if (validationModel == ValidationMode.Forced) 104 | { 105 | textBox.Text = string.Empty; 106 | } 107 | else if (validationType != ValidationType.Email && validationType != ValidationType.PhoneNumber) 108 | { 109 | if (validationModel == ValidationMode.Dynamic) 110 | { 111 | int selectionStart = textBox.SelectionStart == 0 ? textBox.SelectionStart : textBox.SelectionStart - 1; 112 | textBox.Text = textBox.Text.Remove(selectionStart, 1); 113 | textBox.SelectionStart = selectionStart; 114 | } 115 | } 116 | } 117 | } 118 | 119 | textBox.SetValue(IsValidProperty, regexMatch); 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Helpers/BindableValueHolder.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.Windows; 6 | using System.Windows.Markup; 7 | 8 | namespace ModernWpf.Toolkit.UI.Helpers 9 | { 10 | /// 11 | /// Holds the value. 12 | /// Can be used to change several objects' properties at a time. 13 | /// 14 | [ContentProperty(nameof(Value))] 15 | public class BindableValueHolder : DependencyObject 16 | { 17 | /// 18 | /// Identifies the property. 19 | /// 20 | public static readonly DependencyProperty ValueProperty = 21 | DependencyProperty.Register( 22 | nameof(Value), 23 | typeof(object), 24 | typeof(BindableValueHolder), 25 | new PropertyMetadata()); 26 | 27 | /// 28 | /// Gets or sets the held value. 29 | /// 30 | public object Value 31 | { 32 | get { return GetValue(ValueProperty); } 33 | set { SetValue(ValueProperty, value); } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Helpers/CompositionTargetHelper.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 System.Threading.Tasks; 7 | using System.Windows.Media; 8 | 9 | namespace ModernWpf.Toolkit.UI.Helpers 10 | { 11 | /// 12 | /// Provides helpers for the class. 13 | /// 14 | public static class CompositionTargetHelper 15 | { 16 | /// 17 | /// Provides a method to execute code after the rendering pass is completed. 18 | /// 19 | /// 20 | /// Action to be executed after render pass 21 | /// Awaitable Task 22 | public static Task ExecuteAfterCompositionRenderingAsync(Action action) 23 | { 24 | if (action == null) 25 | { 26 | throw new ArgumentNullException($"Parameter { nameof(action) }({ typeof(Action) }) must be not null)"); 27 | } 28 | 29 | var taskCompletionSource = new TaskCompletionSource(); 30 | 31 | try 32 | { 33 | void Callback(object sender, object args) 34 | { 35 | CompositionTarget.Rendering -= Callback; 36 | 37 | action(); 38 | 39 | taskCompletionSource.SetResult(true); 40 | } 41 | 42 | CompositionTarget.Rendering += Callback; 43 | } 44 | catch (Exception e) 45 | { 46 | taskCompletionSource.SetException(e); // Note this can just sometimes be a wrong thread exception, see WinUI function notes. 47 | } 48 | 49 | return taskCompletionSource.Task; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Helpers/DependencyPropertyWatcher.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 System.Windows; 7 | using System.Windows.Data; 8 | 9 | namespace ModernWpf.Toolkit.UI.Helpers 10 | { 11 | /// 12 | /// Used to Track Changes of a Dependency Property 13 | /// 14 | /// Value of Dependency Property 15 | public class DependencyPropertyWatcher : DependencyObject, IDisposable 16 | { 17 | /// 18 | /// Value of Value Property 19 | /// 20 | public static readonly DependencyProperty ValueProperty = 21 | DependencyProperty.Register( 22 | nameof(Value), 23 | typeof(object), 24 | typeof(DependencyPropertyWatcher), 25 | new PropertyMetadata(null, OnPropertyChanged)); 26 | 27 | /// 28 | /// Called when Property Changes. 29 | /// 30 | public event EventHandler PropertyChanged; 31 | 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | /// Target Dependency Object 36 | /// Path of Property 37 | public DependencyPropertyWatcher(DependencyObject target, string propertyPath) 38 | { 39 | Target = target; 40 | BindingOperations.SetBinding( 41 | this, 42 | ValueProperty, 43 | new Binding() { Source = target, Path = new PropertyPath(propertyPath), Mode = BindingMode.OneWay }); 44 | } 45 | 46 | /// 47 | /// Gets the target Dependency Object 48 | /// 49 | public DependencyObject Target { get; private set; } 50 | 51 | /// 52 | /// Gets the current Value 53 | /// 54 | public T Value 55 | { 56 | get { return (T)GetValue(ValueProperty); } 57 | } 58 | 59 | /// 60 | /// Called when the Property is updated 61 | /// 62 | /// Source 63 | /// Args 64 | public static void OnPropertyChanged(object sender, DependencyPropertyChangedEventArgs args) 65 | { 66 | DependencyPropertyWatcher source = (DependencyPropertyWatcher)sender; 67 | 68 | source.PropertyChanged?.Invoke(source, EventArgs.Empty); 69 | } 70 | 71 | /// 72 | /// Clears the Watcher object. 73 | /// 74 | public void Dispose() 75 | { 76 | ClearValue(ValueProperty); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Helpers/GraphicsHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Media; 3 | using System.Windows.Media.Imaging; 4 | 5 | namespace ModernWpf.Toolkit.UI.Helpers 6 | { 7 | public static class GraphicsHelper 8 | { 9 | public static Color GetPixelColor(this BitmapSource bitmapSource, double x, double y) 10 | { 11 | if (IsPositionOutsideBitmapBounds(bitmapSource, x, y)) 12 | { 13 | return Colors.Transparent; 14 | } 15 | 16 | var croppedBitmap = new CroppedBitmap(bitmapSource, new Int32Rect((int)x, (int)y, 1, 1)); 17 | var pixels = new byte[4]; 18 | croppedBitmap.CopyPixels(pixels, 4, 0); 19 | return Color.FromArgb(pixels[3], pixels[2], pixels[1], pixels[0]); 20 | } 21 | 22 | public static Brush GetPixelBrush(this BitmapSource bitmapSource, double x, double y) 23 | { 24 | return new SolidColorBrush(GetPixelColor(bitmapSource, x, y)); 25 | } 26 | 27 | private static bool IsPositionOutsideBitmapBounds(this BitmapSource bitmapSource, double x, double y) 28 | { 29 | return x < 0 || y < 0 || x >= bitmapSource.PixelWidth || y >= bitmapSource.PixelHeight; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/ModernWpf.Toolkit.UI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0-windows10.0.18362.0;netcoreapp3.1;net462 5 | true 6 | latest 7 | ModernWpf Community Toolkit UI 8 | 9 | This library provides UI components, such as XAML extensions, helpers, converters and more. It is part of the ModernWpf Community Toolkit. 10 | 11 | Converters: Commonly used converters that allow the data to be modified as it passes through the binding engine. 12 | 13 | Extensions: 14 | - DependencyObjectExtensions: Provides methods to Register and Unregister PropertyChangedCallback of a DependencyProperty. 15 | - FrameworkElementExtensions: Provides attached dependency properties for the FrameworkElement. 16 | - LogicalTree: Defines a collection of extensions methods for UI. 17 | - MatrixExtensions: Provides a set of extensions to the Matrix struct. 18 | - MatrixHelperEx: Static helper methods for Matrix. 19 | - NullableBool: Custom MarkupExtension which can provide nullable bool values. 20 | - RotateTransformExtensions: Extension methods for RotateTransform. 21 | - ScaleTransformExtensions: Extension methods for ScaleTransform. 22 | - SkewTransformExtensions: Extension methods for SkewTransform. 23 | - TextBoxMask: TextBox mask property allows a user to more easily enter fixed width text in TextBox control. 24 | - TextBoxRegex: TextBoxRegex allows text validation using a regular expression. 25 | - TranslateTransformExtensions: Extension methods for TranslateTransform. 26 | - VisualTree: Defines a collection of extensions methods for UI. 27 | 28 | Helpers: 29 | - BindableValueHolder: Holds the value. Can be used to change several objects' properties at a time. 30 | - DependencyPropertyWatcher: Used to Track Changes of a Dependency Property. 31 | - GraphicsHelper: Used to get pixel's color from a bitmap source. 32 | 33 | WPF ModernWpf Toolkit Windows UI Converters XAML extensions helpers 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | using System.Windows.Markup; 3 | 4 | [assembly: ThemeInfo( 5 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 6 | //(used if a resource is not found in the page, 7 | // or application resource dictionaries) 8 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 9 | //(used if a resource is not found in the page, 10 | // app, or any theme specific resource dictionaries) 11 | )] 12 | 13 | [assembly: XmlnsPrefix("http://schemas.modernwpf.com/toolkit", "toolkit")] 14 | [assembly: XmlnsDefinition("http://schemas.modernwpf.com/toolkit", "ModernWpf.Toolkit.UI")] 15 | [assembly: XmlnsDefinition("http://schemas.modernwpf.com/toolkit", "ModernWpf.Toolkit.UI.Converters")] 16 | [assembly: XmlnsDefinition("http://schemas.modernwpf.com/toolkit", "ModernWpf.Toolkit.UI.Extensions")] 17 | [assembly: XmlnsDefinition("http://schemas.modernwpf.com/toolkit", "ModernWpf.Toolkit.UI.Helpers")] 18 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/ThemeResources/Dark.xaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/ThemeResources/HighContrast.xaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/ThemeResources/Light.xaml: -------------------------------------------------------------------------------- 1 |  3 | 4 | 5 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit.UI/ThemeResources/ToolkitThemeDictionary.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows; 4 | 5 | namespace ModernWpf.Toolkit.UI 6 | { 7 | public class ToolkitThemeDictionary 8 | { 9 | internal const string LightKey = "Light"; 10 | internal const string DarkKey = "Dark"; 11 | internal const string HighContrastKey = "HighContrast"; 12 | 13 | private static Dictionary _defaultThemeDictionaries = new(); 14 | 15 | public static void SetKey(ResourceDictionary themeDictionary, string key) 16 | { 17 | var baseThemeDictionary = GetToolkitThemeDictionary(key); 18 | themeDictionary.MergedDictionaries.Add(baseThemeDictionary); 19 | } 20 | 21 | private static ResourceDictionary GetToolkitThemeDictionary(string key) 22 | { 23 | if (!_defaultThemeDictionaries.TryGetValue(key, out ResourceDictionary dictionary)) 24 | { 25 | dictionary = new ResourceDictionary { Source = GetDefaultSource(key) }; 26 | _defaultThemeDictionaries[key] = dictionary; 27 | } 28 | return dictionary; 29 | } 30 | 31 | private static Uri GetDefaultSource(string theme) 32 | { 33 | return new Uri($"pack://application:,,,/ModernWpf.Toolkit.UI;component/ThemeResources/{theme}.xaml"); 34 | } 35 | 36 | public static void SetMergeOnto(ResourceDictionary themeDictionary, string key) 37 | { 38 | var baseThemeDictionary = GetToolkitThemeDictionary(key); 39 | baseThemeDictionary.MergedDictionaries.Add(themeDictionary); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Converters.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 | namespace ModernWpf.Toolkit 6 | { 7 | /// 8 | /// Set of helpers to convert between data types and notations. 9 | /// 10 | public static class Converters 11 | { 12 | /// 13 | /// Translate numeric file size in bytes to a human-readable shorter string format. 14 | /// 15 | /// File size in bytes. 16 | /// Returns file size short string. 17 | public static string ToFileSizeString(long size) 18 | { 19 | if (size < 1024) 20 | { 21 | return size.ToString("F0") + " bytes"; 22 | } 23 | else if ((size >> 10) < 1024) 24 | { 25 | return (size / 1024F).ToString("F1") + " KB"; 26 | } 27 | else if ((size >> 20) < 1024) 28 | { 29 | return ((size >> 10) / 1024F).ToString("F1") + " MB"; 30 | } 31 | else if ((size >> 30) < 1024) 32 | { 33 | return ((size >> 20) / 1024F).ToString("F1") + " GB"; 34 | } 35 | else if ((size >> 40) < 1024) 36 | { 37 | return ((size >> 30) / 1024F).ToString("F1") + " TB"; 38 | } 39 | else if ((size >> 50) < 1024) 40 | { 41 | return ((size >> 40) / 1024F).ToString("F1") + " PB"; 42 | } 43 | else 44 | { 45 | return ((size >> 50) / 1024F).ToString("F0") + " EB"; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Deferred/DeferredCancelEventArgs.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 | namespace ModernWpf.Toolkit.Deferred 6 | { 7 | /// 8 | /// which can also be canceled. 9 | /// 10 | public class DeferredCancelEventArgs : DeferredEventArgs 11 | { 12 | /// 13 | /// Gets or sets a value indicating whether the event should be canceled. 14 | /// 15 | public bool Cancel { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Deferred/DeferredEventArgs.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 | 7 | namespace ModernWpf.Toolkit.Deferred 8 | { 9 | /// 10 | /// which can retrieve a in order to process data asynchronously before an completes and returns to the calling control. 11 | /// 12 | public class DeferredEventArgs : EventArgs 13 | { 14 | /// 15 | /// Gets a new to use in cases where no wish to be provided. 16 | /// 17 | public static new DeferredEventArgs Empty => new DeferredEventArgs(); 18 | 19 | private readonly object _eventDeferralLock = new object(); 20 | 21 | private EventDeferral _eventDeferral; 22 | 23 | /// 24 | /// Returns an which can be completed when deferred event is ready to continue. 25 | /// 26 | /// instance. 27 | public EventDeferral GetDeferral() 28 | { 29 | lock (_eventDeferralLock) 30 | { 31 | return _eventDeferral ??= new EventDeferral(); 32 | } 33 | } 34 | 35 | internal EventDeferral GetCurrentDeferralAndReset() 36 | { 37 | lock (_eventDeferralLock) 38 | { 39 | var eventDeferral = _eventDeferral; 40 | 41 | _eventDeferral = null; 42 | 43 | return eventDeferral; 44 | } 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Deferred/EventDeferral.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 System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | namespace ModernWpf.Toolkit.Deferred 10 | { 11 | /// 12 | /// Deferral handle provided by a . 13 | /// 14 | public class EventDeferral : IDisposable 15 | { 16 | private readonly TaskCompletionSource _taskCompletionSource = new TaskCompletionSource(); 17 | 18 | internal EventDeferral() 19 | { 20 | } 21 | 22 | /// 23 | /// Call when finished with the Deferral. 24 | /// 25 | public void Complete() => _taskCompletionSource.TrySetResult(null); 26 | 27 | internal async Task WaitForCompletion(CancellationToken cancellationToken) 28 | { 29 | using (cancellationToken.Register(() => _taskCompletionSource.TrySetCanceled())) 30 | { 31 | await _taskCompletionSource.Task; 32 | } 33 | } 34 | 35 | /// 36 | public void Dispose() 37 | { 38 | Complete(); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Deferred/EventHandlerExtensions.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 System.Linq; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | 10 | namespace ModernWpf.Toolkit.Deferred 11 | { 12 | /// 13 | /// Extensions to for Deferred Events. 14 | /// 15 | public static class EventHandlerExtensions 16 | { 17 | /// 18 | /// Use to invoke an async using . 19 | /// 20 | /// type. 21 | /// to be invoked. 22 | /// Sender of the event. 23 | /// instance. 24 | /// to wait on deferred event handler. 25 | public static Task InvokeAsync(this EventHandler eventHandler, object sender, T eventArgs) 26 | where T : DeferredEventArgs 27 | { 28 | return InvokeAsync(eventHandler, sender, eventArgs, CancellationToken.None); 29 | } 30 | 31 | /// 32 | /// Use to invoke an async using with a . 33 | /// 34 | /// type. 35 | /// to be invoked. 36 | /// Sender of the event. 37 | /// instance. 38 | /// option. 39 | /// to wait on deferred event handler. 40 | public static Task InvokeAsync(this EventHandler eventHandler, object sender, T eventArgs, CancellationToken cancellationToken) 41 | where T : DeferredEventArgs 42 | { 43 | if (eventHandler == null) 44 | { 45 | return Task.CompletedTask; 46 | } 47 | 48 | var tasks = eventHandler.GetInvocationList() 49 | .OfType>() 50 | .Select(invocationDelegate => 51 | { 52 | cancellationToken.ThrowIfCancellationRequested(); 53 | 54 | invocationDelegate(sender, eventArgs); 55 | 56 | var deferral = eventArgs.GetCurrentDeferralAndReset(); 57 | 58 | return deferral?.WaitForCompletion(cancellationToken) ?? Task.CompletedTask; 59 | }) 60 | .ToArray(); 61 | 62 | return Task.WhenAll(tasks); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Extensions/PointExtensions.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.Diagnostics.Contracts; 6 | using System.Runtime.CompilerServices; 7 | using Point = System.Windows.Point; 8 | using Rect = System.Windows.Rect; 9 | using Size = System.Windows.Size; 10 | 11 | namespace ModernWpf.Toolkit.Extensions 12 | { 13 | /// 14 | /// Extensions for the type. 15 | /// 16 | public static class PointExtensions 17 | { 18 | /// 19 | /// Creates a new of the specified size, starting at a given point. 20 | /// 21 | /// The input value to convert. 22 | /// The width of the rectangle. 23 | /// The height of the rectangle. 24 | /// A value of the specified size, starting at the given point. 25 | [Pure] 26 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 27 | public static Rect ToRect(this Point point, double width, double height) 28 | { 29 | return new Rect(point.X, point.Y, width, height); 30 | } 31 | 32 | /// 33 | /// Creates a new ending at the specified point, starting at the given coordinates. 34 | /// 35 | /// The input value to convert. 36 | /// The ending position for the rectangle. 37 | /// A value between the two specified points. 38 | [Pure] 39 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 40 | public static Rect ToRect(this Point point, Point end) 41 | { 42 | return new Rect(point, end); 43 | } 44 | 45 | /// 46 | /// Creates a new of the specified size, starting at the given coordinates. 47 | /// 48 | /// The input value to convert. 49 | /// The size of the rectangle to create. 50 | /// A value of the specified size, starting at the given coordinates. 51 | [Pure] 52 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 53 | public static Rect ToRect(this Point point, Size size) 54 | { 55 | return new Rect(point, size); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Extensions/SizeExtensions.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.Diagnostics.Contracts; 6 | using System.Runtime.CompilerServices; 7 | using Point = System.Windows.Point; 8 | using Rect = System.Windows.Rect; 9 | using Size = System.Windows.Size; 10 | 11 | namespace ModernWpf.Toolkit.Extensions 12 | { 13 | /// 14 | /// Extensions for the type. 15 | /// 16 | public static class SizeExtensions 17 | { 18 | /// 19 | /// Creates a new of the specified size, starting at the origin. 20 | /// 21 | /// The input value to convert. 22 | /// A value of the specified size, starting at the origin. 23 | [Pure] 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static Rect ToRect(this Size size) 26 | { 27 | return new Rect(0, 0, size.Width, size.Height); 28 | } 29 | 30 | /// 31 | /// Creates a new of the specified size, starting at the given coordinates. 32 | /// 33 | /// The input value to convert. 34 | /// The horizontal offset. 35 | /// The vertical offset. 36 | /// A value of the specified size, starting at the given coordinates. 37 | [Pure] 38 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 39 | public static Rect ToRect(this Size size, double x, double y) 40 | { 41 | return new Rect(x, y, size.Width, size.Height); 42 | } 43 | 44 | /// 45 | /// Creates a new of the specified size, starting at the given position. 46 | /// 47 | /// The input value to convert. 48 | /// The starting position to use. 49 | /// A value of the specified size, starting at the given position. 50 | [Pure] 51 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 52 | public static Rect ToRect(this Size size, Point point) 53 | { 54 | return new Rect(point, size); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Helpers/WeakEventListener.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 | 7 | namespace ModernWpf.Toolkit.Helpers 8 | { 9 | /// 10 | /// Implements a weak event listener that allows the owner to be garbage 11 | /// collected if its only remaining link is an event handler. 12 | /// 13 | /// Type of instance listening for the event. 14 | /// Type of source for the event. 15 | /// Type of event arguments for the event. 16 | [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 17 | public sealed class WeakEventListener 18 | where TInstance : class 19 | { 20 | /// 21 | /// WeakReference to the instance listening for the event. 22 | /// 23 | private readonly WeakReference _weakInstance; 24 | 25 | /// 26 | /// Initializes a new instance of the class. 27 | /// 28 | /// Instance subscribing to the event. 29 | public WeakEventListener(TInstance instance) 30 | { 31 | if (instance == null) 32 | { 33 | throw new ArgumentNullException(nameof(instance)); 34 | } 35 | 36 | _weakInstance = new WeakReference(instance); 37 | } 38 | 39 | /// 40 | /// Gets or sets the method to call when the event fires. 41 | /// 42 | public Action OnEventAction { get; set; } 43 | 44 | /// 45 | /// Gets or sets the method to call when detaching from the event. 46 | /// 47 | public Action> OnDetachAction { get; set; } 48 | 49 | /// 50 | /// Handler for the subscribed event calls OnEventAction to handle it. 51 | /// 52 | /// Event source. 53 | /// Event arguments. 54 | public void OnEvent(TSource source, TEventArgs eventArgs) 55 | { 56 | var target = (TInstance)_weakInstance.Target; 57 | if (target != null) 58 | { 59 | // Call registered action 60 | OnEventAction?.Invoke(target, source, eventArgs); 61 | } 62 | else 63 | { 64 | // Detach from event 65 | Detach(); 66 | } 67 | } 68 | 69 | /// 70 | /// Detaches from the subscribed event. 71 | /// 72 | public void Detach() 73 | { 74 | OnDetachAction?.Invoke(this); 75 | OnDetachAction = null; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/ModernWpf.Toolkit.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net5.0-windows10.0.18362.0;netcoreapp3.1;net462 5 | true 6 | latest 7 | ModernWpf Community Toolkit 8 | This package includes code only helpers such as Colors conversion tool and some others. 9 | WPF ModernWpf Toolkit Windows 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Windows; 3 | 4 | [assembly: ThemeInfo( 5 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 6 | //(used if a resource is not found in the page, 7 | // or application resource dictionaries) 8 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 9 | //(used if a resource is not found in the page, 10 | // app, or any theme specific resource dictionaries) 11 | )] 12 | [assembly: InternalsVisibleTo("ModernWpf.Toolkit.UI")] 13 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Structures/HslColor.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 | namespace ModernWpf.Toolkit 6 | { 7 | /// 8 | /// Defines a color in Hue/Saturation/Lightness (HSL) space. 9 | /// 10 | public struct HslColor 11 | { 12 | /// 13 | /// The Hue in 0..360 range. 14 | /// 15 | public double H; 16 | 17 | /// 18 | /// The Saturation in 0..1 range. 19 | /// 20 | public double S; 21 | 22 | /// 23 | /// The Lightness in 0..1 range. 24 | /// 25 | public double L; 26 | 27 | /// 28 | /// The Alpha/opacity in 0..1 range. 29 | /// 30 | public double A; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ModernWpf.Toolkit/Structures/HsvColor.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 | namespace ModernWpf.Toolkit 6 | { 7 | /// 8 | /// Defines a color in Hue/Saturation/Value (HSV) space. 9 | /// 10 | public struct HsvColor 11 | { 12 | /// 13 | /// The Hue in 0..360 range. 14 | /// 15 | public double H; 16 | 17 | /// 18 | /// The Saturation in 0..1 range. 19 | /// 20 | public double S; 21 | 22 | /// 23 | /// The Value in 0..1 range. 24 | /// 25 | public double V; 26 | 27 | /// 28 | /// The Alpha/opacity in 0..1 range. 29 | /// 30 | public double A; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ModernWpfCommunityToolkit 2 | 3 | The **ModernWpf Community Toolkit** is a collection of helper functions and custom controls for the **[ModernWpf](https://github.com/Kinnara/ModernWpf)** library. 4 | 5 | This project incorporates components from the [Windows Community Toolkit](https://github.com/windows-toolkit/WindowsCommunityToolkit). 6 | The [Windows Community Toolkit](https://github.com/windows-toolkit/WindowsCommunityToolkit)'s license and 3rd party notices could be found [here](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/license.md) and [here](https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/ThirdPartyNotices.txt) respectively. 7 | 8 | ## ModernWpf Community Toolkit & the [Windows Community Toolkit](https://github.com/windows-toolkit/WindowsCommunityToolkit) 9 | 10 | First of all, we must thank the contributors of the **WCT** for their awesome work on the toolkit. 11 | 12 | The **ModernWpf Community Toolkit (MCT)** is a port of the well-known & popular **[Windows Community Toolkit](https://github.com/windows-toolkit/WindowsCommunityToolkit)** to **WPF**/**ModernWpf**. 13 | 14 | The **[Windows Community Toolkit](https://github.com/windows-toolkit/WindowsCommunityToolkit) (WCT)** [being a part of the **.NET Foundation** and actively developed by **Microsoft** and the **community**] is a collection of helper functions, custom controls and app services which simplifies and helps the development of UWP apps for Windows. 15 | 16 | It has some parts which depend on some **UWP only APIs** (which can't be used from Win32 apps). And some parts are dependent on the **UWP XAML** (aka **WinUI**). Thus, rendering the WCT unusable from some application (such as **pure WPF apps**). 17 | 18 | To resolve this barrier, **ModernWpf Community Toolkit** was made. 19 | 20 | **ModernWpf Community Toolkit** is also a collection of helper functions and custom controls but for building **WPF (Win32) apps**. 21 | 22 | This toolkit depends on another well-known & popular library called **[ModernWpf](https://github.com/Kinnara/ModernWpf)** which brings **WinUI** controls & styles to **WPF** applications. Whereas, this toolkit brings some **WCT** controls & helpers to **WPF**. 23 | 24 | There may be some differences (in APIs or availability of some features) between **MCT** and **WCT** due to certain difference between WPF (.NET) & UWP (WinRT) APIs. 25 | 26 | Most of the source code are ported from the **WCT** (some differences or variations can be found). 27 | 28 | This toolkit contains ported **custom controls** and some features that are not restricted **UWP only** from **WCT**. 29 | 30 | Parts of the WCT which target **.NET Standard** (as you can use them from any .NET library/application) are not ported. However, some WinUI (UWP XAML) specific features are ported. 31 | 32 | This toolkit also contains some additional controls and helpers that are **WPF or ModernWpf specific**. 33 | 34 | So, **ModernWpf** ≋ **WinUI** and **MCT** ≋ **WCT**. 35 | 36 | ## NuGet Packages 37 | | NuGet Package | Latest Versions | 38 | | --- | --- | 39 | | [ModernWpf.Toolkit][Toolkit] | [![latest stable version](https://img.shields.io/nuget/v/ModernWpf.Toolkit)][Toolkit]
[![latest prerelease version](https://img.shields.io/nuget/vpre/ModernWpf.Toolkit)][Toolkit.Pre] | 40 | | [ModernWpf.Toolkit.UI][Toolkit.UI] | [![latest stable version](https://img.shields.io/nuget/v/ModernWpf.Toolkit.UI)][Toolkit.UI]
[![latest prerelease version](https://img.shields.io/nuget/vpre/ModernWpf.Toolkit.UI)][Toolkit.UI.Pre] | 41 | | [ModernWpf.Toolkit.UI.Controls][Toolkit.UI.Controls] | [![latest stable version](https://img.shields.io/nuget/v/ModernWpf.Toolkit.UI.Controls)][Toolkit.UI.Controls]
[![latest prerelease version](https://img.shields.io/nuget/vpre/ModernWpf.Toolkit.UI.Controls)][Toolkit.UI.Controls.Pre] | 42 | | [ModernWpf.Toolkit.UI.Controls.Markdown][Toolkit.UI.Controls.Markdown] | [![latest stable version](https://img.shields.io/nuget/v/ModernWpf.Toolkit.UI.Controls.Markdown)][Toolkit.UI.Controls.Markdown]
[![latest prerelease version](https://img.shields.io/nuget/vpre/ModernWpf.Toolkit.UI.Controls.Markdown)][Toolkit.UI.Controls.Markdown.Pre] | 43 | 44 | [Toolkit]: https://www.nuget.org/packages/ModernWpf.Toolkit/ 45 | [Toolkit.Pre]: https://www.nuget.org/packages/ModernWpf.Toolkit/absoluteLatest 46 | [Toolkit.UI]: https://www.nuget.org/packages/ModernWpf.Toolkit.UI/ 47 | [Toolkit.UI.Pre]: https://www.nuget.org/packages/ModernWpf.Toolkit.UI/absoluteLatest 48 | [Toolkit.UI.Controls]: https://www.nuget.org/packages/ModernWpf.Toolkit.UI.Controls/ 49 | [Toolkit.UI.Controls.Pre]: https://www.nuget.org/packages/ModernWpf.Toolkit.UI.Controls/absoluteLatest 50 | [Toolkit.UI.Controls.Markdown]: https://www.nuget.org/packages/ModernWpf.Toolkit.UI.Controls.Markdown/ 51 | [Toolkit.UI.Controls.Markdown.Pre]: https://www.nuget.org/packages/ModernWpf.Toolkit.UI.Controls.Markdown/absoluteLatest 52 | --------------------------------------------------------------------------------