mirror of
https://github.com/holgerb83/ModernWpfPlayground.git
synced 2025-06-30 09:40:52 +02:00
Compare commits
5 Commits
ae6192bd1f
...
main
Author | SHA1 | Date | |
---|---|---|---|
a5adf60ba7 | |||
14f2a7242a | |||
644e2628e3 | |||
02e3af3dcb | |||
538789078a |
18
.config/dotnet-tools.json
Normal file
18
.config/dotnet-tools.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"version": 1,
|
||||||
|
"isRoot": true,
|
||||||
|
"tools": {
|
||||||
|
"cake.tool": {
|
||||||
|
"version": "2.0.0-rc0002",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-cake"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gitversion.tool": {
|
||||||
|
"version": "5.8.1",
|
||||||
|
"commands": [
|
||||||
|
"dotnet-gitversion"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
.csharpierrc
Normal file
6
.csharpierrc
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"printWidth": 200,
|
||||||
|
"useTabs": false,
|
||||||
|
"tabWidth": 4,
|
||||||
|
"preprocessorSymbolSets": ["", "DEBUG", "DEBUG,CODE_STYLE"]
|
||||||
|
}
|
247
.editorconfig
Normal file
247
.editorconfig
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
# Entfernen Sie die folgende Zeile, wenn Sie EDITORCONFIG-Einstellungen von höheren Verzeichnissen vererben möchten.
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# C#-Dateien
|
||||||
|
[*.cs]
|
||||||
|
|
||||||
|
#### Wichtige EditorConfig-Optionen ####
|
||||||
|
|
||||||
|
# Einzüge und Abstände
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
tab_width = 4
|
||||||
|
|
||||||
|
# Einstellungen für neue Zeilen
|
||||||
|
end_of_line = crlf
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
#### .NET-Codierungskonventionen ####
|
||||||
|
|
||||||
|
# Using-Direktiven organisieren
|
||||||
|
dotnet_separate_import_directive_groups = false
|
||||||
|
dotnet_sort_system_directives_first = false
|
||||||
|
file_header_template = unset
|
||||||
|
|
||||||
|
# this.- und Me.-Einstellungen
|
||||||
|
dotnet_style_qualification_for_event = false
|
||||||
|
dotnet_style_qualification_for_field = false
|
||||||
|
dotnet_style_qualification_for_method = false
|
||||||
|
dotnet_style_qualification_for_property = false
|
||||||
|
|
||||||
|
# Einstellungen für Sprachschlüsselwörter und BCL-Typen
|
||||||
|
dotnet_style_predefined_type_for_locals_parameters_members = true
|
||||||
|
dotnet_style_predefined_type_for_member_access = true
|
||||||
|
|
||||||
|
# Einstellungen für Klammern
|
||||||
|
dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity
|
||||||
|
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity
|
||||||
|
dotnet_style_parentheses_in_other_operators = never_if_unnecessary
|
||||||
|
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity
|
||||||
|
|
||||||
|
# Einstellungen für Modifizierer
|
||||||
|
dotnet_style_require_accessibility_modifiers = for_non_interface_members
|
||||||
|
|
||||||
|
# Einstellungen für Ausdrucksebene
|
||||||
|
dotnet_style_coalesce_expression = true
|
||||||
|
dotnet_style_collection_initializer = true
|
||||||
|
dotnet_style_explicit_tuple_names = true
|
||||||
|
dotnet_style_namespace_match_folder = true
|
||||||
|
dotnet_style_null_propagation = true
|
||||||
|
dotnet_style_object_initializer = true
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
dotnet_style_prefer_auto_properties = true
|
||||||
|
dotnet_style_prefer_compound_assignment = true
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = true
|
||||||
|
dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = true
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true
|
||||||
|
|
||||||
|
# Einstellungen für Felder
|
||||||
|
dotnet_style_readonly_field = true
|
||||||
|
|
||||||
|
# Einstellungen für Parameter
|
||||||
|
dotnet_code_quality_unused_parameters = all
|
||||||
|
|
||||||
|
# Unterdrückungseinstellungen
|
||||||
|
dotnet_remove_unnecessary_suppression_exclusions = none
|
||||||
|
|
||||||
|
# Einstellungen für neue Zeilen
|
||||||
|
dotnet_style_allow_multiple_blank_lines_experimental = true
|
||||||
|
dotnet_style_allow_statement_immediately_after_block_experimental = true
|
||||||
|
|
||||||
|
#### C#-Codierungskonventionen ####
|
||||||
|
|
||||||
|
# Var-Einstellungen
|
||||||
|
csharp_style_var_elsewhere = false
|
||||||
|
csharp_style_var_for_built_in_types = false
|
||||||
|
csharp_style_var_when_type_is_apparent = false
|
||||||
|
|
||||||
|
# Ausdruckskörpermember
|
||||||
|
csharp_style_expression_bodied_accessors = true:silent
|
||||||
|
csharp_style_expression_bodied_constructors = false:silent
|
||||||
|
csharp_style_expression_bodied_indexers = true:silent
|
||||||
|
csharp_style_expression_bodied_lambdas = true:silent
|
||||||
|
csharp_style_expression_bodied_local_functions = false:silent
|
||||||
|
csharp_style_expression_bodied_methods = false:silent
|
||||||
|
csharp_style_expression_bodied_operators = false:silent
|
||||||
|
csharp_style_expression_bodied_properties = true:silent
|
||||||
|
|
||||||
|
# Einstellungen für den Musterabgleich
|
||||||
|
csharp_style_pattern_matching_over_as_with_null_check = true
|
||||||
|
csharp_style_pattern_matching_over_is_with_cast_check = true
|
||||||
|
csharp_style_prefer_extended_property_pattern = true
|
||||||
|
csharp_style_prefer_not_pattern = true
|
||||||
|
csharp_style_prefer_pattern_matching = true
|
||||||
|
csharp_style_prefer_switch_expression = true:suggestion
|
||||||
|
|
||||||
|
# Einstellungen für NULL-Überprüfung
|
||||||
|
csharp_style_conditional_delegate_call = true
|
||||||
|
|
||||||
|
# Einstellungen für Modifizierer
|
||||||
|
csharp_prefer_static_local_function = true
|
||||||
|
csharp_preferred_modifier_order = public,private,protected,internal,file,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async
|
||||||
|
csharp_style_prefer_readonly_struct = true
|
||||||
|
|
||||||
|
# Einstellungen für Codeblöcke
|
||||||
|
csharp_prefer_braces = true:silent
|
||||||
|
csharp_prefer_simple_using_statement = true:suggestion
|
||||||
|
csharp_style_namespace_declarations = block_scoped:silent
|
||||||
|
csharp_style_prefer_method_group_conversion = true:silent
|
||||||
|
csharp_style_prefer_top_level_statements = true:silent
|
||||||
|
|
||||||
|
# Einstellungen für Ausdrucksebene
|
||||||
|
csharp_prefer_simple_default_expression = true:suggestion
|
||||||
|
csharp_style_deconstructed_variable_declaration = true:suggestion
|
||||||
|
csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
|
||||||
|
csharp_style_inlined_variable_declaration = true:suggestion
|
||||||
|
csharp_style_prefer_index_operator = true:suggestion
|
||||||
|
csharp_style_prefer_local_over_anonymous_function = true:suggestion
|
||||||
|
csharp_style_prefer_null_check_over_type_check = true:suggestion
|
||||||
|
csharp_style_prefer_range_operator = true:suggestion
|
||||||
|
csharp_style_prefer_tuple_swap = true:suggestion
|
||||||
|
csharp_style_prefer_utf8_string_literals = true:suggestion
|
||||||
|
csharp_style_throw_expression = true:suggestion
|
||||||
|
csharp_style_unused_value_assignment_preference = discard_variable:suggestion
|
||||||
|
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
|
||||||
|
|
||||||
|
# Einstellungen für using-Anweisungen
|
||||||
|
csharp_using_directive_placement = outside_namespace
|
||||||
|
|
||||||
|
# Einstellungen für neue Zeilen
|
||||||
|
csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
|
||||||
|
csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true
|
||||||
|
csharp_style_allow_embedded_statements_on_same_line_experimental = true
|
||||||
|
|
||||||
|
#### C#-Formatierungsregeln ####
|
||||||
|
|
||||||
|
# Einstellungen für neue Zeilen
|
||||||
|
csharp_new_line_before_catch = true
|
||||||
|
csharp_new_line_before_else = true
|
||||||
|
csharp_new_line_before_finally = true
|
||||||
|
csharp_new_line_before_members_in_anonymous_types = true
|
||||||
|
csharp_new_line_before_members_in_object_initializers = true
|
||||||
|
csharp_new_line_before_open_brace = all
|
||||||
|
csharp_new_line_between_query_expression_clauses = true
|
||||||
|
|
||||||
|
# Einstellungen für Einrückung
|
||||||
|
csharp_indent_block_contents = true
|
||||||
|
csharp_indent_braces = false
|
||||||
|
csharp_indent_case_contents = true
|
||||||
|
csharp_indent_case_contents_when_block = true
|
||||||
|
csharp_indent_labels = one_less_than_current
|
||||||
|
csharp_indent_switch_labels = true
|
||||||
|
|
||||||
|
# Einstellungen für Abstände
|
||||||
|
csharp_space_after_cast = false
|
||||||
|
csharp_space_after_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_after_comma = true
|
||||||
|
csharp_space_after_dot = false
|
||||||
|
csharp_space_after_keywords_in_control_flow_statements = true
|
||||||
|
csharp_space_after_semicolon_in_for_statement = true
|
||||||
|
csharp_space_around_binary_operators = before_and_after
|
||||||
|
csharp_space_around_declaration_statements = false
|
||||||
|
csharp_space_before_colon_in_inheritance_clause = true
|
||||||
|
csharp_space_before_comma = false
|
||||||
|
csharp_space_before_dot = false
|
||||||
|
csharp_space_before_open_square_brackets = false
|
||||||
|
csharp_space_before_semicolon_in_for_statement = false
|
||||||
|
csharp_space_between_empty_square_brackets = false
|
||||||
|
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||||
|
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||||
|
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||||
|
csharp_space_between_parentheses = false
|
||||||
|
csharp_space_between_square_brackets = false
|
||||||
|
|
||||||
|
# Umbrucheinstellungen
|
||||||
|
csharp_preserve_single_line_blocks = true
|
||||||
|
csharp_preserve_single_line_statements = true
|
||||||
|
|
||||||
|
#### Benennungsstile ####
|
||||||
|
|
||||||
|
# Benennungsregeln
|
||||||
|
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
|
||||||
|
dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
|
||||||
|
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.symbols = types
|
||||||
|
dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
|
||||||
|
dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
|
||||||
|
|
||||||
|
# Symbolspezifikationen
|
||||||
|
|
||||||
|
dotnet_naming_symbols.interface.applicable_kinds = interface
|
||||||
|
dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.interface.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
|
||||||
|
dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.types.required_modifiers =
|
||||||
|
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
|
||||||
|
dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
|
||||||
|
dotnet_naming_symbols.non_field_members.required_modifiers =
|
||||||
|
|
||||||
|
# Benennungsstile
|
||||||
|
|
||||||
|
dotnet_naming_style.pascal_case.required_prefix =
|
||||||
|
dotnet_naming_style.pascal_case.required_suffix =
|
||||||
|
dotnet_naming_style.pascal_case.word_separator =
|
||||||
|
dotnet_naming_style.pascal_case.capitalization = pascal_case
|
||||||
|
|
||||||
|
dotnet_naming_style.begins_with_i.required_prefix = I
|
||||||
|
dotnet_naming_style.begins_with_i.required_suffix =
|
||||||
|
dotnet_naming_style.begins_with_i.word_separator =
|
||||||
|
dotnet_naming_style.begins_with_i.capitalization = pascal_case
|
||||||
|
|
||||||
|
[*.{cs,vb}]
|
||||||
|
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||||
|
end_of_line = crlf
|
||||||
|
tab_width = 4
|
||||||
|
indent_size = 4
|
||||||
|
dotnet_style_coalesce_expression = true:suggestion
|
||||||
|
dotnet_style_null_propagation = true:suggestion
|
||||||
|
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||||
|
dotnet_style_prefer_auto_properties = true:silent
|
||||||
|
dotnet_style_object_initializer = true:suggestion
|
||||||
|
dotnet_style_collection_initializer = true:suggestion
|
||||||
|
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||||
|
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||||
|
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||||
|
dotnet_style_explicit_tuple_names = true:suggestion
|
||||||
|
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||||
|
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||||
|
dotnet_style_prefer_compound_assignment = true:suggestion
|
||||||
|
dotnet_style_prefer_simplified_interpolation = true:suggestion
|
||||||
|
dotnet_style_namespace_match_folder = true:suggestion
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -339,3 +339,4 @@ ASALocalRun/
|
|||||||
# BeatPulse healthcheck temp database
|
# BeatPulse healthcheck temp database
|
||||||
healthchecksdb
|
healthchecksdb
|
||||||
.ionide
|
.ionide
|
||||||
|
/tools
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
[assembly:ThemeInfo(
|
|
||||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
|
||||||
//(used if a resource is not found in the page,
|
|
||||||
// or application resource dictionaries)
|
|
||||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
|
||||||
//(used if a resource is not found in the page,
|
|
||||||
// app, or any theme specific resource dictionaries)
|
|
||||||
)]
|
|
@ -1,3 +0,0 @@
|
|||||||
global using System;
|
|
||||||
global using MvvmGen;
|
|
||||||
global using System.Windows;
|
|
@ -1,13 +0,0 @@
|
|||||||
namespace ModernWpfPlayground
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for MainWindow.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class MainWindow
|
|
||||||
{
|
|
||||||
public MainWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,85 +0,0 @@
|
|||||||
using ModernWpfPlayground.Types;
|
|
||||||
using static ModernWpf.ThemeManager;
|
|
||||||
|
|
||||||
namespace ModernWpfPlayground
|
|
||||||
{
|
|
||||||
// ReSharper disable once ClassNeverInstantiated.Global
|
|
||||||
[ViewModel]
|
|
||||||
public partial class MainWindowViewModel
|
|
||||||
{
|
|
||||||
private const string AppName = "TaBEA 3.0.0";
|
|
||||||
|
|
||||||
[Property, PropertyCallMethod(nameof(SetTitle))]
|
|
||||||
private string? _path;
|
|
||||||
|
|
||||||
[Property] private string _title = AppName;
|
|
||||||
|
|
||||||
[Property, PropertyCallMethod(nameof(BooleanValue_OnChanged))]
|
|
||||||
private bool _booleanValue = true;
|
|
||||||
|
|
||||||
[Property] private Visibility _visibilityEnumTest = Visibility.Visible;
|
|
||||||
[Property] private double _sliderTest = 100;
|
|
||||||
[Property] private double _validationTest;
|
|
||||||
[Property] private string? _welcomeMessage = "Shadow of the empire";
|
|
||||||
|
|
||||||
[Property, PropertyCallMethod(nameof(SetTheme))]
|
|
||||||
private ThemeMode _themeMode = ThemeMode.UseSystemSetting;
|
|
||||||
|
|
||||||
[Property, PropertyCallMethod(nameof(SetAccentColor))]
|
|
||||||
private AccentColors _accentColors = AccentColors.Green;
|
|
||||||
|
|
||||||
[Property] private int _windowWidth = 1200;
|
|
||||||
[Property] private int _windowHeight = 600;
|
|
||||||
[Property] private bool _isPaneOpen = true;
|
|
||||||
|
|
||||||
|
|
||||||
[Command]
|
|
||||||
private void ShowNotification()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command]
|
|
||||||
private void Close()
|
|
||||||
{
|
|
||||||
Application.Current.MainWindow?.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetTitle()
|
|
||||||
{
|
|
||||||
Title = Path != null ? $"{System.IO.Path.GetFileName(Path)} - {AppName}" : AppName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void SetAccentColor() => Current.AccentColor = AccentColors.ToWindowsColor();
|
|
||||||
|
|
||||||
|
|
||||||
private void SetTheme() => Current.ApplicationTheme = ThemeMode.ToApplicationTheme();
|
|
||||||
|
|
||||||
[Command]
|
|
||||||
private async void ShowDialog()
|
|
||||||
{
|
|
||||||
var dialog = new ContentDialogExample { Message = WelcomeMessage };
|
|
||||||
var result = await dialog.ShowAsync();
|
|
||||||
WelcomeMessage = result.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BooleanValue_OnChanged()
|
|
||||||
{
|
|
||||||
VisibilityEnumTest = BooleanValue ? Visibility.Visible : Visibility.Collapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Command]
|
|
||||||
private void SaveViewModel()
|
|
||||||
{
|
|
||||||
// var contents = _serializer.Serialize(Values);
|
|
||||||
// if (Path is null)
|
|
||||||
// {
|
|
||||||
// var saveFileDialog = new SaveFileDialog {AddExtension = true, DefaultExt = "*.yaml"};
|
|
||||||
// var result = saveFileDialog.ShowDialog(Application.Current.MainWindow?.Owner);
|
|
||||||
// if (result != true) return;
|
|
||||||
// Path = saveFileDialog.FileName;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// File.WriteAllText(Path, contents);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<OutputType>WinExe</OutputType>
|
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
<PublishSingleFile>true</PublishSingleFile>
|
|
||||||
<SelfContained>true</SelfContained>
|
|
||||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="FastMember" Version="1.5.0" />
|
|
||||||
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
|
|
||||||
<PackageReference Include="ModernWpfUis" Version="1.2.0" />
|
|
||||||
<PackageReference Include="MvvmGen" Version="1.1.1" />
|
|
||||||
<PackageReference Include="YamlDotNet" Version="11.2.1" />
|
|
||||||
<PackageReference Include="MahApps.Metro.IconPacks.FontAwesome" Version="4.11.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Controls\Controls.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="MvvmStuff" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,29 +0,0 @@
|
|||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace ModernWpfPlayground.Types
|
|
||||||
{
|
|
||||||
public enum AccentColors
|
|
||||||
{
|
|
||||||
Green,
|
|
||||||
Yellow,
|
|
||||||
Blue,
|
|
||||||
Purple,
|
|
||||||
Red
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AccentColorExtension
|
|
||||||
{
|
|
||||||
public static Color ToWindowsColor(this AccentColors accentColor)
|
|
||||||
{
|
|
||||||
return accentColor switch
|
|
||||||
{
|
|
||||||
AccentColors.Green => Color.FromRgb(0, 86, 76),
|
|
||||||
AccentColors.Yellow => Color.FromRgb(164, 144, 0),
|
|
||||||
AccentColors.Blue => Color.FromRgb(0, 120, 215),
|
|
||||||
AccentColors.Purple => Color.FromRgb(104, 33, 122),
|
|
||||||
AccentColors.Red => Color.FromRgb(183, 71, 42),
|
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(accentColor), accentColor, null)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
@ -1,9 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows.Markup;
|
|
||||||
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
[assembly: CLSCompliant(true)]
|
|
||||||
|
|
||||||
[assembly: XmlnsDefinition("http://wpflib.de/", "Controls")]
|
|
@ -1,49 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Markup;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Converts enums to a List with KeyValuePairs.
|
|
||||||
/// </summary>
|
|
||||||
public class EnumToItemSourceConverter : MarkupExtension, IValueConverter
|
|
||||||
{
|
|
||||||
private static EnumToItemSourceConverter? _converter;
|
|
||||||
|
|
||||||
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
if (value is not Enum) return Binding.DoNothing;
|
|
||||||
return (from object enumValue in Enum.GetValues(value.GetType())
|
|
||||||
select new KeyValuePair<string, object>(GetDescription(enumValue), enumValue)).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the content of a description attribute of an enum.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static string GetDescription(object value)
|
|
||||||
{
|
|
||||||
if (value is not Enum enumValue) return string.Empty;
|
|
||||||
var descriptionAttribute = enumValue.GetType()
|
|
||||||
.GetField(enumValue.ToString())?
|
|
||||||
.GetCustomAttributes(false)
|
|
||||||
.OfType<DescriptionAttribute>()
|
|
||||||
.FirstOrDefault();
|
|
||||||
|
|
||||||
return descriptionAttribute?.Description ?? value.ToString() ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return Binding.DoNothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ProvideValue(IServiceProvider serviceProvider) => _converter ??= new EnumToItemSourceConverter();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Markup;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for <see cref="MagicSymbolControl"/>
|
|
||||||
/// </summary>
|
|
||||||
[ContentProperty(nameof(Symbol))]
|
|
||||||
public class MagicSymbolControl : ContentControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Dependency property for <see cref="Symbol"/> property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(nameof(Symbol), typeof(object), typeof(MagicSymbolControl), new PropertyMetadata(default, PropertyChangedCallback));
|
|
||||||
|
|
||||||
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (d is MagicSymbolControl magic)
|
|
||||||
{
|
|
||||||
magic.Content = MagicSymbolConverter.ConvertToFrameworkElement(e.NewValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Symbol to show
|
|
||||||
/// </summary>
|
|
||||||
public object Symbol
|
|
||||||
{
|
|
||||||
get => GetValue(SymbolProperty);
|
|
||||||
set => SetValue(SymbolProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new instance of <see cref="MagicSymbolControl"/>
|
|
||||||
/// </summary>
|
|
||||||
public MagicSymbolControl()
|
|
||||||
{
|
|
||||||
Focusable = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Magically converts a text to
|
|
||||||
/// </summary>
|
|
||||||
[ValueConversion(typeof(string), typeof(FrameworkElement))]
|
|
||||||
public class MagicSymbolConverter : IValueConverter
|
|
||||||
{
|
|
||||||
private const string NoParseKeyword = "noParse:";
|
|
||||||
private const string PathKeyword = "path:";
|
|
||||||
private const string DynResKeyword = "dynRes:";
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return ConvertToFrameworkElement(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Convert string to Framework element.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static object ConvertToFrameworkElement(object value)
|
|
||||||
{
|
|
||||||
var data = value as string;
|
|
||||||
if (string.IsNullOrWhiteSpace(data)) return value; //maybe not a string. eventually something else.
|
|
||||||
|
|
||||||
if (data.StartsWith(NoParseKeyword, StringComparison.Ordinal)) return data[NoParseKeyword.Length..];
|
|
||||||
|
|
||||||
if (data.StartsWith(PathKeyword, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var path = data[PathKeyword.Length..];
|
|
||||||
var icon = ObjectImageConverter.GetIcon(Geometry.Parse(path), Brushes.Black);
|
|
||||||
return new Image
|
|
||||||
{
|
|
||||||
Source = icon,
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Right,
|
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
|
||||||
Height = 16
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.StartsWith(DynResKeyword, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var resourceKey = data[DynResKeyword.Length..];
|
|
||||||
//get icon from resource dictionary
|
|
||||||
return new Image
|
|
||||||
{
|
|
||||||
Source = Application.Current.FindResource(resourceKey) as ImageSource,
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Right,
|
|
||||||
VerticalAlignment = VerticalAlignment.Center,
|
|
||||||
Height = 16
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var textComponents = ParseText(data);
|
|
||||||
return CreateTextBlock(textComponents);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextBlock CreateTextBlock(IEnumerable<TextComponent> textComponents)
|
|
||||||
{
|
|
||||||
//create text block
|
|
||||||
var block = new TextBlock();
|
|
||||||
foreach (var tc in textComponents)
|
|
||||||
{
|
|
||||||
var run = new Run(tc.Text) {FontFamily = new FontFamily("Palatino Linotype"), FontSize = 16};
|
|
||||||
switch (tc.Style)
|
|
||||||
{
|
|
||||||
case BaselineAlignment.Subscript:
|
|
||||||
run.BaselineAlignment = BaselineAlignment.Subscript;
|
|
||||||
run.FontSize = 12;
|
|
||||||
break;
|
|
||||||
case BaselineAlignment.Superscript:
|
|
||||||
run.BaselineAlignment = BaselineAlignment.Superscript;
|
|
||||||
run.FontSize = 12;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
block.Inlines.Add(run);
|
|
||||||
}
|
|
||||||
|
|
||||||
block.HorizontalAlignment = HorizontalAlignment.Right;
|
|
||||||
block.VerticalAlignment = VerticalAlignment.Center;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<TextComponent> ParseText(string data)
|
|
||||||
{
|
|
||||||
//parse text
|
|
||||||
var textComponents = new List<TextComponent>();
|
|
||||||
var alignment = BaselineAlignment.Baseline;
|
|
||||||
var snippet = new StringBuilder();
|
|
||||||
foreach (var c in data)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '~':
|
|
||||||
if (snippet.Length > 0)
|
|
||||||
{
|
|
||||||
var comp = new TextComponent(snippet.ToString(), alignment);
|
|
||||||
textComponents.Add(comp);
|
|
||||||
snippet.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
alignment = alignment == BaselineAlignment.Subscript
|
|
||||||
? BaselineAlignment.Baseline
|
|
||||||
: BaselineAlignment.Subscript;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
if (snippet.Length > 0)
|
|
||||||
{
|
|
||||||
var comp = new TextComponent(snippet.ToString(), alignment);
|
|
||||||
textComponents.Add(comp);
|
|
||||||
snippet.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
alignment = alignment == BaselineAlignment.Superscript
|
|
||||||
? BaselineAlignment.Baseline
|
|
||||||
: BaselineAlignment.Superscript;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
snippet.Append(c);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (snippet.Length > 0)
|
|
||||||
{
|
|
||||||
var comp = new TextComponent(snippet.ToString(), alignment);
|
|
||||||
textComponents.Add(comp);
|
|
||||||
snippet.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return textComponents;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
=> Binding.DoNothing;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Selects the right template on base of value-type.
|
|
||||||
/// </summary>
|
|
||||||
public class PropertyDataTemplateSelector : DataTemplateSelector
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Default data template. (currently Textbox)
|
|
||||||
/// </summary>
|
|
||||||
public DataTemplate? DefaultDataTemplate { private get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data template for boolean. (currently Checkbox)
|
|
||||||
/// </summary>
|
|
||||||
public DataTemplate? BooleanDataTemplate { private get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Data template for enums. (currently Combobox)
|
|
||||||
/// </summary>
|
|
||||||
public DataTemplate? EnumComboBoxDataTemplate { private get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override DataTemplate? SelectTemplate(object item, DependencyObject container)
|
|
||||||
{
|
|
||||||
return item switch
|
|
||||||
{
|
|
||||||
bool _ => BooleanDataTemplate,
|
|
||||||
Enum _ => EnumComboBoxDataTemplate,
|
|
||||||
UIElement _ => null,
|
|
||||||
_ => DefaultDataTemplate
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,181 +0,0 @@
|
|||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Markup;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <inheritdoc cref="ContentControl" />
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for PropertyPresenter.xaml
|
|
||||||
/// </summary>
|
|
||||||
[ContentProperty(nameof(Value))]
|
|
||||||
public sealed partial class PropertyPresenter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Button alignment property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty ButtonAlignmentProperty = DependencyProperty.Register(nameof(ButtonAlignment), typeof(Dock), typeof(PropertyPresenter), new PropertyMetadata(Dock.Right));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content of the command property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty CommandContentProperty = DependencyProperty.Register(nameof(CommandContent), typeof(object), typeof(PropertyPresenter), new PropertyMetadata("..."));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command Parameter property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(PropertyPresenter), new PropertyMetadata(default(object)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(PropertyPresenter), new PropertyMetadata(default(ICommand)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// is checked property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(nameof(IsChecked), typeof(bool?), typeof(PropertyPresenter), new FrameworkPropertyMetadata(default(bool?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Is readonly property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(PropertyPresenter), new PropertyMetadata(default(bool)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Label property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(PropertyPresenter), new PropertyMetadata(default(string)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// label width property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register(nameof(LabelWidth), typeof(double), typeof(PropertyPresenter), new PropertyMetadata(150.0));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Symbol Property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(nameof(Symbol), typeof(object), typeof(PropertyPresenter), new PropertyMetadata(default(object)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Value Property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(nameof(Value), typeof(object), typeof(PropertyPresenter), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Watermark Property
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(nameof(Watermark), typeof(string), typeof(PropertyPresenter), new FrameworkPropertyMetadata(default(string)));
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public PropertyPresenter()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Button alignment.
|
|
||||||
/// </summary>
|
|
||||||
public Dock ButtonAlignment
|
|
||||||
{
|
|
||||||
get => (Dock)GetValue(ButtonAlignmentProperty);
|
|
||||||
set => SetValue(ButtonAlignmentProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command.
|
|
||||||
/// </summary>
|
|
||||||
public ICommand? Command
|
|
||||||
{
|
|
||||||
get => (ICommand)GetValue(CommandProperty);
|
|
||||||
set => SetValue(CommandProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command content.
|
|
||||||
/// </summary>
|
|
||||||
public object? CommandContent
|
|
||||||
{
|
|
||||||
get => GetValue(CommandContentProperty);
|
|
||||||
set => SetValue(CommandContentProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Command parameter.
|
|
||||||
/// </summary>
|
|
||||||
public object? CommandParameter
|
|
||||||
{
|
|
||||||
get => GetValue(CommandParameterProperty);
|
|
||||||
set => SetValue(CommandParameterProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// IsChecked.
|
|
||||||
/// </summary>
|
|
||||||
public bool? IsChecked
|
|
||||||
{
|
|
||||||
get => (bool?)GetValue(IsCheckedProperty);
|
|
||||||
set => SetValue(IsCheckedProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// IsReadOnly
|
|
||||||
/// </summary>
|
|
||||||
public bool IsReadOnly
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(IsReadOnlyProperty);
|
|
||||||
set => SetValue(IsReadOnlyProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Label.
|
|
||||||
/// </summary>
|
|
||||||
public string? Label
|
|
||||||
{
|
|
||||||
get => (string)GetValue(LabelProperty);
|
|
||||||
set => SetValue(LabelProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Label width.
|
|
||||||
/// </summary>
|
|
||||||
public double LabelWidth
|
|
||||||
{
|
|
||||||
get => (double)GetValue(LabelWidthProperty);
|
|
||||||
set => SetValue(LabelWidthProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Symbol.
|
|
||||||
/// </summary>
|
|
||||||
public object? Symbol
|
|
||||||
{
|
|
||||||
get => GetValue(SymbolProperty);
|
|
||||||
set => SetValue(SymbolProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Value.
|
|
||||||
/// </summary>
|
|
||||||
public object? Value
|
|
||||||
{
|
|
||||||
get => GetValue(ValueProperty);
|
|
||||||
set => SetValue(ValueProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Watermark.
|
|
||||||
/// </summary>
|
|
||||||
public string Watermark
|
|
||||||
{
|
|
||||||
get => (string)GetValue(WatermarkProperty);
|
|
||||||
set => SetValue(WatermarkProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{base.ToString()} {Value}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,165 +0,0 @@
|
|||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a TextBox that can update the binding on enter.
|
|
||||||
/// </summary>
|
|
||||||
public class TextBoxEx : TextBox
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Identifies the <see cref="MoveFocusOnEnter"/> dependency property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty MoveFocusOnEnterProperty =
|
|
||||||
DependencyProperty.Register(
|
|
||||||
"MoveFocusOnEnter", typeof(bool), typeof(TextBoxEx), new UIPropertyMetadata(true));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Identifies the <see cref="UpdateBindingOnEnter"/> dependency property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty UpdateBindingOnEnterProperty =
|
|
||||||
DependencyProperty.Register(
|
|
||||||
"UpdateBindingOnEnter", typeof(bool), typeof(TextBoxEx), new UIPropertyMetadata(true));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Identifies the <see cref="ScrollToHomeOnFocus"/> dependency property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty ScrollToHomeOnFocusProperty =
|
|
||||||
DependencyProperty.Register("ScrollToHomeOnFocus", typeof(bool), typeof(TextBoxEx), new PropertyMetadata(true));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Identifies the <see cref="SelectAllOnFocus"/> dependency property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty SelectAllOnFocusProperty =
|
|
||||||
DependencyProperty.Register("SelectAllOnFocus", typeof(bool), typeof(TextBoxEx), new PropertyMetadata(true));
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="T:Controls.TextBoxEx" /> class.
|
|
||||||
/// </summary>
|
|
||||||
public TextBoxEx()
|
|
||||||
{
|
|
||||||
GotKeyboardFocus += HandleGotKeyboardFocus;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether to select all on focus.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// <c>true</c> if all should be selected; otherwise, <c>false</c>.
|
|
||||||
/// </value>
|
|
||||||
public bool SelectAllOnFocus
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(SelectAllOnFocusProperty);
|
|
||||||
set => SetValue(SelectAllOnFocusProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether to scroll to home on focus.
|
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
|
||||||
/// <c>true</c> if scroll is enabled; otherwise, <c>false</c>.
|
|
||||||
/// </value>
|
|
||||||
public bool ScrollToHomeOnFocus
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(ScrollToHomeOnFocusProperty);
|
|
||||||
set => SetValue(ScrollToHomeOnFocusProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether MoveFocusOnEnter.
|
|
||||||
/// </summary>
|
|
||||||
public bool MoveFocusOnEnter
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(MoveFocusOnEnterProperty);
|
|
||||||
|
|
||||||
set => SetValue(MoveFocusOnEnterProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether UpdateBindingOnEnter.
|
|
||||||
/// </summary>
|
|
||||||
public bool UpdateBindingOnEnter
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(UpdateBindingOnEnterProperty);
|
|
||||||
|
|
||||||
set => SetValue(UpdateBindingOnEnterProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnPreviewKeyDown(e);
|
|
||||||
switch (e.Key)
|
|
||||||
{
|
|
||||||
case Key.Enter:
|
|
||||||
if (!AcceptsReturn)
|
|
||||||
{
|
|
||||||
if (UpdateBindingOnEnter)
|
|
||||||
{
|
|
||||||
// get the binding to the Text property
|
|
||||||
var bindingExpression = GetBindingExpression(TextProperty);
|
|
||||||
// update the source (do not update the target)
|
|
||||||
bindingExpression?.UpdateSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (MoveFocusOnEnter)
|
|
||||||
{
|
|
||||||
// Move focus to next element
|
|
||||||
// http://madprops.org/blog/enter-to-tab-in-wpf/
|
|
||||||
if (e.OriginalSource is UIElement uiElement)
|
|
||||||
{
|
|
||||||
var shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
|
||||||
uiElement.MoveFocus(new TraversalRequest(shift ? FocusNavigationDirection.Previous : FocusNavigationDirection.Next));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case Key.Escape:
|
|
||||||
Undo();
|
|
||||||
SelectAll();
|
|
||||||
e.Handled = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
base.OnPreviewMouseLeftButtonDown(e);
|
|
||||||
|
|
||||||
if (!IsKeyboardFocusWithin)
|
|
||||||
{
|
|
||||||
SelectAll();
|
|
||||||
Focus();
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Handles the got keyboard focus event.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="sender">The sender.</param>
|
|
||||||
/// <param name="e">The <see cref="KeyboardFocusChangedEventArgs" /> instance containing the event data.</param>
|
|
||||||
private void HandleGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (SelectAllOnFocus)
|
|
||||||
{
|
|
||||||
SelectAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ScrollToHomeOnFocus)
|
|
||||||
{
|
|
||||||
ScrollToHome();
|
|
||||||
}
|
|
||||||
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A component of the symbol
|
|
||||||
/// </summary>
|
|
||||||
public readonly struct TextComponent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Constructor
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text"></param>
|
|
||||||
/// <param name="style"></param>
|
|
||||||
public TextComponent(string text, BaselineAlignment style = BaselineAlignment.Baseline)
|
|
||||||
{
|
|
||||||
Text = text;
|
|
||||||
Style = style;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Text of the symbol component
|
|
||||||
/// </summary>
|
|
||||||
public readonly string Text;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Style of the symbol component
|
|
||||||
/// </summary>
|
|
||||||
public readonly BaselineAlignment Style;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Net;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using Brush = System.Windows.Media.Brush;
|
|
||||||
using Brushes = System.Windows.Media.Brushes;
|
|
||||||
using FontFamily = System.Windows.Media.FontFamily;
|
|
||||||
using Point = System.Windows.Point;
|
|
||||||
|
|
||||||
namespace Controls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Makes an Bitmap from every Imageformat.
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ObjectImageConverter : IValueConverter
|
|
||||||
{
|
|
||||||
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
const string dynResPrefix = "dynRes:";
|
|
||||||
if (value is Bitmap bitmap)
|
|
||||||
{
|
|
||||||
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(16, 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value is not string strValue) return Binding.DoNothing;
|
|
||||||
if (strValue.StartsWith(dynResPrefix, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var resource = Application.Current.TryFindResource(strValue.Replace(dynResPrefix, string.Empty , StringComparison.InvariantCulture));
|
|
||||||
return resource is ImageSource source ? source : Binding.DoNothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strValue.StartsWith("text:", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var parts = strValue.Split(':');
|
|
||||||
return parts.Length == 3 ? DrawText(WebUtility.HtmlDecode(parts[2]), parts[1], Brushes.Black) : Binding.DoNothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetIcon(Geometry.Parse(strValue), null);
|
|
||||||
}
|
|
||||||
|
|
||||||
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) =>
|
|
||||||
Binding.DoNothing;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get icon a ImageSource from geometry.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="geometry">geometry</param>
|
|
||||||
/// <param name="brush">color of the icon</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static ImageSource GetIcon(Geometry geometry, Brush? brush)
|
|
||||||
{
|
|
||||||
if (brush == null)
|
|
||||||
brush = Brushes.Black;
|
|
||||||
var drawing = new GeometryDrawing(brush, null, geometry);
|
|
||||||
return new DrawingImage(drawing);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Draw text as ImageSource from string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">the text</param>
|
|
||||||
/// <param name="strFontFamily">font of the string</param>
|
|
||||||
/// <param name="brush">color of the string</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static ImageSource DrawText(string text, string strFontFamily, Brush brush)
|
|
||||||
{
|
|
||||||
var fontFamily = new FontFamily(strFontFamily);
|
|
||||||
var formattedText = new FormattedText(text,
|
|
||||||
CultureInfo.GetCultureInfo("en-us"),
|
|
||||||
FlowDirection.LeftToRight,
|
|
||||||
new Typeface(
|
|
||||||
fontFamily,
|
|
||||||
FontStyles.Normal,
|
|
||||||
FontWeights.Normal,
|
|
||||||
FontStretches.Normal),
|
|
||||||
64, brush, 1.5);
|
|
||||||
|
|
||||||
var geometry = formattedText.BuildGeometry(new Point(0, 0));
|
|
||||||
return GetIcon(geometry, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invert boolean converter
|
|
||||||
/// </summary>
|
|
||||||
[ValueConversion(typeof(bool), typeof(bool))]
|
|
||||||
public class InverseBooleanConverter : IValueConverter
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) =>
|
|
||||||
value is bool b ? !b : throw new InvalidOperationException("The target must be a boolean");
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,13 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 16.0.30002.166
|
VisualStudioVersion = 17.0.31912.275
|
||||||
MinimumVisualStudioVersion = 15.0.26124.0
|
MinimumVisualStudioVersion = 15.0.26124.0
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernWpfPlayground", "App\ModernWpfPlayground.csproj", "{E090F4BD-69CD-4D8B-A3A2-620DCE22AE29}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{216EA1DF-5F39-4D23-9E1F-887785D1FF6C}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Controls", "Controls\Controls.csproj", "{3884FD41-5A46-4A67-A147-57C36F0059DC}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ModernWpfPlayground", "src\App\ModernWpfPlayground.csproj", "{D7364CD3-5150-4FA8-90D9-07093354D7A0}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Controls", "src\Controls\Controls.csproj", "{3AAA0309-C1C0-44C8-A53F-E3CE8556A4D4}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -13,18 +15,22 @@ Global
|
|||||||
Release|Any CPU = Release|Any CPU
|
Release|Any CPU = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
{E090F4BD-69CD-4D8B-A3A2-620DCE22AE29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{D7364CD3-5150-4FA8-90D9-07093354D7A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{E090F4BD-69CD-4D8B-A3A2-620DCE22AE29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D7364CD3-5150-4FA8-90D9-07093354D7A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{E090F4BD-69CD-4D8B-A3A2-620DCE22AE29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D7364CD3-5150-4FA8-90D9-07093354D7A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{E090F4BD-69CD-4D8B-A3A2-620DCE22AE29}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D7364CD3-5150-4FA8-90D9-07093354D7A0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{3884FD41-5A46-4A67-A147-57C36F0059DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{3AAA0309-C1C0-44C8-A53F-E3CE8556A4D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{3884FD41-5A46-4A67-A147-57C36F0059DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{3AAA0309-C1C0-44C8-A53F-E3CE8556A4D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{3884FD41-5A46-4A67-A147-57C36F0059DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{3AAA0309-C1C0-44C8-A53F-E3CE8556A4D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{3884FD41-5A46-4A67-A147-57C36F0059DC}.Release|Any CPU.Build.0 = Release|Any CPU
|
{3AAA0309-C1C0-44C8-A53F-E3CE8556A4D4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{D7364CD3-5150-4FA8-90D9-07093354D7A0} = {216EA1DF-5F39-4D23-9E1F-887785D1FF6C}
|
||||||
|
{3AAA0309-C1C0-44C8-A53F-E3CE8556A4D4} = {216EA1DF-5F39-4D23-9E1F-887785D1FF6C}
|
||||||
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {21075E5E-39D9-4681-91A0-D9E7E0BDBB85}
|
SolutionGuid = {21075E5E-39D9-4681-91A0-D9E7E0BDBB85}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
60
build.cake
Normal file
60
build.cake
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#tool "dotnet:?package=GitVersion.Tool"
|
||||||
|
|
||||||
|
using System;
|
||||||
|
var target = Argument("target", "Publish");
|
||||||
|
var configuration = Argument("configuration", "Release");
|
||||||
|
|
||||||
|
var gitVersion = GitVersion(new GitVersionSettings());
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// TASKS
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
Task("Clean")
|
||||||
|
.WithCriteria(c => HasArgument("rebuild"))
|
||||||
|
.Does(() =>
|
||||||
|
{
|
||||||
|
CleanDirectory($"./src/App/bin/{configuration}");
|
||||||
|
});
|
||||||
|
|
||||||
|
Task("Build")
|
||||||
|
.IsDependentOn("Clean")
|
||||||
|
.Does(() =>
|
||||||
|
{
|
||||||
|
DotNetBuild("./ModernWpfPlayground.sln", new DotNetBuildSettings
|
||||||
|
{
|
||||||
|
Configuration = configuration, ArgumentCustomization = c=> c.Append($"/p:Version={gitVersion.AssemblySemVer}")
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Task("Publish")
|
||||||
|
.IsDependentOn("Build")
|
||||||
|
.Does(() =>
|
||||||
|
{
|
||||||
|
DotNetPublish("./src/App/ModernWpfPlayground.csproj", new DotNetPublishSettings{
|
||||||
|
Configuration = configuration,
|
||||||
|
EnableCompressionInSingleFile = true,
|
||||||
|
PublishReadyToRun = true,
|
||||||
|
PublishSingleFile = true,
|
||||||
|
Runtime = "win-x64",
|
||||||
|
SelfContained = true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Task("Test")
|
||||||
|
// .IsDependentOn("Build")
|
||||||
|
// .Does(() =>
|
||||||
|
// {
|
||||||
|
// DotNetCoreTest("./src/Example.sln", new DotNetCoreTestSettings
|
||||||
|
// {
|
||||||
|
// Configuration = configuration,
|
||||||
|
// NoBuild = true,
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
// EXECUTION
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
RunTarget(target);
|
@ -1,4 +1,5 @@
|
|||||||
using ModernWpf;
|
using System.Windows;
|
||||||
|
using ModernWpf;
|
||||||
using ModernWpfPlayground.Types;
|
using ModernWpfPlayground.Types;
|
||||||
|
|
||||||
namespace ModernWpfPlayground
|
namespace ModernWpfPlayground
|
10
src/App/AssemblyInfo.cs
Normal file
10
src/App/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
@ -1,9 +1,10 @@
|
|||||||
namespace ModernWpfPlayground
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
{
|
{
|
||||||
public partial class ContentDialogExample
|
public partial class ContentDialogExample
|
||||||
{
|
{
|
||||||
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
|
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register("Message", typeof(string), typeof(ContentDialogExample), new PropertyMetadata(default(string)));
|
||||||
"Message", typeof(string), typeof(ContentDialogExample), new PropertyMetadata(default(string)));
|
|
||||||
|
|
||||||
public string? Message
|
public string? Message
|
||||||
{
|
{
|
23
src/App/DivideByHundredConverter.cs
Normal file
23
src/App/DivideByHundredConverter.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground;
|
||||||
|
|
||||||
|
public class DivideByHundredConverter : MarkupExtension, IValueConverter
|
||||||
|
{
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return (double)value / 100d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
x:Class="ModernWpfPlayground.MainWindow"
|
x:Class="ModernWpfPlayground.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:controls="http://wpflib.de/"
|
xmlns:controls="clr-namespace:Controls;assembly=Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
|
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
|
||||||
xmlns:local="clr-namespace:ModernWpfPlayground"
|
xmlns:local="clr-namespace:ModernWpfPlayground"
|
||||||
@ -27,7 +27,11 @@
|
|||||||
<KeyBinding Key="S" Modifiers="Control" />
|
<KeyBinding Key="S" Modifiers="Control" />
|
||||||
<KeyBinding Key="N" Modifiers="Control" />
|
<KeyBinding Key="N" Modifiers="Control" />
|
||||||
</Window.InputBindings>
|
</Window.InputBindings>
|
||||||
|
<Window.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<ScaleTransform x:Key="ZoomSliderScaleTransform" ScaleX="{Binding Value, ElementName=ZoomSlider, Converter={local:DivideByHundredConverter}}" ScaleY="{Binding Value, ElementName=ZoomSlider, Converter={local:DivideByHundredConverter}}" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Window.Resources>
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<!-- TitleBar -->
|
<!-- TitleBar -->
|
||||||
<Grid
|
<Grid
|
||||||
@ -49,6 +53,9 @@
|
|||||||
<ColumnDefinition Width="{Binding ElementName=Window, Path=(ui:TitleBar.SystemOverlayLeftInset), Converter={local:PixelsToGridLengthConverter}}" />
|
<ColumnDefinition Width="{Binding ElementName=Window, Path=(ui:TitleBar.SystemOverlayLeftInset), Converter={local:PixelsToGridLengthConverter}}" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="{Binding ElementName=Window, Path=(ui:TitleBar.SystemOverlayRightInset), Converter={local:PixelsToGridLengthConverter}}" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<Menu
|
<Menu
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@ -69,16 +76,6 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</Menu.Resources>
|
</Menu.Resources>
|
||||||
<MenuItem Header="File">
|
<MenuItem Header="File">
|
||||||
<MenuItem
|
|
||||||
Command="{Binding ResetViewModelCommand}"
|
|
||||||
Header="New"
|
|
||||||
Icon="{iconPacks:FontAwesome Kind=FileRegular}"
|
|
||||||
InputGestureText="Ctrl+N" />
|
|
||||||
<MenuItem
|
|
||||||
Command="{Binding OpenViewModelCommand}"
|
|
||||||
Header="Open"
|
|
||||||
Icon="{iconPacks:FontAwesome Kind=FolderOpenRegular}"
|
|
||||||
InputGestureText="Ctrl+O" />
|
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Command="{Binding SaveViewModelCommand}"
|
Command="{Binding SaveViewModelCommand}"
|
||||||
Header="Save"
|
Header="Save"
|
||||||
@ -110,12 +107,31 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontSize="13"
|
FontSize="13"
|
||||||
Text="{Binding ElementName=Window, Path=Title}" />
|
Text="{Binding ElementName=Window, Path=Title}" />
|
||||||
|
<Slider
|
||||||
|
x:Name="ZoomSlider"
|
||||||
|
Grid.Column="3"
|
||||||
|
Width="150"
|
||||||
|
AutoToolTipPlacement="TopLeft"
|
||||||
|
Interval="1"
|
||||||
|
IsSnapToTickEnabled="True"
|
||||||
|
Maximum="200"
|
||||||
|
Minimum="50"
|
||||||
|
TickFrequency="10"
|
||||||
|
TickPlacement="BottomRight"
|
||||||
|
WindowChrome.IsHitTestVisibleInChrome="True"
|
||||||
|
Value="100" />
|
||||||
|
<MenuItem
|
||||||
|
Grid.Column="4"
|
||||||
|
Click="MenuItem_OnClick"
|
||||||
|
Header="Reset"
|
||||||
|
WindowChrome.IsHitTestVisibleInChrome="True" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<Grid
|
<Grid
|
||||||
Height="24"
|
Height="24"
|
||||||
Background="{DynamicResource SystemControlBackgroundAccentBrush}"
|
Background="{DynamicResource SystemControlBackgroundAccentBrush}"
|
||||||
DockPanel.Dock="Bottom">
|
DockPanel.Dock="Bottom"
|
||||||
|
LayoutTransform="{StaticResource ZoomSliderScaleTransform}">
|
||||||
<Grid.Resources>
|
<Grid.Resources>
|
||||||
<Style TargetType="TextBlock">
|
<Style TargetType="TextBlock">
|
||||||
<Setter Property="Foreground" Value="White" />
|
<Setter Property="Foreground" Value="White" />
|
||||||
@ -137,7 +153,7 @@
|
|||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Text="BlaBlaBla" />
|
Text="BlaBlaBla" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid Row="1">
|
<Grid LayoutTransform="{StaticResource ZoomSliderScaleTransform}" Row="1">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="40" />
|
<ColumnDefinition Width="40" />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
@ -207,7 +223,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</ui:SplitView.Pane>
|
</ui:SplitView.Pane>
|
||||||
<!-- Content -->
|
<!-- Content -->
|
||||||
<TabControl>
|
<TabControl LayoutTransform="{StaticResource ZoomSliderScaleTransform}">
|
||||||
<TabItem Header="Bolt">
|
<TabItem Header="Bolt">
|
||||||
<ScrollViewer ui:ScrollViewerHelper.AutoHideScrollBars="True">
|
<ScrollViewer ui:ScrollViewerHelper.AutoHideScrollBars="True">
|
||||||
<Grid>
|
<Grid>
|
||||||
@ -221,10 +237,6 @@
|
|||||||
Margin="5"
|
Margin="5"
|
||||||
Orientation="Vertical"
|
Orientation="Vertical"
|
||||||
Spacing="5">
|
Spacing="5">
|
||||||
<Button
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Command="{Binding OpenViewModelCommand}"
|
|
||||||
Content="Open" />
|
|
||||||
<Button
|
<Button
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Command="{Binding SaveViewModelCommand}"
|
Command="{Binding SaveViewModelCommand}"
|
||||||
@ -233,16 +245,9 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem
|
<TabItem Header="General" IsSelected="True">
|
||||||
Header="General"
|
|
||||||
IsSelected="True">
|
|
||||||
<ScrollViewer ui:ScrollViewerHelper.AutoHideScrollBars="True">
|
<ScrollViewer ui:ScrollViewerHelper.AutoHideScrollBars="True">
|
||||||
<ui:SimpleStackPanel Margin="5" Spacing="10">
|
<ui:SimpleStackPanel Margin="5" Spacing="10">
|
||||||
<ComboBox
|
|
||||||
DisplayMemberPath="Key"
|
|
||||||
ItemsSource="{Binding ThemeMode, Converter={controls:EnumToItemSourceConverter}}"
|
|
||||||
SelectedValue="{Binding ThemeMode}"
|
|
||||||
SelectedValuePath="Value" />
|
|
||||||
<controls:PropertyPresenter Label="Theme Mode" Value="{Binding ThemeMode}" />
|
<controls:PropertyPresenter Label="Theme Mode" Value="{Binding ThemeMode}" />
|
||||||
<controls:PropertyPresenter Label="Accent color" Value="{Binding AccentColors}" />
|
<controls:PropertyPresenter Label="Accent color" Value="{Binding AccentColors}" />
|
||||||
<controls:PropertyPresenter
|
<controls:PropertyPresenter
|
21
src/App/MainWindow.xaml.cs
Normal file
21
src/App/MainWindow.xaml.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls.Primitives;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ZoomSlider.Value = 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
src/App/MainWindowViewModel.cs
Normal file
102
src/App/MainWindowViewModel.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using ModernWpfPlayground.Types;
|
||||||
|
using static ModernWpf.ThemeManager;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground
|
||||||
|
{
|
||||||
|
// ReSharper disable once ClassNeverInstantiated.Global
|
||||||
|
public partial class MainWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private const string AppName = "TaBEA 3.0.0";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _path;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string _title = AppName;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _booleanValue = true;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Visibility _visibilityEnumTest = Visibility.Visible;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private double _sliderTest = 100;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private double _validationTest;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string? _welcomeMessage = "Shadow of the empire";
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private ThemeMode _themeMode = ThemeMode.UseSystemSetting;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private AccentColors _accentColors = AccentColors.Green;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int _windowWidth = 1200;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private int _windowHeight = 600;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private bool _isPaneOpen = true;
|
||||||
|
|
||||||
|
partial void OnBooleanValueChanged(bool value)
|
||||||
|
{
|
||||||
|
VisibilityEnumTest = value ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnPathChanged(string? value)
|
||||||
|
{
|
||||||
|
Title = value != null ? $"{System.IO.Path.GetFileName(value)} - {AppName}" : AppName;
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void ShowNotification() { }
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void Close()
|
||||||
|
{
|
||||||
|
Application.Current.MainWindow?.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnThemeModeChanged(ThemeMode value)
|
||||||
|
{
|
||||||
|
Current.ApplicationTheme = value.ToApplicationTheme();
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnAccentColorsChanged(AccentColors value)
|
||||||
|
{
|
||||||
|
Current.AccentColor = value.ToWindowsColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private async void ShowDialog()
|
||||||
|
{
|
||||||
|
var dialog = new ContentDialogExample { Message = WelcomeMessage };
|
||||||
|
var result = await dialog.ShowAsync();
|
||||||
|
WelcomeMessage = result.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void SaveViewModel()
|
||||||
|
{
|
||||||
|
// var contents = _serializer.Serialize(Values);
|
||||||
|
// if (Path is null)
|
||||||
|
// {
|
||||||
|
// var saveFileDialog = new SaveFileDialog {AddExtension = true, DefaultExt = "*.yaml"};
|
||||||
|
// var result = saveFileDialog.ShowDialog(Application.Current.MainWindow?.Owner);
|
||||||
|
// if (result != true) return;
|
||||||
|
// Path = saveFileDialog.FileName;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// File.WriteAllText(Path, contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/App/ModernWpfPlayground.csproj
Normal file
40
src/App/ModernWpfPlayground.csproj
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Controls\Controls.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.1.0-preview1" />
|
||||||
|
<PackageReference Include="FastMember" Version="1.5.0" />
|
||||||
|
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
|
||||||
|
<PackageReference Include="ModernWpfUI" Version="0.9.7-preview.2" />
|
||||||
|
<PackageReference Include="YamlDotNet" Version="12.0.2" />
|
||||||
|
<PackageReference Include="MahApps.Metro.IconPacks.FontAwesome" Version="4.11.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Update="App.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="ContentDialogExample.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
</Page>
|
||||||
|
<Page Update="MainWindow.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
@ -1,4 +1,5 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Markup;
|
using System.Windows.Markup;
|
||||||
|
|
||||||
@ -18,7 +19,6 @@ namespace ModernWpfPlayground
|
|||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override object ProvideValue(IServiceProvider serviceProvider) =>
|
public override object ProvideValue(IServiceProvider serviceProvider) => _converter ??= new PixelsToGridLengthConverter();
|
||||||
_converter ??= new PixelsToGridLengthConverter();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
28
src/App/Types/AccentColors.cs
Normal file
28
src/App/Types/AccentColors.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace ModernWpfPlayground.Types;
|
||||||
|
|
||||||
|
public enum AccentColors
|
||||||
|
{
|
||||||
|
Green,
|
||||||
|
Yellow,
|
||||||
|
Blue,
|
||||||
|
Purple,
|
||||||
|
Red
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AccentColorExtension
|
||||||
|
{
|
||||||
|
public static Color ToWindowsColor(this AccentColors accentColor)
|
||||||
|
{
|
||||||
|
return accentColor switch
|
||||||
|
{
|
||||||
|
AccentColors.Green => Color.FromRgb(0, 86, 76),
|
||||||
|
AccentColors.Yellow => Color.FromRgb(164, 144, 0),
|
||||||
|
AccentColors.Blue => Color.FromRgb(0, 120, 215),
|
||||||
|
AccentColors.Purple => Color.FromRgb(104, 33, 122),
|
||||||
|
AccentColors.Red => Color.FromRgb(183, 71, 42),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(accentColor), accentColor, null)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,14 @@ namespace ModernWpfPlayground.Types
|
|||||||
{
|
{
|
||||||
public enum ThemeMode
|
public enum ThemeMode
|
||||||
{
|
{
|
||||||
[Description("Light")] Light,
|
[Description("Light")]
|
||||||
[Description("Dark")] Dark,
|
Light,
|
||||||
[Description("Use system setting")] UseSystemSetting
|
|
||||||
|
[Description("Dark")]
|
||||||
|
Dark,
|
||||||
|
|
||||||
|
[Description("Use system setting")]
|
||||||
|
UseSystemSetting
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ThemeModeExtension
|
public static class ThemeModeExtension
|
10
src/Controls/AssemblyInfo.cs
Normal file
10
src/Controls/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
21
src/Controls/Controls.csproj
Normal file
21
src/Controls/Controls.csproj
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Page Update="PropertyPresenter\PropertyPresenter.xaml">
|
||||||
|
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||||
|
</Page>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
||||||
|
</Project>
|
42
src/Controls/PropertyPresenter/EnumToItemSourceConverter.cs
Normal file
42
src/Controls/PropertyPresenter/EnumToItemSourceConverter.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts enums to a List with KeyValuePairs.
|
||||||
|
/// </summary>
|
||||||
|
public class EnumToItemSourceConverter : MarkupExtension, IValueConverter
|
||||||
|
{
|
||||||
|
private static EnumToItemSourceConverter? _converter;
|
||||||
|
|
||||||
|
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
if (value is not Enum)
|
||||||
|
return Binding.DoNothing;
|
||||||
|
return (from object enumValue in Enum.GetValues(value.GetType()) select new KeyValuePair<string, object>(GetDescription(enumValue), enumValue)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the content of a description attribute of an enum.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static string GetDescription(object value)
|
||||||
|
{
|
||||||
|
if (value is not Enum enumValue)
|
||||||
|
return string.Empty;
|
||||||
|
var descriptionAttribute = enumValue.GetType().GetField(enumValue.ToString())?.GetCustomAttributes(false).OfType<DescriptionAttribute>().FirstOrDefault();
|
||||||
|
|
||||||
|
return descriptionAttribute?.Description ?? value.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return Binding.DoNothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider) => _converter ??= new EnumToItemSourceConverter();
|
||||||
|
}
|
47
src/Controls/PropertyPresenter/MagicSymbolControl.cs
Normal file
47
src/Controls/PropertyPresenter/MagicSymbolControl.cs
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for <see cref="MagicSymbolControl"/>
|
||||||
|
/// </summary>
|
||||||
|
[ContentProperty(nameof(Symbol))]
|
||||||
|
public class MagicSymbolControl : ContentControl
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Dependency property for <see cref="Symbol"/> property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(
|
||||||
|
nameof(Symbol),
|
||||||
|
typeof(object),
|
||||||
|
typeof(MagicSymbolControl),
|
||||||
|
new PropertyMetadata(default, PropertyChangedCallback)
|
||||||
|
);
|
||||||
|
|
||||||
|
private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (d is MagicSymbolControl magic)
|
||||||
|
{
|
||||||
|
magic.Content = MagicSymbolConverter.ConvertToFrameworkElement(e.NewValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol to show
|
||||||
|
/// </summary>
|
||||||
|
public object Symbol
|
||||||
|
{
|
||||||
|
get => GetValue(SymbolProperty);
|
||||||
|
set => SetValue(SymbolProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="MagicSymbolControl"/>
|
||||||
|
/// </summary>
|
||||||
|
public MagicSymbolControl()
|
||||||
|
{
|
||||||
|
Focusable = false;
|
||||||
|
}
|
||||||
|
}
|
146
src/Controls/PropertyPresenter/MagicSymbolConverter.cs
Normal file
146
src/Controls/PropertyPresenter/MagicSymbolConverter.cs
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using System.Text;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Magically converts a text to
|
||||||
|
/// </summary>
|
||||||
|
[ValueConversion(typeof(string), typeof(FrameworkElement))]
|
||||||
|
public class MagicSymbolConverter : IValueConverter
|
||||||
|
{
|
||||||
|
private const string NoParseKeyword = "noParse:";
|
||||||
|
private const string PathKeyword = "path:";
|
||||||
|
private const string DynResKeyword = "dynRes:";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return ConvertToFrameworkElement(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert string to Framework element.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static object ConvertToFrameworkElement(object value)
|
||||||
|
{
|
||||||
|
var data = value as string;
|
||||||
|
if (string.IsNullOrWhiteSpace(data))
|
||||||
|
return value; //maybe not a string. eventually something else.
|
||||||
|
|
||||||
|
if (data.StartsWith(NoParseKeyword, StringComparison.Ordinal))
|
||||||
|
return data[NoParseKeyword.Length..];
|
||||||
|
|
||||||
|
if (data.StartsWith(PathKeyword, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var path = data[PathKeyword.Length..];
|
||||||
|
var icon = ObjectImageConverter.GetIcon(Geometry.Parse(path), Brushes.Black);
|
||||||
|
return new Image
|
||||||
|
{
|
||||||
|
Source = icon,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Height = 16
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.StartsWith(DynResKeyword, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var resourceKey = data[DynResKeyword.Length..];
|
||||||
|
//get icon from resource dictionary
|
||||||
|
return new Image
|
||||||
|
{
|
||||||
|
Source = Application.Current.FindResource(resourceKey) as ImageSource,
|
||||||
|
HorizontalAlignment = HorizontalAlignment.Right,
|
||||||
|
VerticalAlignment = VerticalAlignment.Center,
|
||||||
|
Height = 16
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var textComponents = ParseText(data);
|
||||||
|
return CreateTextBlock(textComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextBlock CreateTextBlock(IEnumerable<TextComponent> textComponents)
|
||||||
|
{
|
||||||
|
//create text block
|
||||||
|
var block = new TextBlock();
|
||||||
|
foreach (var tc in textComponents)
|
||||||
|
{
|
||||||
|
var run = new Run(tc.Text) { FontFamily = new FontFamily("Palatino Linotype"), FontSize = 16 };
|
||||||
|
switch (tc.Style)
|
||||||
|
{
|
||||||
|
case BaselineAlignment.Subscript:
|
||||||
|
run.BaselineAlignment = BaselineAlignment.Subscript;
|
||||||
|
run.FontSize = 12;
|
||||||
|
break;
|
||||||
|
case BaselineAlignment.Superscript:
|
||||||
|
run.BaselineAlignment = BaselineAlignment.Superscript;
|
||||||
|
run.FontSize = 12;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
block.Inlines.Add(run);
|
||||||
|
}
|
||||||
|
|
||||||
|
block.HorizontalAlignment = HorizontalAlignment.Right;
|
||||||
|
block.VerticalAlignment = VerticalAlignment.Center;
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<TextComponent> ParseText(string data)
|
||||||
|
{
|
||||||
|
//parse text
|
||||||
|
var textComponents = new List<TextComponent>();
|
||||||
|
var alignment = BaselineAlignment.Baseline;
|
||||||
|
var snippet = new StringBuilder();
|
||||||
|
foreach (var c in data)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '~':
|
||||||
|
if (snippet.Length > 0)
|
||||||
|
{
|
||||||
|
var comp = new TextComponent(snippet.ToString(), alignment);
|
||||||
|
textComponents.Add(comp);
|
||||||
|
snippet.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment = alignment == BaselineAlignment.Subscript ? BaselineAlignment.Baseline : BaselineAlignment.Subscript;
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
if (snippet.Length > 0)
|
||||||
|
{
|
||||||
|
var comp = new TextComponent(snippet.ToString(), alignment);
|
||||||
|
textComponents.Add(comp);
|
||||||
|
snippet.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
alignment = alignment == BaselineAlignment.Superscript ? BaselineAlignment.Baseline : BaselineAlignment.Superscript;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snippet.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (snippet.Length > 0)
|
||||||
|
{
|
||||||
|
var comp = new TextComponent(snippet.ToString(), alignment);
|
||||||
|
textComponents.Add(comp);
|
||||||
|
snippet.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return textComponents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selects the right template on base of value-type.
|
||||||
|
/// </summary>
|
||||||
|
public class PropertyDataTemplateSelector : DataTemplateSelector
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default data template. (currently Textbox)
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate? DefaultDataTemplate { private get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data template for boolean. (currently Checkbox)
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate? BooleanDataTemplate { private get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Data template for enums. (currently Combobox)
|
||||||
|
/// </summary>
|
||||||
|
public DataTemplate? EnumComboBoxDataTemplate { private get; set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override DataTemplate? SelectTemplate(object item, DependencyObject container)
|
||||||
|
{
|
||||||
|
return item switch
|
||||||
|
{
|
||||||
|
bool _ => BooleanDataTemplate,
|
||||||
|
Enum _ => EnumComboBoxDataTemplate,
|
||||||
|
UIElement _ => null,
|
||||||
|
_ => DefaultDataTemplate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@
|
|||||||
</Validation.ErrorTemplate>
|
</Validation.ErrorTemplate>
|
||||||
<ContentControl.Resources>
|
<ContentControl.Resources>
|
||||||
<DataTemplate x:Key="DefaultDataTemplate">
|
<DataTemplate x:Key="DefaultDataTemplate">
|
||||||
|
<Grid>
|
||||||
<Grid>
|
<Grid>
|
||||||
<controls:TextBoxEx
|
<controls:TextBoxEx
|
||||||
x:Name="InputTextBox"
|
x:Name="InputTextBox"
|
||||||
@ -39,6 +40,13 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</TextBox.Style>
|
</TextBox.Style>
|
||||||
</controls:TextBoxEx>
|
</controls:TextBoxEx>
|
||||||
|
<controls:MagicSymbolControl
|
||||||
|
x:Name="PartSymbol"
|
||||||
|
Margin="5,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Symbol="{Binding Symbol, ElementName=LayoutRoot}" />
|
||||||
|
</Grid>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="6,0,0,0"
|
Margin="6,0,0,0"
|
||||||
Padding="2,2,2,2"
|
Padding="2,2,2,2"
|
||||||
@ -152,13 +160,6 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Focusable="False"
|
Focusable="False"
|
||||||
Text="{Binding Label, ElementName=LayoutRoot}" />
|
Text="{Binding Label, ElementName=LayoutRoot}" />
|
||||||
<controls:MagicSymbolControl
|
|
||||||
x:Name="PartSymbol"
|
|
||||||
Grid.Column="2"
|
|
||||||
Margin="5,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Symbol="{Binding Symbol, ElementName=LayoutRoot}" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<DockPanel Grid.Column="1">
|
<DockPanel Grid.Column="1">
|
||||||
<Button
|
<Button
|
200
src/Controls/PropertyPresenter/PropertyPresenter.xaml.cs
Normal file
200
src/Controls/PropertyPresenter/PropertyPresenter.xaml.cs
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ContentControl" />
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for PropertyPresenter.xaml
|
||||||
|
/// </summary>
|
||||||
|
[ContentProperty(nameof(Value))]
|
||||||
|
public sealed partial class PropertyPresenter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Button alignment property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty ButtonAlignmentProperty = DependencyProperty.Register(nameof(ButtonAlignment), typeof(Dock), typeof(PropertyPresenter), new PropertyMetadata(Dock.Right));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Content of the command property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CommandContentProperty = DependencyProperty.Register(nameof(CommandContent), typeof(object), typeof(PropertyPresenter), new PropertyMetadata("..."));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command Parameter property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register(
|
||||||
|
nameof(CommandParameter),
|
||||||
|
typeof(object),
|
||||||
|
typeof(PropertyPresenter),
|
||||||
|
new PropertyMetadata(default(object))
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(PropertyPresenter), new PropertyMetadata(default(ICommand)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// is checked property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
|
||||||
|
nameof(IsChecked),
|
||||||
|
typeof(bool?),
|
||||||
|
typeof(PropertyPresenter),
|
||||||
|
new FrameworkPropertyMetadata(default(bool?), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Is readonly property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register(nameof(IsReadOnly), typeof(bool), typeof(PropertyPresenter), new PropertyMetadata(default(bool)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Label property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty LabelProperty = DependencyProperty.Register(nameof(Label), typeof(string), typeof(PropertyPresenter), new PropertyMetadata(default(string)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// label width property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty LabelWidthProperty = DependencyProperty.Register(nameof(LabelWidth), typeof(double), typeof(PropertyPresenter), new PropertyMetadata(150.0));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol Property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty SymbolProperty = DependencyProperty.Register(nameof(Symbol), typeof(object), typeof(PropertyPresenter), new PropertyMetadata(default(object)));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value Property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
|
||||||
|
nameof(Value),
|
||||||
|
typeof(object),
|
||||||
|
typeof(PropertyPresenter),
|
||||||
|
new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Watermark Property
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
|
||||||
|
nameof(Watermark),
|
||||||
|
typeof(string),
|
||||||
|
typeof(PropertyPresenter),
|
||||||
|
new FrameworkPropertyMetadata(default(string))
|
||||||
|
);
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public PropertyPresenter()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Button alignment.
|
||||||
|
/// </summary>
|
||||||
|
public Dock ButtonAlignment
|
||||||
|
{
|
||||||
|
get => (Dock)GetValue(ButtonAlignmentProperty);
|
||||||
|
set => SetValue(ButtonAlignmentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command.
|
||||||
|
/// </summary>
|
||||||
|
public ICommand? Command
|
||||||
|
{
|
||||||
|
get => (ICommand)GetValue(CommandProperty);
|
||||||
|
set => SetValue(CommandProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command content.
|
||||||
|
/// </summary>
|
||||||
|
public object? CommandContent
|
||||||
|
{
|
||||||
|
get => GetValue(CommandContentProperty);
|
||||||
|
set => SetValue(CommandContentProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Command parameter.
|
||||||
|
/// </summary>
|
||||||
|
public object? CommandParameter
|
||||||
|
{
|
||||||
|
get => GetValue(CommandParameterProperty);
|
||||||
|
set => SetValue(CommandParameterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IsChecked.
|
||||||
|
/// </summary>
|
||||||
|
public bool? IsChecked
|
||||||
|
{
|
||||||
|
get => (bool?)GetValue(IsCheckedProperty);
|
||||||
|
set => SetValue(IsCheckedProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// IsReadOnly
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(IsReadOnlyProperty);
|
||||||
|
set => SetValue(IsReadOnlyProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Label.
|
||||||
|
/// </summary>
|
||||||
|
public string? Label
|
||||||
|
{
|
||||||
|
get => (string)GetValue(LabelProperty);
|
||||||
|
set => SetValue(LabelProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Label width.
|
||||||
|
/// </summary>
|
||||||
|
public double LabelWidth
|
||||||
|
{
|
||||||
|
get => (double)GetValue(LabelWidthProperty);
|
||||||
|
set => SetValue(LabelWidthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Symbol.
|
||||||
|
/// </summary>
|
||||||
|
public object? Symbol
|
||||||
|
{
|
||||||
|
get => GetValue(SymbolProperty);
|
||||||
|
set => SetValue(SymbolProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Value.
|
||||||
|
/// </summary>
|
||||||
|
public object? Value
|
||||||
|
{
|
||||||
|
get => GetValue(ValueProperty);
|
||||||
|
set => SetValue(ValueProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Watermark.
|
||||||
|
/// </summary>
|
||||||
|
public string Watermark
|
||||||
|
{
|
||||||
|
get => (string)GetValue(WatermarkProperty);
|
||||||
|
set => SetValue(WatermarkProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{base.ToString()} {Value}";
|
||||||
|
}
|
||||||
|
}
|
156
src/Controls/PropertyPresenter/TextBoxEx.cs
Normal file
156
src/Controls/PropertyPresenter/TextBoxEx.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a TextBox that can update the binding on enter.
|
||||||
|
/// </summary>
|
||||||
|
public class TextBoxEx : TextBox
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="MoveFocusOnEnter"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty MoveFocusOnEnterProperty = DependencyProperty.Register(nameof(MoveFocusOnEnter), typeof(bool), typeof(TextBoxEx), new UIPropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="UpdateBindingOnEnter"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty UpdateBindingOnEnterProperty = DependencyProperty.Register(nameof(UpdateBindingOnEnter), typeof(bool), typeof(TextBoxEx), new UIPropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="ScrollToHomeOnFocus"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty ScrollToHomeOnFocusProperty = DependencyProperty.Register(nameof(ScrollToHomeOnFocus), typeof(bool), typeof(TextBoxEx), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies the <see cref="SelectAllOnFocus"/> dependency property.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly DependencyProperty SelectAllOnFocusProperty = DependencyProperty.Register(nameof(SelectAllOnFocus), typeof(bool), typeof(TextBoxEx), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="T:Controls.TextBoxEx" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public TextBoxEx()
|
||||||
|
{
|
||||||
|
GotKeyboardFocus += HandleGotKeyboardFocus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to select all on focus.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if all should be selected; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool SelectAllOnFocus
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(SelectAllOnFocusProperty);
|
||||||
|
set => SetValue(SelectAllOnFocusProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether to scroll to home on focus.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// <c>true</c> if scroll is enabled; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
|
public bool ScrollToHomeOnFocus
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(ScrollToHomeOnFocusProperty);
|
||||||
|
set => SetValue(ScrollToHomeOnFocusProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether MoveFocusOnEnter.
|
||||||
|
/// </summary>
|
||||||
|
public bool MoveFocusOnEnter
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(MoveFocusOnEnterProperty);
|
||||||
|
set => SetValue(MoveFocusOnEnterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether UpdateBindingOnEnter.
|
||||||
|
/// </summary>
|
||||||
|
public bool UpdateBindingOnEnter
|
||||||
|
{
|
||||||
|
get => (bool)GetValue(UpdateBindingOnEnterProperty);
|
||||||
|
set => SetValue(UpdateBindingOnEnterProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPreviewKeyDown(e);
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.Enter:
|
||||||
|
if (!AcceptsReturn)
|
||||||
|
{
|
||||||
|
if (UpdateBindingOnEnter)
|
||||||
|
{
|
||||||
|
// get the binding to the Text property
|
||||||
|
var bindingExpression = GetBindingExpression(TextProperty);
|
||||||
|
// update the source (do not update the target)
|
||||||
|
bindingExpression?.UpdateSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MoveFocusOnEnter)
|
||||||
|
{
|
||||||
|
// Move focus to next element
|
||||||
|
// http://madprops.org/blog/enter-to-tab-in-wpf/
|
||||||
|
if (e.OriginalSource is UIElement uiElement)
|
||||||
|
{
|
||||||
|
var shift = (Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift;
|
||||||
|
uiElement.MoveFocus(new TraversalRequest(shift ? FocusNavigationDirection.Previous : FocusNavigationDirection.Next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case Key.Escape:
|
||||||
|
Undo();
|
||||||
|
SelectAll();
|
||||||
|
e.Handled = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPreviewMouseLeftButtonDown(e);
|
||||||
|
|
||||||
|
if (!IsKeyboardFocusWithin)
|
||||||
|
{
|
||||||
|
SelectAll();
|
||||||
|
Focus();
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the got keyboard focus event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sender">The sender.</param>
|
||||||
|
/// <param name="e">The <see cref="KeyboardFocusChangedEventArgs" /> instance containing the event data.</param>
|
||||||
|
private void HandleGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (SelectAllOnFocus)
|
||||||
|
{
|
||||||
|
SelectAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ScrollToHomeOnFocus)
|
||||||
|
{
|
||||||
|
ScrollToHome();
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
30
src/Controls/PropertyPresenter/TextComponent.cs
Normal file
30
src/Controls/PropertyPresenter/TextComponent.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A component of the symbol
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct TextComponent
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Constructor
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text"></param>
|
||||||
|
/// <param name="style"></param>
|
||||||
|
public TextComponent(string text, BaselineAlignment style = BaselineAlignment.Baseline)
|
||||||
|
{
|
||||||
|
Text = text;
|
||||||
|
Style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Text of the symbol component
|
||||||
|
/// </summary>
|
||||||
|
public readonly string Text;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Style of the symbol component
|
||||||
|
/// </summary>
|
||||||
|
public readonly BaselineAlignment Style;
|
||||||
|
}
|
97
src/Controls/PropertyPresenter/ValueConverter.cs
Normal file
97
src/Controls/PropertyPresenter/ValueConverter.cs
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Net;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using Brush = System.Windows.Media.Brush;
|
||||||
|
using Brushes = System.Windows.Media.Brushes;
|
||||||
|
using FontFamily = System.Windows.Media.FontFamily;
|
||||||
|
using Point = System.Windows.Point;
|
||||||
|
|
||||||
|
namespace Controls;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes an Bitmap from every Imageformat.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ObjectImageConverter : IValueConverter
|
||||||
|
{
|
||||||
|
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||||
|
{
|
||||||
|
const string dynResPrefix = "dynRes:";
|
||||||
|
if (value is Bitmap bitmap)
|
||||||
|
{
|
||||||
|
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromWidthAndHeight(16, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value is not string strValue)
|
||||||
|
return Binding.DoNothing;
|
||||||
|
if (strValue.StartsWith(dynResPrefix, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var resource = Application.Current.TryFindResource(strValue.Replace(dynResPrefix, string.Empty, StringComparison.InvariantCulture));
|
||||||
|
return resource is ImageSource source ? source : Binding.DoNothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strValue.StartsWith("text:", StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
var parts = strValue.Split(':');
|
||||||
|
return parts.Length == 3 ? DrawText(WebUtility.HtmlDecode(parts[2]), parts[1], Brushes.Black) : Binding.DoNothing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetIcon(Geometry.Parse(strValue), null);
|
||||||
|
}
|
||||||
|
|
||||||
|
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get icon a ImageSource from geometry.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="geometry">geometry</param>
|
||||||
|
/// <param name="brush">color of the icon</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ImageSource GetIcon(Geometry geometry, Brush? brush)
|
||||||
|
{
|
||||||
|
if (brush == null)
|
||||||
|
brush = Brushes.Black;
|
||||||
|
var drawing = new GeometryDrawing(brush, null, geometry);
|
||||||
|
return new DrawingImage(drawing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Draw text as ImageSource from string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">the text</param>
|
||||||
|
/// <param name="strFontFamily">font of the string</param>
|
||||||
|
/// <param name="brush">color of the string</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ImageSource DrawText(string text, string strFontFamily, Brush brush)
|
||||||
|
{
|
||||||
|
var fontFamily = new FontFamily(strFontFamily);
|
||||||
|
var formattedText = new FormattedText(
|
||||||
|
text,
|
||||||
|
CultureInfo.GetCultureInfo("en-us"),
|
||||||
|
FlowDirection.LeftToRight,
|
||||||
|
new Typeface(fontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal),
|
||||||
|
64,
|
||||||
|
brush,
|
||||||
|
1.5
|
||||||
|
);
|
||||||
|
|
||||||
|
var geometry = formattedText.BuildGeometry(new Point(0, 0));
|
||||||
|
return GetIcon(geometry, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invert boolean converter
|
||||||
|
/// </summary>
|
||||||
|
[ValueConversion(typeof(bool), typeof(bool))]
|
||||||
|
public class InverseBooleanConverter : IValueConverter
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) => value is bool b ? !b : throw new InvalidOperationException("The target must be a boolean");
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => Binding.DoNothing;
|
||||||
|
}
|
Reference in New Issue
Block a user