diff --git a/.editorconfig b/.editorconfig index fbc40f7..12405e6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,137 +1,378 @@ -; This file is for unifying the coding style for different editors and IDEs. -; More information at http://editorconfig.org - -# This file is the top-most EditorConfig file root = true -########################################## -# Common Settings -########################################## - - +# All files [*] indent_style = space -end_of_line = crlf -trim_trailing_whitespace = true -insert_final_newline = false -charset = utf-8 -[*.{md,markdown,json,txt,log,yml,yaml,jsonc}] +# Xml files +[*.{xml,md,markdown,json,csproj,targets,targets,props,config,yml}] indent_size = 2 -indent_style = space -[*.{md,markdown}] -insert_final_newline = true -trim_trailing_whitespace = true +# C# files +[*.cs] -########################################## -# File Extension Settings -########################################## +#### Core EditorConfig Options #### -[*.{xaml,xml,slnf,sln,csproj,proj,projitems,shproj,props,targets,appxmanifest,html,cshtml,webmanifest,manifest,css,vsconfig,sh}] -indent_size = 2 -indent_style = space - -[*.plist] +# Indentation and spacing indent_size = 4 -indent_style = tab -end_of_line = lf +tab_width = 4 -[web.config] -indent_size = 4 -end_of_line = lf +# New line preferences +insert_final_newline = false + +#### .NET Coding Conventions #### +[*.{cs,vb}] + +# Organize usings +dotnet_separate_import_directive_groups = true +dotnet_sort_system_directives_first = true +file_header_template = unset + +# this. and Me. preferences +dotnet_style_qualification_for_event = false:silent +dotnet_style_qualification_for_field = false:silent +dotnet_style_qualification_for_method = false:silent +dotnet_style_qualification_for_property = false:silent + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:silent +dotnet_style_predefined_type_for_member_access = true:silent + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent +dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent + +# Expression-level preferences +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_namespace_match_folder = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_object_initializer = true:suggestion +dotnet_style_operator_placement_when_wrapping = beginning_of_line +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_collection_expression = when_types_loosely_match:suggestion +dotnet_style_prefer_compound_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion +dotnet_style_prefer_simplified_interpolation = true:suggestion +# Field preferences +dotnet_style_readonly_field = true:warning + +# Parameter preferences +dotnet_code_quality_unused_parameters = all:suggestion + +# Suppression preferences +dotnet_remove_unnecessary_suppression_exclusions = none + +#### C# Coding Conventions #### [*.cs] -# EOL should be normalized by Git. See https://github.com/dotnet/format/issues/1099 -end_of_line = unset -# See https://github.com/dotnet/roslyn/issues/20356#issuecomment-310143926 -trim_trailing_whitespace = false +# var preferences +csharp_style_var_elsewhere = false:silent +csharp_style_var_for_built_in_types = false:silent +csharp_style_var_when_type_is_apparent = false:silent -tab_width = 4 -indent_size = 4 +# Expression-bodied members +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:suggestion +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 -# Sort using and Import directives with System.* appearing first -dotnet_sort_system_directives_first = true +# Pattern matching preferences +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_prefer_extended_property_pattern = true:suggestion +csharp_style_prefer_not_pattern = true:suggestion +csharp_style_prefer_pattern_matching = true:silent +csharp_style_prefer_switch_expression = true:suggestion + +# Null-checking preferences +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_prefer_static_anonymous_function = true:suggestion +csharp_prefer_static_local_function = true:warning +csharp_preferred_modifier_order = public,private,protected,internal,file,const,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_style_prefer_readonly_struct_member = true:suggestion + +# Code-block preferences +csharp_prefer_braces = true:silent +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = file_scoped:suggestion +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_top_level_statements = true:silent + +# Expression-level preferences +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 + +# 'using' directive preferences +csharp_using_directive_placement = outside_namespace:silent + +#### C# Formatting Rules #### + +# New line preferences +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 + +# Indentation preferences +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 + +# Space preferences +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 -# Avoid "this." and "Me." if not necessary -dotnet_style_qualification_for_field = false:suggestion -dotnet_style_qualification_for_property = false:suggestion -dotnet_style_qualification_for_method = false:suggestion -dotnet_style_qualification_for_event = false:suggestion +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true #### Naming styles #### +[*.{cs,vb}] # Naming rules -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_and_namespaces_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces +dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase -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.interfaces_should_be_ipascalcase.severity = suggestion +dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces +dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase -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 +dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = suggestion +dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters +dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase + +dotnet_naming_rule.methods_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods +dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.properties_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties +dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.events_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.events_should_be_pascalcase.symbols = events +dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_variables_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables +dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase + +dotnet_naming_rule.local_constants_should_be_camelcase.severity = suggestion +dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants +dotnet_naming_rule.local_constants_should_be_camelcase.style = camelcase + +dotnet_naming_rule.parameters_should_be_camelcase.severity = suggestion +dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters +dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase + +dotnet_naming_rule.public_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields +dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_fields_should_be__camelcase.severity = suggestion +dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields +dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase + +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = suggestion +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields +dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = s_camelcase + +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields +dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields +dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields +dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields +dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.enums_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums +dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.local_functions_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase + +dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase # Symbol specifications -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.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interfaces.required_modifiers = + +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.enums.required_modifiers = + +dotnet_naming_symbols.events.applicable_kinds = event +dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.events.required_modifiers = + +dotnet_naming_symbols.methods.applicable_kinds = method +dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.methods.required_modifiers = + +dotnet_naming_symbols.properties.applicable_kinds = property +dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.properties.required_modifiers = + +dotnet_naming_symbols.public_fields.applicable_kinds = field +dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_fields.required_modifiers = + +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_fields.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.private_static_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_fields.required_modifiers = static + +dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum +dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types_and_namespaces.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 = +dotnet_naming_symbols.non_field_members.required_modifiers = + +dotnet_naming_symbols.type_parameters.applicable_kinds = namespace +dotnet_naming_symbols.type_parameters.applicable_accessibilities = * +dotnet_naming_symbols.type_parameters.required_modifiers = + +dotnet_naming_symbols.private_constant_fields.applicable_kinds = field +dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_constant_fields.required_modifiers = const + +dotnet_naming_symbols.local_variables.applicable_kinds = local +dotnet_naming_symbols.local_variables.applicable_accessibilities = local +dotnet_naming_symbols.local_variables.required_modifiers = + +dotnet_naming_symbols.local_constants.applicable_kinds = local +dotnet_naming_symbols.local_constants.applicable_accessibilities = local +dotnet_naming_symbols.local_constants.required_modifiers = const + +dotnet_naming_symbols.parameters.applicable_kinds = parameter +dotnet_naming_symbols.parameters.applicable_accessibilities = * +dotnet_naming_symbols.parameters.required_modifiers = + +dotnet_naming_symbols.public_constant_fields.applicable_kinds = field +dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_constant_fields.required_modifiers = const + +dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal +dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected +dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function +dotnet_naming_symbols.local_functions.applicable_accessibilities = * +dotnet_naming_symbols.local_functions.required_modifiers = # Naming styles -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 +dotnet_naming_style.pascalcase.required_prefix = +dotnet_naming_style.pascalcase.required_suffix = +dotnet_naming_style.pascalcase.word_separator = +dotnet_naming_style.pascalcase.capitalization = pascal_case -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.ipascalcase.required_prefix = I +dotnet_naming_style.ipascalcase.required_suffix = +dotnet_naming_style.ipascalcase.word_separator = +dotnet_naming_style.ipascalcase.capitalization = pascal_case -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_style_operator_placement_when_wrapping = beginning_of_line -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_naming_style.tpascalcase.required_prefix = T +dotnet_naming_style.tpascalcase.required_suffix = +dotnet_naming_style.tpascalcase.word_separator = +dotnet_naming_style.tpascalcase.capitalization = pascal_case + +dotnet_naming_style._camelcase.required_prefix = _ +dotnet_naming_style._camelcase.required_suffix = +dotnet_naming_style._camelcase.word_separator = +dotnet_naming_style._camelcase.capitalization = camel_case + +dotnet_naming_style.camelcase.required_prefix = +dotnet_naming_style.camelcase.required_suffix = +dotnet_naming_style.camelcase.word_separator = +dotnet_naming_style.camelcase.capitalization = camel_case + +dotnet_naming_style.s_camelcase.required_prefix = s_ +dotnet_naming_style.s_camelcase.required_suffix = +dotnet_naming_style.s_camelcase.word_separator = +dotnet_naming_style.s_camelcase.capitalization = camel_case -csharp_indent_labels = one_less_than_current -csharp_using_directive_placement = outside_namespace:silent -csharp_prefer_simple_using_statement = true:suggestion -csharp_prefer_braces = true:silent -csharp_style_namespace_declarations = file_scoped:warning -csharp_style_prefer_method_group_conversion = true:silent -csharp_style_prefer_top_level_statements = true:silent -csharp_style_prefer_primary_constructors = true:suggestion -csharp_style_expression_bodied_methods = false:silent -csharp_style_expression_bodied_constructors = false:silent -csharp_style_expression_bodied_operators = false:silent -csharp_style_expression_bodied_properties = true:silent -csharp_style_expression_bodied_indexers = true:silent -csharp_style_expression_bodied_accessors = true:silent -csharp_style_expression_bodied_lambdas = true:silent -csharp_style_expression_bodied_local_functions = false:silent diff --git a/.markdownlint.jsonc b/.markdownlint.jsonc new file mode 100644 index 0000000..16b902f --- /dev/null +++ b/.markdownlint.jsonc @@ -0,0 +1,16 @@ +{ + "$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint/v0.38.0/schema/markdownlint-config-schema.json", + "default": true, + "line-length": false, + "commands-show-output": false, + "no-bare-urls": false, + "no-inline-html": false, + "no-duplicate-heading": false, + "no-emphasis-as-heading": false, + // Headers must start at the beginning of the line - false positive in some cases where it makes sense. + "MD023": false, + // First line in a file should be a top-level heading - false positive for include files. + "MD041": false, + // Link fragments should be valid - false positive for docfx tabs + "MD051": false +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c74be28 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "*.tmpl*": "mustache" + }, +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..e7d7a0d --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +# Contributing to DevTKSS.Uno.SampleApps + +Thank you for your interest in contributing to this project! We welcome contributions from the community. + +## Code of Conduct + +Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md) to foster a welcoming and respectful community. + +## How to Contribute + +1. **Fork the repository** and create your branch from `main`. +2. **Write clear, concise commit messages**. +3. **Test your changes** to ensure they work as expected. +4. **Submit a pull request** with a description of your changes. + +## License + +By contributing, you agree that your contributions will be licensed under the [Apache License 2.0](LICENSE.md). + +## Reporting Issues + +If you find a bug or have a feature request, please [open an issue](../../issues). + +## Development Guidelines + +- Follow Uno Platform best practices. +- Ensure code is clean, well-documented, and tested. +- Adhere to existing coding style and conventions. + +Thank you for helping improve DevTKSS.Uno.SampleApps! + +## Current Documentation Problems + +As workaround to the redirect_url not working, the `[!INCLUDE` Markup is used to include the needed content. + +> [!IMPORTANT] +> As DocFx currently also loads explicitly excluded files from the `**/obj/**` folder, the metadata stage does not filter these files out, which can lead to unexpected results in the generated documentation. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ed680b5 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,202 @@ +# Apache 2.0 License + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for describing the origin of the Work and + reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting the License. You accept and agree to be bound by the + terms of this License by copying, modifying, or distributing the + Work (or any work based on the Work). + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +## DevTKSS Uno Sample Apps + +Copyright (c) Sonja Schweitzer + +All rights reserved. diff --git a/README.md b/README.md index c4a4e50..6cadfa7 100644 --- a/README.md +++ b/README.md @@ -1,110 +1,129 @@ # DevTKSS Uno Samples -Welcome to this Samples Repository! ❤️ +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/LICENSE.md) +[![Documentation](https://img.shields.io/badge/docs-online-green.svg)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/) +[![Uno Platform](https://img.shields.io/badge/Uno%20Platform-5.5+-purple.svg)](https://platform.uno/) -The samples in this Repository are meant to help other Developers, independent to their pre-knowledge, get an Idea of how to use the shown things. +## Welcome to this Samples and Tutorials Library! ❤️ + +This is a collection of Sample Apps and Tutorials for the [Uno Platform](https://platform.uno/), created to fill the gap of missing **German-localized** learning content. Most tutorials are available in both **German** (primary) and **English**. + +**Quick Links:** [Get Started](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/HowTo-Setup-DevelopmentEnvironment-en.html) | [Documentation](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/) | [Video Tutorials (German)](https://youtube.com/playlist?list=PLEL6kb4Bivm_g81iKBl-f0eYPNr5h2dFX) | [Discussions](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/discussions) + +--- + +## About This Repository + +This repository aims to help developers, regardless of their prior knowledge, learn: + +- How to get started with the [Uno Platform](https://platform.uno/) +- How to use featured controls and patterns in real applications +- Best practices for MVUX, Navigation, and other Uno.Extensions + +### Prerequisites + +Before diving into the samples, make sure you have: + +- **.NET 9.0 SDK** or later +- **Visual Studio 2022** (17.8+) with Uno Platform extension, **Rider**, or **VS Code** +- **Uno.Check** tool installed and verified (run `uno-check`) > [!TIP] -> Check out the [Documentation](./doc/articles/introduction.md), for more a more detailed List and future coming Guides and Explanations. +> For detailed setup instructions, see our [Development Environment Setup Guide](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/HowTo-Setup-DevelopmentEnvironment-en.html). + +--- + +## Sample Applications + +### Mvux Gallery + +![Mvux Gallery Showcase Thumbnail](./doc/articles/.attachments/DevTKSS%20Uno%20Mvux%20Samples%20Gallery%20App-Thumbnail.png) + +**Want to see a quick showcase of what you can explore?** + +![Mvux Gallery ShowCase](./doc/articles/.attachments/MvuxGallery-ShowCase.gif) + +The [Mvux Gallery](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/tree/master/src/DevTKSS.Uno.Samples.MvuxGallery/) demonstrates modern Uno Platform development patterns with a comprehensive example application. + +**[View Detailed Mvux Gallery Overview](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/MvuxGallery-Overview-en.html)** + +#### Featured Controls -## Table of Contents +- **FeedView** combined with GridView and ListView +- **DataTemplate** centralized resource definitions +- **Card**, **Grid**, **NavigationView** +- **ItemOverlayTemplate** (replicated from WinUI 3 Gallery) +- **TabBar & TabBarItem** -- [DevTKSS Uno Samples](#devtkss-uno-samples) - - [Table of Contents](#table-of-contents) - - [Mvux Gallery](#mvux-gallery) - - [Controls to be explored in this App](#controls-to-be-explored-in-this-app) - - [Uno.Extensions to be explored here](#unoextensions-to-be-explored-here) - - [Known Issues](#known-issues) - - [Tutorials](#tutorials) - - [German Language](#german-language) - - [Help Welcome!](#help-welcome) - - [See also](#see-also) +#### Demonstrated Uno.Extensions -## Mvux Gallery +- **[MVUX](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Mvux/Overview.html)** - Model-View-Update-eXtended pattern +- **Navigation** + - [Navigation via XAML](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/Navigation/HowTo-Defining-UI-NavigationView-en.html) + - [React to Route Changes with IRouteNotifier](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/Navigation/HowTo-ChangeRoutes-en.html) +- **Hosting** - App Host Builder pattern +- **Dependency Injection** - Constructor injection +- **Serialization** - JSON data handling +- **Configuration** - Data loaded from `appsettings.json` +- **Storage** - Local data persistence +- **Localization** - Multi-language support -![Mvux Gallery Showcase Thumbnail](./doc/articles/images/DevTKSS%20Uno%20Mvux%20Samples%20Gallery%20App-Thumbnail.png) +#### Known Issues -**Wanna see a quick showcase, what to explore there?** +- ThemeResource styles are not listening to theme changes ([Issue #13](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/issues/13)) +- DocFX fails to resolve source code links for included code snippets -![Mvux Gallery ShowCase](./doc/articles/images/MvuxGallery-ShowCase.gif) +--- -Following list provides you a quick Overview, what you can find in the [Mvux Gallery](./src/DevTKSS.Uno.Samples/DevTKSS.Uno.Samples.MvuxGallery) App. -The Overview about it and its Tutorials you can find [here](./doc/articles/MvuxGallery/Overview.md) +### Xaml Navigation App -### Controls to be explored in this App +![Image of final Xaml Navigation App](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/doc/articles/.attachments/DevTKSS.Uno.XamlNavigationApp.png) -- FeedView combined with: - - GridView - - ListView -- DataTemplate centralized Resource definition -- Card -- Grid -- NavigationView -- `ItemOverlayTemplate` DataTemplate layout replicated from WinUI 3 Gallery -- TabBar & TabBarItem +A complete tutorial application demonstrating navigation patterns with MVUX and XAML. -### Uno.Extensions to be explored here +#### Tutorial Content -- Mvux - - ListFeed - - State -- Navigation - - via Xaml -- Hosting -- DependencyInjection -- Serialization - - JsonSerializerContext of each DataModel - - Using multiple `JsonSerializable(typeof...)` Attributes to extend the `CodeSampleOptionsContext.Default.<...>` Items -- Configuration - - Data for Serialization load from separate `appsettings.sampledata.json` -- Storage - - Directly in the Model Definition - - Via Service - - Via StorageExtension - - Referenced currently in private preview package - - Via Uno.Extensions.Storage.IStorage Interface extension - - added as PR to Uno.Extensions [#2734](https://github.com/unoplatform/uno.extensions/pull/2734) -- Localization - - **IStringLocalizer** - - Resources Dictionaries - - Binding current value in `IState` and to corresponding View - - Requesting localized Items via FeedView - - **ILocalizationService** - - Requesting current culture +- [Uno.Extensions.Reactive (MVUX)](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Mvux/Overview.html) +- [Uno.Extensions.Navigation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/NavigationOverview.html) +- [XAML Markup Navigation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-NavigateInXAML.html) -### Known Issues +**Available Resources:** -- [ ] Fixing ThemeResource Styled that are not seeming to listen to Theme changes -- [ ] Getting `IOptions` with JsonTypeInfo Typed to Dictionary or Tuples does not work as expected and only returns null values. (see [#6](./issues/6)) -- [ ] Missing Information about how to use `NamedOptions` at the point they should get returned by the IConfiguration to Configure the Service because Uno did remove the Microsoft own `.Configure<...>` which would be known, but is missing a documentation about those Changes applied. So in amiss of that, we need to create a derived Record for each of them to get the correct JsonSerializable Type and makes us need to define the CodeSampleService Generic. Following this up on [#9](./issues/9) +- **[Tutorial Documentation](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/Navigation/Extensions-Navigation-en.html)** - Step-by-step guide (🇩🇪 German | 🇬🇧 English) +- **[Video Tutorial Series](https://youtube.com/playlist?list=PLEL6kb4Bivm_g81iKBl-f0eYPNr5h2dFX)** - Complete walkthrough (🇩🇪 German with English subtitles) +- **[Source Code](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/tree/master/src/DevTKSS.Uno.XamlNavigationApp-1/)** - Browse the implementation -## Tutorials +--- -### German Language +## Documentation & Tutorials -- **Xaml Navigation with NavigationView** - - Video Tutorial Playlist I recommend to check out frequently: +You can access all tutorials and guides in both English and German. Use the table below to quickly jump to the documentation in your preferred language: - https://www.youtube.com/playlist?list=PLEL6kb4Bivm_g81iKBl-f0eYPNr5h2dFX +| Section | English | German | +|--------------------------|------------------------------------------------------------------------|-------------------------------------------------------------------------| +| Getting Started | [Guide (EN)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/HowTo-Setup-DevelopmentEnvironment-en.html) | [Anleitung (DE)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/de/HowTo-Setup-DevelopmentEnvironment-de.html) | +| Mvux Gallery Overview | [Overview (EN)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/MvuxGallery-Overview-en.html) | [Übersicht (DE)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/de/MvuxGallery-Overview-de.html) | +| Navigation Tutorials | [Navigation (EN)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/en/Navigation/Extensions-Navigation-en.html) | [Navigation (DE)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/articles/de/Navigation/Extensions-Navigation-de.html) | +| All Docs Index | [Docs Home (EN)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/) | [Docs Home (DE)](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/index.html?lang=de) | - - [Documentation in German Language](./doc/articles/MvuxGallery/How-To-XamlNavigation.md) +Most content is available in both German (original) and English (translated). - Here is a sneak peak of the end Result of the Xaml Navigation Tutorial you can explore 😍 +--- - ![Image of final XamlNavigationApp](./doc/articles/images/DevTKSS.Uno.XamlNavigationApp.png) +## Feedback, Issues and Contributing - Source Code already available in the [DevTKSS.Uno.XamlNavigationApp](./src/DevTKSS.Uno.XamlNavigationApp-1/) Project. - -## Help Welcome! +We welcome your feedback and contributions! -If you want to help out, please feel free to open an [issue](./issues) or PR. +- **Questions?** Start a [Discussion](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/discussions) +- **Found a bug?** Open an [Issue](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/issues) +- **Want to contribute?** Check out our [Contributing Guidelines](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/CONTRIBUTING.md) +- **Have an idea?** Share it in [Discussions](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/discussions/new) -Every helping hand is welcome and I will try to review and merge it as soon as possible. +--- -## See also +### Helpful Resources -- [Uno Platform](https://platform.uno/) - - [Documentation Intro](https://platform.uno/docs/articles/intro.html) - - [Uno Navigation Extensions](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/NavigationOverview.html) - - [Mvux Documentation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Mvux/Overview.html) - - [FeedView Control](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Mvux/FeedView.html) +- [Uno Platform Homepage](https://platform.uno/) +- [Uno Platform Documentation](https://platform.uno/docs/articles/intro.html) +- [Uno Platform Discord Community](https://discord.gg/eBHZSKG) +- [Uno Platform on GitHub](https://github.com/unoplatform/uno) diff --git a/cSpell.json b/cSpell.json index 6ef7ef4..ddb30cf 100644 --- a/cSpell.json +++ b/cSpell.json @@ -3,13 +3,26 @@ "version": "0.2", "language": "en,de", "words": [ + "alertblocks", "appsettings", + "definitionlists", "DevTKSS", + "dotnet", + "docfx", + "gridtables", "Listboard", + "markdig", + "medialinks", "Mvux", + "Mvvm", + "MVVM", "Resizetizer", "resw", - "sampledata" + "sampledata", + "singulinkfx", + "TKSS", + "unoapp", + "upgraden" ], "dictionaries": [ "csharp", @@ -21,6 +34,8 @@ "node_modules/**", "dist/**", "src/*", - "**.gitignore" + "**.gitignore", + "doc/templates/**", + "LICENSE.md" ] -} \ No newline at end of file +} diff --git a/doc/Build-Docs.ps1 b/doc/Build-Docs.ps1 new file mode 100644 index 0000000..6581054 --- /dev/null +++ b/doc/Build-Docs.ps1 @@ -0,0 +1,37 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Builds DocFX documentation with clean API regeneration. + +.DESCRIPTION + 1. Cleans obsolete API documentation files + 2. Regenerates metadata from current source code + 3. Builds the documentation site + +.EXAMPLE + .\Build-Docs.ps1 +#> + +[CmdletBinding()] +param( + [Parameter()] + [ValidateSet('Quiet', 'Info', 'Warning', 'Error', 'Verbose')] + [string]$LogLevel = 'Warning' +) + +Set-Location $PSScriptRoot + +# Step 1: Clean obsolete API docs +Write-Host "`n==> Cleaning obsolete API documentation..." -ForegroundColor Cyan +& .\Clean-ApiDocs.ps1 + +# Step 2: Run DocFX (metadata + build + pdf in one command) +Write-Host "`n==> Running DocFX (metadata, build, pdf)..." -ForegroundColor Cyan +docfx docfx.json --logLevel $LogLevel +if ($LASTEXITCODE -ne 0) { + Write-Error "DocFX build failed" + exit $LASTEXITCODE +} + +Write-Host "`n✓ Documentation built successfully!" -ForegroundColor Green +Write-Host "Output: $PSScriptRoot\_site" -ForegroundColor Gray diff --git a/doc/Clean-ApiDocs.ps1 b/doc/Clean-ApiDocs.ps1 new file mode 100644 index 0000000..1373e7a --- /dev/null +++ b/doc/Clean-ApiDocs.ps1 @@ -0,0 +1,40 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Cleans obsolete API documentation files before regenerating with DocFX. + +.DESCRIPTION + Removes all generated YAML files from the api/ directory and the _site/ + output folder to ensure only current types are documented and built. + Preserves any manually-created markdown files like api/index.md. + +.EXAMPLE + .\Clean-ApiDocs.ps1 +#> + +[CmdletBinding()] +param() + +$apiPath = Join-Path $PSScriptRoot "api" +$sitePath = Join-Path $PSScriptRoot "_site" + +# Clean API folder +if (Test-Path $apiPath) { + Write-Host "Cleaning API documentation folder: $apiPath" -ForegroundColor Cyan + + # Remove all .yml files (generated API docs) + Get-ChildItem -Path $apiPath -Filter "*.yml" -File | Remove-Item -Force -Verbose + + Write-Host "✓ Cleaned obsolete API documentation files" -ForegroundColor Green +} else { + Write-Host "API folder does not exist yet: $apiPath" -ForegroundColor Yellow +} + +# Clean _site folder +if (Test-Path $sitePath) { + Write-Host "Cleaning output site folder: $sitePath" -ForegroundColor Cyan + Remove-Item -Path $sitePath -Recurse -Force -Verbose + Write-Host "✓ Cleaned output site folder" -ForegroundColor Green +} else { + Write-Host "Output site folder does not exist yet: $sitePath" -ForegroundColor Yellow +} diff --git a/doc/Resources/filterConfig.yml b/doc/Resources/filterConfig.yml new file mode 100644 index 0000000..75a0bdb --- /dev/null +++ b/doc/Resources/filterConfig.yml @@ -0,0 +1,24 @@ +# YAML-Language Server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/filterconfig.schema.json +apiRules: + - exclude: + uidRegex: ^Uno\.Resizetizer$ + type: Namespace + - exclude: + uidRegex: ReactiveViewModelMappings$ + type: Type + - exclude: + uidRegex: GlobalStaticResources$ + type: Type + # Exclude all auto-generated ViewModel types (end with ViewModel suffix) + - exclude: + uidRegex: ViewModel$ + type: Type + # Exclude all types with BindableAttribute (catches generated Bindable*ViewModel types) + - exclude: + hasAttribute: + uid: Uno.Extensions.Reactive.BindableAttribute + type: Type + # Exclude __Reactive methods + - exclude: + uidRegex: __Reactive(\(.*\))?$ + type: Member \ No newline at end of file diff --git a/doc/api/.gitignore b/doc/api/.gitignore index ec8a492..387d3fa 100644 --- a/doc/api/.gitignore +++ b/doc/api/.gitignore @@ -1,2 +1,2 @@ *.yml -manifest* +.manifest diff --git a/doc/api/index.md b/doc/api/index.md index 513aa68..f3ec504 100644 --- a/doc/api/index.md +++ b/doc/api/index.md @@ -1,3 +1,3 @@ -# Welcome to the API Reference for the SampleApps +# DevTKSS.Uno.Samples.MvuxGallery API Documentation -Use the Side TOC to navigate through the API documentation. +Use the table of contents to browse API documentation for the `DevTKSS.Uno.Samples` library. diff --git a/doc/articles/.attachments/Adding-mvux-model-constructor-DI.png b/doc/articles/.attachments/Adding-mvux-model-constructor-DI.png new file mode 100644 index 0000000..f2dae37 Binary files /dev/null and b/doc/articles/.attachments/Adding-mvux-model-constructor-DI.png differ diff --git a/doc/articles/.attachments/Adding-mvvm-viewmodel-constructor-DI.png b/doc/articles/.attachments/Adding-mvvm-viewmodel-constructor-DI.png new file mode 100644 index 0000000..db4cc53 Binary files /dev/null and b/doc/articles/.attachments/Adding-mvvm-viewmodel-constructor-DI.png differ diff --git a/doc/articles/.attachments/Adding-new-Item-class.png b/doc/articles/.attachments/Adding-new-Item-class.png new file mode 100644 index 0000000..a17e152 Binary files /dev/null and b/doc/articles/.attachments/Adding-new-Item-class.png differ diff --git a/doc/articles/.attachments/Adding-new-Item-page-de.png b/doc/articles/.attachments/Adding-new-Item-page-de.png new file mode 100644 index 0000000..6998e36 Binary files /dev/null and b/doc/articles/.attachments/Adding-new-Item-page-de.png differ diff --git a/doc/articles/.attachments/Adding-new-Item-to-sln-de.png b/doc/articles/.attachments/Adding-new-Item-to-sln-de.png new file mode 100644 index 0000000..98000d4 Binary files /dev/null and b/doc/articles/.attachments/Adding-new-Item-to-sln-de.png differ diff --git a/doc/articles/.attachments/Adding-new-Item-to-sln-en.png b/doc/articles/.attachments/Adding-new-Item-to-sln-en.png new file mode 100644 index 0000000..e3dca7b Binary files /dev/null and b/doc/articles/.attachments/Adding-new-Item-to-sln-en.png differ diff --git a/doc/articles/.attachments/Adding-service-constructor-DI.png b/doc/articles/.attachments/Adding-service-constructor-DI.png new file mode 100644 index 0000000..ff5989e Binary files /dev/null and b/doc/articles/.attachments/Adding-service-constructor-DI.png differ diff --git a/doc/articles/images/DevTKSS Uno Mvux Samples Gallery App-Thumbnail.png b/doc/articles/.attachments/DevTKSS Uno Mvux Samples Gallery App-Thumbnail.png similarity index 100% rename from doc/articles/images/DevTKSS Uno Mvux Samples Gallery App-Thumbnail.png rename to doc/articles/.attachments/DevTKSS Uno Mvux Samples Gallery App-Thumbnail.png diff --git a/doc/articles/images/DevTKSS.Uno.XamlNavigationApp.png b/doc/articles/.attachments/DevTKSS.Uno.XamlNavigationApp.png similarity index 100% rename from doc/articles/images/DevTKSS.Uno.XamlNavigationApp.png rename to doc/articles/.attachments/DevTKSS.Uno.XamlNavigationApp.png diff --git a/doc/articles/.attachments/Finding-Uno-VS2022-Extension-Menu-de.png b/doc/articles/.attachments/Finding-Uno-VS2022-Extension-Menu-de.png new file mode 100644 index 0000000..046684b Binary files /dev/null and b/doc/articles/.attachments/Finding-Uno-VS2022-Extension-Menu-de.png differ diff --git a/doc/articles/images/MvuxGallery-ShowCase.gif b/doc/articles/.attachments/MvuxGallery-ShowCase.gif similarity index 100% rename from doc/articles/images/MvuxGallery-ShowCase.gif rename to doc/articles/.attachments/MvuxGallery-ShowCase.gif diff --git a/doc/articles/.attachments/converting-class-to-vm-mvvm.png b/doc/articles/.attachments/converting-class-to-vm-mvvm.png new file mode 100644 index 0000000..390fcc6 Binary files /dev/null and b/doc/articles/.attachments/converting-class-to-vm-mvvm.png differ diff --git a/doc/articles/.attachments/place-project-in-sln-de.png b/doc/articles/.attachments/place-project-in-sln-de.png new file mode 100644 index 0000000..0449144 Binary files /dev/null and b/doc/articles/.attachments/place-project-in-sln-de.png differ diff --git a/doc/articles/.attachments/project-explorer-view-de.png b/doc/articles/.attachments/project-explorer-view-de.png new file mode 100644 index 0000000..5920c02 Binary files /dev/null and b/doc/articles/.attachments/project-explorer-view-de.png differ diff --git a/doc/articles/.attachments/renaming-class-to-record-mvux.png b/doc/articles/.attachments/renaming-class-to-record-mvux.png new file mode 100644 index 0000000..d80673d Binary files /dev/null and b/doc/articles/.attachments/renaming-class-to-record-mvux.png differ diff --git a/doc/articles/.attachments/select-platform.gif b/doc/articles/.attachments/select-platform.gif new file mode 100644 index 0000000..9e988a6 Binary files /dev/null and b/doc/articles/.attachments/select-platform.gif differ diff --git a/doc/articles/.attachments/select-presentation-mvux.png b/doc/articles/.attachments/select-presentation-mvux.png new file mode 100644 index 0000000..b4fc14a Binary files /dev/null and b/doc/articles/.attachments/select-presentation-mvux.png differ diff --git a/doc/articles/.attachments/select-regions-di-optional-localization.png b/doc/articles/.attachments/select-regions-di-optional-localization.png new file mode 100644 index 0000000..3907fea Binary files /dev/null and b/doc/articles/.attachments/select-regions-di-optional-localization.png differ diff --git a/doc/articles/.attachments/select-template-de.png b/doc/articles/.attachments/select-template-de.png new file mode 100644 index 0000000..8424784 Binary files /dev/null and b/doc/articles/.attachments/select-template-de.png differ diff --git a/doc/articles/.attachments/select-theme-optional-themeservice.png b/doc/articles/.attachments/select-theme-optional-themeservice.png new file mode 100644 index 0000000..8374788 Binary files /dev/null and b/doc/articles/.attachments/select-theme-optional-themeservice.png differ diff --git a/doc/articles/.attachments/select-toolkit-optional-vscode-debugging.png b/doc/articles/.attachments/select-toolkit-optional-vscode-debugging.png new file mode 100644 index 0000000..c5036e8 Binary files /dev/null and b/doc/articles/.attachments/select-toolkit-optional-vscode-debugging.png differ diff --git a/doc/articles/.attachments/select-xaml.png b/doc/articles/.attachments/select-xaml.png new file mode 100644 index 0000000..83d7f1c Binary files /dev/null and b/doc/articles/.attachments/select-xaml.png differ diff --git a/doc/articles/MvuxGallery/How-To-XamlNavigation.md b/doc/articles/MvuxGallery/How-To-XamlNavigation.md deleted file mode 100644 index 7e07eb1..0000000 --- a/doc/articles/MvuxGallery/How-To-XamlNavigation.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -uid: DevTKSS.Uno.SamplesApps.MvuxGallery.XamlNavigation ---- -# Navigieren via Xaml in Uno Apps - -Jede Anwendung, die mehr als eine einzige Seite umfasst oder eben nicht vollkommen überladen ist, braucht eine vernünftige "Navigation". - -Grundlegend enthält es die gleichen Bausteine wie man es von einer Navigation mittels Landkarte und Co kennt: - -- **Eine Sammlung von `ViewMap`'s**, mit der wir dem Navigator mitteilen, welche Seite mit welchen Daten zusammengehört. Das kann ein ViewModel oder auch spezifischen Daten sein, wobei es dann ein `DataViewMap` element zusätzlich wird. -- **Eine hierarchisch aufgebaute `Routes` Sammlung**, mit der wir dem Navigator mitteilen, in welcher Relation die verschiedenen Routen zueinander stehen. Wenn wir keine Relation in dem Sinne haben, dann wäre es eine schlichte flache Liste, aber sagen wir mal, wir wollen eine seitliche Navigationsleiste (hierzu können wir bspw. TabBar oder NavigationView nutzen) haben, dann wird das oberste Element in dem eben diese Navigationssteuerelemente UI technisch definiert sind, zum hierarchisch übergeordneten Element auch in unseren Routes, hierzu aber später mehr. - -## Voraussetzungen erfüllen - -Bevor es los geht, prüft bitte mit `Uno.Check` ob eure Entwicklungs-Umgebung startklar ist. Hierzu habe ich euch eine kurze Link Sammlung zu allen dahingehenden Dokumentations-Seiten im Bereich [Getting Started](../getting-started.md) erstellt. - -Hier findet ihr noch ein Video in dem wir alle hierfür notwendigen Schritte für das Desktop Target durchlaufen, nachdem Visual Studio installiert ist: - -[!Video https://youtu.be/oI6IZVOeQBI?si=gpYxFPMMvKrVZiCp] - -Solltet ihr schon eine existierende Uno Anwendung haben, prüft einfach mal in der .csproj Datei, ob ihr in der `UnoFeatures` Sammlung die Elemente `Hosting` und `Navigation` habt und fügt diese hinzu, wenn das nicht bereits der Fall sein sollte. - -Des weiteren benötigt eure App.xaml.cs Datei folgende Elemente als Anfangs Inhalt: - - -```diff -using Uno.Resizetizer; - -namespace DevTKSS.Uno.Samples.MvuxGallery; -public partial class App : Application -{ - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// - public App() - { - this.InitializeComponent(); - } - -+ protected Window? MainWindow { get; private set; } - protected IHost? Host { get; private set; } - -+ protected async override void OnLaunched(LaunchActivatedEventArgs args) -+ { -+ var builder = this.CreateBuilder(args) -+ // Add navigation support for toolkit controls such as TabBar and NavigationView -+ .UseToolkitNavigation() -+ .Configure(host => host -+ .UseNavigation(ReactiveViewModelMappings.ViewModelMappings, RegisterRoutes) -+ ); - MainWindow = builder.Window; - -#if DEBUG - MainWindow.UseStudio(); -#endif - MainWindow.SetWindowIcon(); - -+ Host = await builder.NavigateAsync(); - } -+ -+ private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes) -+ { -+ views.Register( -+ new ViewMap(ViewModel: typeof(ShellModel)), -+ new ViewMap(), -+ new ViewMap() -+ ); -+ -+ routes.Register( -+ new RouteMap("", View: views.FindByViewModel(), -+ Nested: -+ [ -+ new ("Main", View: views.FindByViewModel(), IsDefault:true), -+ new ("Second", View: views.FindByViewModel()), -+ ] -+ ) -+ ); -+ } -+ } - -``` - -Den Namespace, den wir in einer Xaml-basierten Navigation in einer Uno Anwendung benötigen, ist `Uno.Extensions.Navigation.UI`, meist mit dem xmlns Namespace Identifikator `xmlns:uen=` eurer Seite dann vorzufinden. - -## Navigation mittels NavigationView und Seiten - -### Intro mit Show Case - -Anhand der MvuxGallery: - -[!Video https://www.youtube.com/embed/vVvnK02r2ug?si=aa3V7HhtglLyCuXd] - -### Erstellen und Konfiguration der App mit dem Wizard - -[!Video https://youtu.be/UGKidrvdKpQ?si=wXszYWvbK4R7FCUc] - -(*weitere Video teile folgen!*) - -## Weitere interessante Informationen - -### Uno Documentation links - -- [How-To: Navigate in Xaml](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-NavigateInXAML.html) -- [How-To: Define Routes](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-DefineRoutes.html) -- [How-To: Regions](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-Regions.html) -- [How-To: Use NavigationView to Switch Views](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-UseNavigationView.html) -- [How-To: IRouteNotifier](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-IRouteNotifier.html) (*möglicherweise fehlerhaft aktuell*) diff --git a/doc/articles/MvuxGallery/Overview.md b/doc/articles/MvuxGallery/Overview.md deleted file mode 100644 index 6f13f90..0000000 --- a/doc/articles/MvuxGallery/Overview.md +++ /dev/null @@ -1,94 +0,0 @@ ---- -uid: DevTKSS.Uno.SampleApps.MvuxGallery.Overview ---- - -## Mvux Gallery - -The [Mvux Gallery (source link)](../../../src/DevTKSS.Uno.Samples.MvuxGallery/) Tutorials are currently: - -- [How-To: Xaml Navigation mit NavigationView (deutschsprachig)](./How-To-XamlNavigation.md) - -### Controls - -Here is a list of Controls and Features you can explore in the MvuxGallery App with links to their Source code in this Repository. - -- [Card](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/SimpleCardsPage.xaml) -- [Counter](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/CounterPage.xaml) and [CounterModel](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/CounterModel.cs) -- [FeedView + GridView](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml) and [Model](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) -- [FeedView + ListView](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/ListboardPage.xaml) and [Model](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs) -- [DataTemplate centralized Resource Definition](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Styles/Generic.xaml) -- [`ItemOverlayTemplate` DataTemplate](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Styles/Generic.xaml) (*Layout replicated from WinUI 3 Gallery*) -- [TabBar and TabBarItem](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml) and [Model for Binding Items to ListFeed](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) - -### Uno.Extensions - -- Mvux - - ListFeed - - State - - --> Almost every Model, detailed overview will follow. - -- Navigation - - via Xaml - - NavigationView - - [MainPage.xaml](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/MainPage.xaml) see [DE Tutorial](./How-To-XamlNavigation.md) - - Via Model - - (planned) - -- Hosting - - [App.xaml.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/App.xaml.cs) - -- DependencyInjection - - Service Registration - - [App.xaml.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/App.xaml.cs) - - Service Definition - - [CodeSampleService.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) - - [ICodeSampleService.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/ICodeSampleService.cs) - - Data Model Definition - - [SampleCode.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/SampleCode.cs) - - [CodeSampleOption.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOption.cs) - - [CodeSampleOptionsConfiguration.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) - -- Serialization - - JsonSerializerContext of each DataModel - - [CodeSampleOptionsContext](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptions.cs) - - [CodeSampleOptionsConfiguration](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) - - > [!NOTE] - > Currently `ValueTuple` and `Dictionary` Definitions of IOptions loaded Settings could'nt get successfully loaded, therefore this is defined as Array for Workaround. - -- Configuration - - Data for Serialization - - [appsettings.sampledata.json](../../../src/DevTKSS.Uno.Samples.MvuxGallery/appsettings.sampledata.json) - - [`IOptions` in Service](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) - -- Storage - - Via Model - - [DashboardModel.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) - - Via Service - - [CodeSampleService.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) - - Via [own StorageExtensions](../../../src/DevTKSS.Extensions.Uno/StorageExtensions.cs) and [IEnumerableExtensions](../../../src/DevTKSS.Extensions.Uno/EnumerableExtensions.string.cs) (*temporary imported until PR might get merged or Package gets published*) - - Via Uno.Extensions.Storage.StorageExtensions - - added as PR to Uno.Extensions [#2734](https://github.com/unoplatform/uno.extensions/pull/2734) - -- Localization - - **IStringLocalizer** - - Resources Dictionaries (*I recommend to lookup those links using Visual Studio 2022*) - - [en](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Strings/en/) - - [de](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Strings/de/) - - Binding current value in `IState` and to corresponding View - - [DashboardModel.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) - - [ListboardModel.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs) - - [MainModel.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs) - - [CounterModel.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/CounterModel.cs) - - Requesting localized Items via FeedView - - Service Definition - - [GalleryImageService.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageService.cs) - - [IGalleryImageService.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/IGalleryImageService.cs) - - Data Model Definition - - [GalleryImageModel.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageModel.cs) - - **ILocalizationService** - - Requesting current culture - - [GalleryImageService.cs](../../../src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageService.cs) - - Switching culture - - (planned) diff --git a/doc/articles/MvuxGallery/toc.yml b/doc/articles/MvuxGallery/toc.yml deleted file mode 100644 index ff7288c..0000000 --- a/doc/articles/MvuxGallery/toc.yml +++ /dev/null @@ -1,9 +0,0 @@ -# yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/toc.schema.json -topicHref: Overview.md -items: -- name: Overview - uid: DevTKSS.Uno.SampleApps.MvuxGallery.Overview - href: Overview.md -- name: Xaml Navigation - uid: DevTKSS.Uno.SampleApps.MvuxGallery.XamlNavigation - href: How-To-XamlNavigation.md diff --git a/doc/articles/de/HowTo-Adding-New-Pages-de.md b/doc/articles/de/HowTo-Adding-New-Pages-de.md new file mode 100644 index 0000000..e97b710 --- /dev/null +++ b/doc/articles/de/HowTo-Adding-New-Pages-de.md @@ -0,0 +1,45 @@ +--- +uid: DevTKSS.Uno.Setup.HowTo-AddingNewPages.de +--- + +## Anleitung: Hinzufügen einer Seite + +In dieser Anleitung werden wir zusammen eine neue Seite mit Beispielinhalt zu unserer Uno App hinzufügen. + +1. **Neues Element hinzufügen:** + 1. Klicke hierzu mit der rechten Maustaste auf den Ordner **Presentation** rechts im Projektmappen-Browser + 2. Wähle **Hinzufügen** aus + 3. Und klicke dann auf **Neues Element** + + ![Hinzufügen-neues-Element-zu-Projektmappe](../.attachments/Adding-new-Item-to-sln-de.png) + +2. **Seiten Element erstellen:** + 1. Wähle oben in der Liste das Element **`Page (Uno Platform)`** aus und gebe diesem einen Namen mit der Endung Page. Beispielsweise: `SamplePage.xaml`. Diese Endung ist zwingend erforderlich für Uno Anwendungen. + 2. Klicke nun noch auf **Hinzufüge**. + + ![Hinzufügen-neues-Element-Seite](../.attachments/Adding-new-Item-Page-de.png) + +### Hinzufügen von Beispiel Inhalt + +Um nun auf der Seite, auch zu sehen, dass wir uns auch auf der gewünschten Seite befinden, fügen wir nun noch einen einfachen Beispiel Inhalt hinzu: + +```xml + + + + + +``` + +Somit wird diese Seite im Endeffekt der Text `Hello World` in diesem Fall angezeigt werden. Dir steht es natürlich frei, jeden beliebigen Inhalt zu verwenden. + +--- diff --git a/doc/articles/de/HowTo-Adding-New-VM-Class-Record-de.md b/doc/articles/de/HowTo-Adding-New-VM-Class-Record-de.md new file mode 100644 index 0000000..4e2bad9 --- /dev/null +++ b/doc/articles/de/HowTo-Adding-New-VM-Class-Record-de.md @@ -0,0 +1,49 @@ +--- +uid: DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.de +--- + +## Anleitung: Aus Klassen ein ViewModel oder Model erstellen + +In dieser Anleitung wollen wir uns einmal anschauen, wie man in Visual Studio ein neues Klassen-Element erstellen kann und anschließend entweder ein ViewModel oder ein Model für die Verwendung in einer Uno Platform Anwendung mit **MVUX** erstellen kann. + +Für die folgenden Schritte, nehmen wir einmal an, die Seite, zu der das zu erstellende Element gehören soll, heißt **SamplePage.xaml** + +1. **Neues Element (für die Verwendung als Model oder ViewModel) hinzufügen:** + 1. Klicke hierzu mit der rechten Maustaste auf den Ordner **Presentation** rechts im Projektmappen-Browser + 2. Wähle **Hinzufügen** aus + 3. Und klicke dann auf **Neues Element** + + ![Hinzufügen-neues-Element-zu-Projektmappe](../.attachments/Adding-new-Item-to-sln-de.png) + +2. **Klassen Element erstellen:** + 1. Wähle in der Liste das Element **`Class`** aus und benenne diese nach folgendem Schema: + + **Deine Anwendung nutzt:** + - **Mvvm:** `SampleViewModel.cs` + - **Mvux:** `SampleModel.cs` + +3. Klicke nun noch auf **Hinzufüge**. + + ![Hinzufügen-neues-Element-Klasse](../.attachments/Adding-new-Item-Class.png) + +### [Ein Model erstellen **Mvux**](#tab/create-mvux-model) + +Um ein für Mvux passendes Model zu erstellen: + +1. Füge vor das aktuelle `class` ein `partial` ein. +2. Ersetze `class` durch `record` +3. Mit dem Snippet Kürzel `ctor` kannst du dir auch direkt automatisch einen (Sekundären-) Konstruktor einfügen lassen. + +![Umbenennen-Klasse-zu-Mvux-Model](../.attachments/renaming-class-to-record-mvux.png) + +### [Ein ViewModel erstellen](#tab/create-mvvm-viewmodel) + +Um ein für Mvvm passendes ViewModel zu erstellen: + +1. Füge vor `class` ein `partial` ein. +2. Füge hinter deinen ViewModel Namen `: ObservableObject` hinzu +3. Mit dem Snippet Kürzel `ctor` kannst du dir auch direkt automatisch einen (Sekundären-) Konstruktor einfügen lassen. + +![Konvertieren-Klasse-zu-ViewModel-Mvvm](../.attachments/converting-class-to-vm-mvvm.png) + +--- diff --git a/doc/articles/de/HowTo-CreateApp-de.md b/doc/articles/de/HowTo-CreateApp-de.md new file mode 100644 index 0000000..bd396ce --- /dev/null +++ b/doc/articles/de/HowTo-CreateApp-de.md @@ -0,0 +1,86 @@ +--- +uid: DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.de +--- + +## Tutorial: Eine neue Uno Anwendung erstellen + +In dieser Anleitung lernst du, wie du eine Uno Platform Anwendung mittels des Wizard oder dotnet CLI erstellen kannst um beispielsweise das [Xaml Navigation App Tutorial](./Navigation/Extensions-Navigation-de.md) zu verfolgen. + +Um dem folgen zu können, solltest du zuvor die [Anleitung Entwicklungsumgebung einrichten](xref:DevTKSS.Uno.Setup.DevelopmentEnvironment.de) durchlaufen haben. + +## Video Tutorial zur Konfiguration + +![How To: Konfigurieren unserer Uno App Visual Studio Wizard](https://youtu.be/UGKidrvdKpQ) + +## Eine Uno App via Template erstellen und konfigurieren + +Im folgenden wirst du lernen, wie du eine Uno App konfigurieren kannst, indem du die gewünschten Optionen auswählst. Du kannst entweder den Visual Studio Wizard verwenden oder das dotnet CLI Tool nutzen. Bei letzterem empfiehlt es sich, den [Web Wizard](https://new.platform.uno/) zu besuchen, um die Konfiguration zu erleichtern und den passenden `dotnet new` Command zu erhalten! + +### [Visual Studio 2022](#tab/vs-wizard) + +#### Template auswählen + +1. Öffne Visual Studio 2022 und wähle im Startfenster **"Neues Projekt erstellen"** aus. +2. Suche nach dem Template **"Uno App"** und wähle es aus. Klicke auf **"Weiter"**. + + ![select-template](../.attachments/select-template-de.png) + +3. Gib deinem Projekt einen Namen und aktiviere die Option **"Projekt im selben Verzeichnis wie die Lösung erstellen"**. Anschließend klicke auf **"Erstellen"**. + + ![place-project-in-sln](../.attachments/place-project-in-sln-de.png) + +#### Der Template Wizard + +**Wähle die folgenden Optionen im Visual Studio Wizard aus, um deine App zu konfigurieren:** *(am beispiel des Xaml Navigation App Tutorials)* + +1. Verwende das Preset **`recommended`** +1. Ziel-Framework: **`net9.0`** + +1. Als `Platform` wähle mindestens **Desktop** bzw. **Skia Desktop** aus. + +1. Markup: **`Xaml`** + + ![select-Xaml](../.attachments/select-xaml.png) + +1. Präsentation: **`MVUX`** + + ![select-MVUX](../.attachments/select-presentation-mvux.png) + +1. Wähle das **Material Design Theme** unter **Themes** aus. + + ![select-theme-optional-themeservice](../.attachments/select-theme-optional-themeservice.png) + + > [!TIP] + > Hier ist standardmäßig auch **ThemeService** angewählt, damit könntest du später dann auch zwischen hell und dunklem UI wechseln, der wird hier nicht direkt benötigt, kannst du aber wenn du möchtest drin lassen. + +1. Erweiterungen: **`Regions`**, **`DependencyInjection`** + + ![select-extensions](../.attachments/select-regions-di-optional-localization.png) + +1. *(Optional)* wähle das **Uno Toolkit** aus. + + ![select-toolkit-optional-vscode-debugging](../.attachments/select-toolkit-optional-vscode-debugging.png) + + > [!TIP] + > Wenn du dir offen lassen möchtest, später in Visual Studio Code zu entwickeln, solltest du hier auch `Visual Studio Code Debugging` auswählen. + +1. Klicke nun zum Schluss auf **`Create`**, um die App zu generieren. + +### [Das dotnet CLI Tool](#tab/dotnet-cli) + +1. Öffne optional in deinem Browser den [Uno Platform Web Wizard](https://new.platform.uno/), um die Konfiguration zu erleichtern und den passenden `dotnet new` Command zu erhalten. Alternativ kannst du alle möglichen Optionen jederzeit mittels `dotnet new unoapp --help` im Terminal einsehen! +1. Öffne ein Terminal und navigiere in das gewünschte Verzeichnis. +1. Mit dem nachfolgenden Befehl, erhältst du die Mindestkonfiguration um eine neue App für das [**Xaml Navigation App Tutorial**](./Navigation/Extensions-Navigation-de.md) zu erstellen: + + ```bash + dotnet new unoapp -o XamlNavigationApp -preset "recommended" -platforms "desktop" -config False -http "none" -loc False -dsp False -theme-service False + ``` + + Alternativ, wenn du alle im Video gezeigten Optionen nutzen möchtest, kannst du folgenden Befehl verwenden: + + ```bash + dotnet new unoapp -o XamlNavigationApp -preset "recommended" -platforms "desktop" -http "none" + ``` + +--- + diff --git a/doc/articles/de/HowTo-Setup-DevelopmentEnvironment-de.md b/doc/articles/de/HowTo-Setup-DevelopmentEnvironment-de.md new file mode 100644 index 0000000..8e5e0dc --- /dev/null +++ b/doc/articles/de/HowTo-Setup-DevelopmentEnvironment-de.md @@ -0,0 +1,81 @@ +--- +uid: DevTKSS.Uno.Setup.DevelopmentEnvironment.de +--- + +## Anleitung: Entwicklungsumgebung für Uno Platform Apps einrichten + +Im folgenden werden wir uns zusammen anschauen, wie man die Entwicklungsumgebung für die Anwendungsentwicklung mit Uno Platform kinderleicht einrichten kann, beziehungsweise das Command Line Interface (**CLI**) Tool `dotnet tool uno-check` diese Routineaufgabe für uns erledigen lassen kann. + +> [!TIP] +> Seit dem v6 Release von Uno (SDK & Extension) ist dieses von vorne herein auch in der Visual Studio Uno Platform Extension inkludiert! + +> [!TIP] +> Solltest du bei der Ausführung des Tools Probleme haben, kannst du hier den zugehörigen [Offiziellen Guide zu Uno-Check von Uno Platform](https://platform.uno/docs/articles/external/uno.check/doc/using-uno-check.html) finden. + +### Videoanleitung + +![How To: Einrichten unserer Uno Platform Entwicklungsumgebung](https://youtu.be/oI6IZVOeQBI) + +> [!NOTE] +> Die aktuellste Anleitung für deinen Start mit Uno Platform findest du immer im offiziellen [Quick Start Guide](https://platform.uno/docs/articles/get-started.html). + +--- + +### Schritt für Schritt Anleitung zur Einrichtung + +1. **Wähle und installiere deine bevorzugte IDE** + + > [!NOTE] + > In diesem Guide wird Visual Studio 2022 Community Edition verwendet. Solltest du mit Rider oder Visual Studio Code arbeiten, informiere dich bitte im zuvor verlinkten Quick Start Guide über etwaige Abweichungen! + + [Offizielle Installationsseite für Visual Studio - auch VS Code](https://visualstudio.microsoft.com) + + **IDE**: Integrierte Entwicklungs-Umgebung + +1. **Installiere die Uno Platform-Erweiterung** + + Erhältlich im [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=nventive.unoplatform) + +1. **Installiere `Uno.Check` über die Kommandozeile** + + ```bash + dotnet tool install -g Uno.Check + ``` + +1. **Starte `Uno.Check`, um deine Umgebung zu prüfen** + + Entweder via des zuvor schon genutzten Terminals: + + ```bash + uno-check check + ``` + + Oder wie zuvor schon erwähnt, können wir seit der 6. Version der Visual Studio Extension von Uno Platform `Uno.Check` bereits automatisch dort in unserer IDE verwenden. Also immer wenn wir unsere Projektmappe öffnen, läuft es automatisch durch, bzw. können wir es auch in dem Extensions Drop-Down Menü in Visual Studio > Uno Platform > `Run Uno.Check` auch manuell anstoßen. Es schaut dann nach, welche Endgeräte wir in unserer Projektdatei spezifiziert haben und prüft alle entsprechend benötigten Installationen auf Existenz, aber auch ob wir mit den neusten verfügbaren Versionen arbeiten. Das ist besonders dann hilfreich, wenn Fehlerbehebungen stattgefunden haben und natürlich auch wenn es ein neues Major-Release gab. + + ![Finde das Uno Extensions Menü in den Visual Studio](../.attachments/Finding-Uno-VS2022-Extension-Menu-de.png) + +### Optionen zur Konfiguration von Uno Check + +Wenn du nur für bestimmte `Targets`, also Endgeräte deine Anwendungen entwickeln möchtest und dem entsprechend auch nicht alle anderen Workloads benötigst, also bspw. für das [XamlNavigation Tutorial](./Navigation/Extensions-Navigation-de.md) + +> [!TIP] +> Um eine übersicht über die verfügbaren Befehle, Konfigurationen und optionale zugehörige Parameter kannst du erhalten, indem du `uno-check -h` im Terminal eingibst. + +> [!NOTE] +> Weitere Infos zu den Konfigurationsmöglichkeiten, kannst du in der [Uno.Check Dokumentation](https://platform.uno/docs/articles/external/uno.check/doc/configuring-uno-check.html) finden! + +### **Probleme bei der Einrichtung?** + +Sieh dir den [Troubleshooting Guide](https://platform.uno/docs/articles/external/uno.check/doc/troubleshooting-uno-check.html) an. + +--- + +### Nächste Schritte + +Sobald deine Umgebung eingerichtet ist, kannst du neben den Tutorials hier, auch beispielsweise mit dem [Counter Workshop](https://platform.uno/docs/articles/getting-started/counterapp/get-started-counter.html) starten und diese Grundlagen lernen: + +- Die Struktur einer Uno-App +- Den Umgang mit Assets (Bilder/Icons) über **`Uno.Resizetizer`** +- Die Verwendung von Commands und Bindings + +--- diff --git a/doc/articles/de/HowTo-Using-DI-in-ctor-de.md b/doc/articles/de/HowTo-Using-DI-in-ctor-de.md new file mode 100644 index 0000000..139074d --- /dev/null +++ b/doc/articles/de/HowTo-Using-DI-in-ctor-de.md @@ -0,0 +1,22 @@ +--- +uid: DevTKSS.Uno.Setup.Using-DI-in-ctor.de +--- +## Anleitung: Nutze Konstruktor Parameter für DependencyInjection + +Diese Anleitung baut darauf auf, dass du bereits ein Model, ViewModel oder eine Service Klasse erstellt hast. Solltest du das noch nicht getan haben, ist hier eine [Anleitung um das zu tun](xref:DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.de) + +Um **DependencyInjection** in deinem Model oder ViewModel, oder jeglicher Klassen Definition ebenso nutzen möchtest, füge nun in den erstellten Konstruktor die für die Funktionen während der Laufzeit benötigten (*optimalerweise*) Interfaces und/oder Klassen deiner erwarteten Services hinzu: + +## [In Mvux](#tab/model-with-di-params) + +![Hinzufügen-von-DI-Parametern-via-Konstruktor-Mvux](../.attachments/Adding-mvux-model-constructor-DI.png) + +## [In Mvvm](#tab/viewmodel-with-di-params) + +![Hinzufügen-von-DI-Parametern-via-Konstruktor-Mvvm](../.attachments/Adding-mvvm-viewmodel-constructor-DI.png) + +## [Sonstige Klassen oder Services](#tab/classes-with-di-params) + +![Hinzufügen-von-DI-Parametern-via-Konstruktor-Klassen](../.attachments/Adding-service-constructor-DI.png) + +--- diff --git a/doc/articles/de/Introduction-de.md b/doc/articles/de/Introduction-de.md new file mode 100644 index 0000000..8eba71e --- /dev/null +++ b/doc/articles/de/Introduction-de.md @@ -0,0 +1,39 @@ +--- +uid: DevTKSS.Uno.SampleApps.Intro.de +--- + +# Dokumentation & Tutorials + +Hier findest du praktische Anleitungen und Einblicke zu verschiedenen Beispiel-Apps, die mit der **Uno Platform** entwickelt wurden. +Die Tutorials helfen dir – unabhängig von deinem Vorwissen – die gezeigten Konzepte schnell zu verstehen und direkt umzusetzen. + +> 🎯 Ziel: Entwickler*innen aller Erfahrungsstufen beim Einstieg in die Uno Platform unterstützen. + +--- + +## Erste Schritte + +- [Umgebung einrichten für Uno Platform App-Entwicklung](xref:DevTKSS.Uno.Setup.DevelopmentEnvironment.de) +- [Link-Sammlung für den Einstieg in die Uno App Entwicklung](xref:DevTKSS.Uno.ResourcesLookup.de) + +--- + +## Aktuelle Beispiel-Apps + +Hier ein schneller Überblick über die enthaltenen Samples. Detaillierte Infos findest du jeweils im zugehörigen Kapitel des Inhaltsverzeichnisses. + +### MvuxGallery + +- [Dokumentation ansehen](xref:DevTKSS.Uno.SampleApps.MvuxGallery.Overview.de) +- [Zum Quellcode](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/) + +### XamlNavigationApp (Mvux) + +- [NavigationView in MVUX oder MVVM + XAML](xref:DevTKSS.Uno.ExtensionsNavigation.Overview.de) +- [Zum Quellcode](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.XamlNavigationApp-1/) + +--- + +## Weitere Ressourcen + +- [API-Dokumentation](~/api/index.md) diff --git a/doc/articles/de/MvuxGallery-Overview-de.md b/doc/articles/de/MvuxGallery-Overview-de.md new file mode 100644 index 0000000..2c60f00 --- /dev/null +++ b/doc/articles/de/MvuxGallery-Overview-de.md @@ -0,0 +1,93 @@ +--- +uid: DevTKSS.Uno.SampleApps.MvuxGallery.Overview.de +--- + +# Mvux Galerie Übersicht + +![MvuxGallery](../.attachments/DevTKSS%20Uno%20Mvux%20Samples%20Gallery%20App-Thumbnail.png) + +Die [Mvux Galerie (Quelllink)](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery) soll Ihnen einen Eindruck davon vermitteln, was mit den Mvux- und Uno.Extensions-Paketen in Ihrer Uno Platform App möglich ist. + +Da sie bereits viele Steuerelemente und Funktionen enthält, habe ich mich entschieden, einige Tutorials zu erstellen, um Sie durch den Prozess des Erstellens dieser App mit einigen Beispiel-Apps und hinzugefügten Tutorials zu führen. Werfen Sie einen Blick auf das Inhaltsverzeichnis und die Navigationsleiste in diesen Dokumenten, um zu sehen, was bereits verfügbar ist. + +## Beispiel-Steuerelemente + +Hier ist eine Liste von Steuerelementen und Funktionen, die Sie in der MvuxGallery App erkunden können, mit Links zu ihrem Quellcode in der MvuxGallery App: + +- [Card](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/SimpleCardsPage.xaml) +- [Counter](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/CounterPage.xaml) und [CounterModel](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/CounterModel.cs) +- [FeedView + GridView](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml) und [Model](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) +- [FeedView + ListView](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/ListboardPage.xaml) und [Model](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs) +- [DataTemplate zentrale Style Ressourcendefinition](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Styles/Generic.xaml) +- [`ItemOverlayTemplate` DataTemplate](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Styles/Generic.xaml) (*Layout repliziert aus WinUI 3 Galerie*) +- [TabBar und TabBarItem](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml) und [Model für das Binden von Elementen an ListFeed](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) + +## Beispielhafte Uno.Extensions + +- Mvux + - ListFeed + - State + + --> Fast jedes Model, detaillierte Übersicht folgt. + +- Navigation + - über Xaml + - NavigationView + - [MainPage.xaml](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/MainPage.xaml) siehe [hier geht's zum Tutorial!](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de) + - Über Model + - (geplant) + +- Hosting + - [App.xaml.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/App.xaml.cs) + +- DependencyInjection + - Service Registrierung + - [App.xaml.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/App.xaml.cs) + - Service Definition + - [CodeSampleService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) + - [ICodeSampleService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery//Models/CodeSamples/ICodeSampleService.cs) + - Datenmodell Definition + - [SampleCode.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/SampleCode.cs) + - [CodeSampleOption.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOption.cs) + - [CodeSampleOptionsConfiguration.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) + +- Serialization + - JsonSerializerContext jedes Datenmodells + - [CodeSampleOptionsContext](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptions.cs) + - [CodeSampleOptionsConfiguration](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) + +- Konfiguration + - Daten für Serialization + - [appsettings.sampledata.json](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/appsettings.sampledata.json) + - [`IOptions` im Service](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) + +- Storage + - Über Model + - [DashboardModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) + - Über Service + - [CodeSampleService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) + - Über [eigene StorageExtensions](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Extensions.Uno/StorageExtensions.cs) und [IEnumerableExtensions](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Extensions.Uno/EnumerableExtensions.string.cs) (*vorübergehend importiert, bis PR möglicherweise gemergt wird oder anstelle ein eigenständiges Paket veröffentlicht wird*) + - Über Uno.Extensions.Storage.StorageExtensions + - hinzugefügt als PR zu Uno.Extensions [#2734](https://github.com/unoplatform/uno.extensions/pull/2734) + +- Lokalisierung + - **IStringLocalizer** + - Ressourcenwörterbücher (*Ich empfehle, diese Links mit Visual Studio 2022 zu durchsuchen*) + - [en](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Strings/en/Resources.resw) + - [de](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Strings/de/Resources.resw) + - Bindung des aktuellen Werts in `IState` und zur entsprechenden Ansicht + - [DashboardModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) + - [ListboardModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs) + - [MainModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs) + - [CounterModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/CounterModel.cs) + - Anforderung lokalisierter Elemente über FeedView + - Service Definition + - [GalleryImageService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageService.cs) + - [IGalleryImageService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/IGalleryImageService.cs) + - Datenmodell Definition + - [GalleryImageModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageModel.cs) + - **ILocalizationService** + - Anforderung der aktuellen Kultur + - [GalleryImageService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageService.cs) + - Wechsel der Kultur + - (geplant) diff --git a/doc/articles/de/Navigation/Extensions-Navigation-de.md b/doc/articles/de/Navigation/Extensions-Navigation-de.md new file mode 100644 index 0000000..5a56615 --- /dev/null +++ b/doc/articles/de/Navigation/Extensions-Navigation-de.md @@ -0,0 +1,57 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.Overview.de +--- + +# Tutorial: Navigation mit Uno Extensions + +![Mvux XamlNavigationApp](../../.attachments/DevTKSS.Uno.XamlNavigationApp.png) + +## Inhalt dieses Tutorials + +- Ein `NavigationView`-Steuerelement zur Navigation. +- Routen, die in der Datei `App.xaml` definiert sind. +- Eine `MainPage.xaml`, die als Einstiegspunkt für die Navigation dient. +- `DashboardPage` und `SecondPage` als Beispielseiten für die Navigation. +- Jede Seite bindet an einen `IState`-Eigenschaft im zugehörigen Model, um die Zustandsverwaltung gemäß MVUX zu demonstrieren. + +Da diese Beispiel-App im Rahmen eines Community-Tutorial-Videos auf YouTube erstellt wurde, kannst du dem Video folgen und den Aufbau der App Schritt für Schritt nachvollziehen. Dort sind auch Transkripte hinzugefügt, da es in Deutscher Sprache aufgenommen wurde. + +- [Zur Playlist auf YouTube](https://youtube.com/playlist?list=PLEL6kb4Bivm_g81iKBl-f0eYPNr5h2dFX&si=qHkpAUMSW9s8GZCO) + +## Vorstellung der Möglichkeiten + +Lass uns zuerst einmal schauen, was man beispielsweise in einer Xaml-basierten Uno Anwendung damit erstellen kann, am beispiel der MvuxGallery. + +![MvuxGallery Showcase](https://youtu.be/vVvnK02r2ug) + +--- + +## Voraussetzungen + +Diese Tutorial Reihe baut darauf auf, dass deine Entwicklungsumgebung bereits vollständig eingerichtet ist und der Befehl `uno-check --tfm net9.0-desktop` ausgeführt in deinem Terminal grünes Licht gibt. Hier kannst du diese auch noch einmal nachschauen: + +- [Tutorial: Einrichten der Entwicklungsumgebung](xref:DevTKSS.Uno.Setup.DevelopmentEnvironment.de) + +## Nächste Schritte + +In den nächsten Schritten findest du Anleitungen, mit welchen du lernen kannst, wie man in einer Uno Platform Anwendung eine Navigation mithilfe des Uno Feature `Navigation`, also des `Uno.Extensions.Navigation` NuGet implementieren kann. Hierfür kannst du einfach die Fußleisten Navigation verwenden, um die einzelnen Schritte zu durchlaufen. + +**Ich starte mit...** + +[**Einer neuen Uno Platform App**](xref:DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.de) | [**Einer bestehenden Uno Platform App**](xref:DevTKSS.Uno.ExtensionsNavigation.UpgradeExistingApp.de) + +Wenn du diesen Schritt abgeschlossen hast, fahren wir mit der Implementierung der Navigation mittels des `NavigationView` Steuerelements fort. + +[**Implementierung der Navigation via NavigationView**](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de) + +--- + +- [Hier geht's zum Source Code der verwendeten Beispiel Anwendung XamlNavigationApp](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.XamlNavigationApp-1) + +### Uno Dokumentation Links + +- [How-To: Navigate in Xaml](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-NavigateInXAML.html) +- [How-To: Define Routes](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-DefineRoutes.html) +- [How-To: Regions](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-Regions.html) +- [How-To: Use NavigationView to Switch Views](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-UseNavigationView.html) +- [How-To: IRouteNotifier](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-IRouteNotifier.html) diff --git a/doc/articles/de/Navigation/HowTo-ChangeRoutes-de.md b/doc/articles/de/Navigation/HowTo-ChangeRoutes-de.md new file mode 100644 index 0000000..4e82829 --- /dev/null +++ b/doc/articles/de/Navigation/HowTo-ChangeRoutes-de.md @@ -0,0 +1,145 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-ChangeRoutes.de +--- + +# Anleitung: Reagieren auf Routen Änderungen + +Wenn wir nun Routen in unserer Anwendung registriert haben, möchten wir vielleicht auch auf Änderungen der Route reagieren, um beispielsweise bestimmte Aktionen auszuführen oder Daten zu laden. + +Dafür können wir den `IRouteNotifier` nutzen, um uns über Änderungen der aktuellen Route zu informieren. Dieser enthält das Ereignis `RouteChanged`, das ausgelöst wird, wenn sich die Route ändert. Im folgenden Beispiel werde ich dir zeigen, wie du dies in deiner Anwendung implementieren kannst. + +## Voraussetzungen + +Bevor du mit der Implementierung beginnst, benötigst du zum einen natürlich das Uno Feature "Navigation" in deiner Anwendung, also die `Uno.Extensions.Navigation` Bibliothek, zum anderen aber auch eine oder mehrere [Routen registriert](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.de) haben und eine ViewModel oder Model Klasse mit zugehöriger Seite, also View erzeugt haben und dort navigieren können. Der Einfachheit halber werde ich davon ausgehen, dass du hierfür die folgenden drei Tutorials bereits erfolgreich absolviert hast: + +- [Tutorial: Erstellen des UI mit einer `NavigationView` in Xaml](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de) +- [Tutorial: Routen in der App registrieren](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.de) +- [Tutorial: Anleitung: Navigation im Model oder ViewModel](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-DefiningModelOrViewModel.de) + +## Tutorial Video: Reagieren auf Routen Änderungen + +In diesem Video werden wir uns zusammen anschauen, wie du auf Routen Änderungen in deiner Anwendung reagieren kannst, indem du den `IRouteNotifier` verwendest. Wir werden sehen, wie du das Ereignis `RouteChanged` abonnierst und darauf reagierst. Den Code kannst du dabei direkt aus dem Code hierunter kopieren und in deine Anwendung einfügen, wenn du möchtest, aber aus eigener Erfahrung heraus hilft es dir mehr, den Code selber zu schreiben und dabei zuzuschauen, wie es funktioniert. So kannst du auch besser verstehen, was du tust und warum. + +![Reagieren-auf-Routen-aenderungen-mit-IRouteNotifier](https://www.youtube.com/embed/RZ3RirA7jhk) + +## IRouteNotifier im Model Konstruktor anfordern + +Um den `IRouteNotifier` in deinem Model oder ViewModel zu verwenden, musst du ihn als Abhängigkeit im Konstruktor anfordern. Hier ist ein Beispiel, wie du dies in einem ViewModel machen kannst: + +```csharp +public partial record MainModel +{ + private readonly IRouteNotifier _routeNotifier; + + public MainModel(IRouteNotifier routeNotifier) + { + _routeNotifier = routeNotifier; + _routeNotifier.RouteChanged += OnRouteChanged; + } + + private void OnRouteChanged(object sender, RouteChangedEventArgs e) + { + // Hier kannst du später auf die Routenänderung reagieren + } +} +``` + +> [!IMPORTANT] +> Am verlässlichsten aus meiner Erfahrung funktioniert es, wenn wir das Ereignis in eine eigene Methode auslagern, also nicht als Lambda Ausdruck im Konstruktor registrieren. Eigentlich sollte zwar das selbe passieren, aber ich hatte öfters das Problem, dass die Methode nicht aufgerufen wurde, wenn ich es als Lambda Ausdruck geschrieben habe. + +## Verknüpfen des Routen Namens mit einem `IState` im Model + +Um den aktuellen Routen Namen in deinem Model oder ViewModel zu speichern und darauf zuzugreifen, kannst du ein `IState` verwenden. Hier ist ein Beispiel, wie du dies implementieren kannst: + +```csharp +public IState Title => State.Value(this, () => "Dashboard"); +``` + +Nun ist der aktuelle Inhalt natürlich hardcoded. Was wenn wir uns aber zwischendurch doch mal umentscheiden und die Seite umbenennen? Und wollen wir denn überhaupt dass der Titel, in dem Fall unser Routen Name gerade, abhängig davon ist, wie unser Model heißt? Gehen wir mal davon aus, dass dem nicht so ist. + +1. Wollen wir also nun als initialen Wert erstmal den aktuellen Routen Namen verwenden ohne den Namen hart zu codieren, brauchen wir erstmal einen `INavigator`, falls wir den noch nicht zuvor angefordert haben: + + ```diff + public partial record MainModel + { + private readonly IRouteNotifier _routeNotifier; + + private readonly INavigator _navigator; + + public MainModel( + IRouteNotifier routeNotifier, + + INavigator navigator) + { + _routeNotifier = routeNotifier; + _routeNotifier.RouteChanged += Main_OnRouteChanged; + + _navigator = navigator; + } + } + ``` + +2. Und danach können wir dann hiermit auch direkt unsere aktuelle Route abfragen, auf der wir uns befinden: + + ```csharp + public IState Title => State.Value(this, () => _navigator.Route?.ToString() ?? string.Empty); + ``` + + **Was passiert hier?** + Was wir effektiv nun geändert haben, ist dass wir nun: + 1. Von unserem Navigator die Eigenschaft `Route` abfragen, die uns das aktuelle `Route`-Objekt oder (laut Compiler) möglicherweise auch `null` zurückgibt. + 2. Der `Route`-Type hat eine Überschreibung der `ToString()` Methode, welche uns bei Abfrage dann den Routen-Namen als `string` zurückgibt. + 3. Falls dieser Wert selber oder eben infolge von einem `null` Wert der `Route` Eigenschaft `null` sein sollte, geben wir stattdessen einen leeren String zurück mittels des Null-Koaleszenz Operators `??`. + +Und somit haben wir auch schon unseren aktuellen Routen Namen griffbereit hinterlegt in unserem Model im `Title`. + +Dort im Model selber bringt unserem User das aber natürlich erstmal nichts, also müssen wir das Ganze ja auch noch irgendwie in der UI anzeigen. Erinnerst du dich noch daran, dass ich im [Tutorial: Erstellen des UI mit einer `NavigationView` in Xaml](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de) gezeigt habe, wie du den Header der `NavigationView` an eine Eigenschaft im Model binden kannst? Zufälligerweise hieß diese Eigenschaft genau `Title`. Perfekt! + +Solltest du das noch nicht gemacht haben, dann geht das jetzt ganz einfach auch noch nachträglich: + +```diff + + + + + + + + + +``` + +## Reagieren auf Routen Änderungen + +Nun fehlt nur noch die eigentliche Reaktion auf die Routen Änderung. Das machen wir in der Methode `OnRouteChanged`, die wir zuvor im Konstruktor registriert haben. Hier ist ein Beispiel, wie du dies implementieren kannst: + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/MainModel.cs#L19-L22)] + +**Was passiert hier?** + +1. Ein `IState` hat die Methode `SetAsync`, mit der wir den Wert des States ändern können. Diese ist asynchron, daher verwenden wir das `await` Schlüsselwort davor. +2. In den RouteChangedEventArgs `e` erhalten wir den `Navigator`, der wie schon zuvor beim [Verknüpfen des Routen Namens](#verknüpfen-des-routen-namens-mit-einem-istatestring-im-model) in der Überladung der `Route.ToString()` Methode den aktuellen Routen Namen als `string` zurückgibt. +3. Diesen übergeben wir dann direkt an die `SetAsync` Methode und lassen das Mvux für uns die Aktualisierung des States und somit auch der UI übernehmen. + +> [!TIP] +> Ist dir aufgefallen, dass wir hier beim EventHandler `OnRouteChanged` `async void` verwenden mussten? Das liegt daran, dass EventHandler immer `void` zurückgeben müssen. In solchen Fällen ist es üblich, `async void` zu verwenden, um asynchrone Operationen durchzuführen. Allerdings solltest du `async void` nur in solchen Fällen mit EventHandlern verwenden und sonst immer `async Task` oder `ValueTask` bevorzugen, um eine bessere Fehlerbehandlung und Kontrolle über asynchrone Operationen zu haben. Ohne das `async` Schlüsselwort könnten wir das `await` nicht verwenden, was uns hier aber zwingend notwendig ist, um die asynchrone Methode `SetAsync` aufzurufen ohne vom Compiler wiederum die Meldung zu bekommen, dass wir `await` nutzen sollten. + +## Anwendung starten + +Nun sind wir auch schon fertig mit dem erstellen unseres Codes und können die Anwendung einfach mal starten. + +Wenn du nun in der NavigationView auf einen anderen Menüpunkt klickst und korrekt zuvor die Routen registriert hast, solltest du sehen, dass sich der Text im Header der NavigationView entsprechend ändert und den aktuellen Routen Namen anzeigt. + +Glückwunsch! Du hast erfolgreich gelernt, wie du auf Routen Änderungen in deiner Anwendung reagieren kannst, indem du den `IRouteNotifier` verwendest und den aktuellen Routen Namen in deinem Model speicherst. + +**Hier nochmal der komplette Code, den du in deinem Model von diesem Tutorial haben solltest:** + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/MainModel.cs#L3-L25)] + +## Links zur Uno Documentation + +- [IRouteNotifier Documentation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-IRouteNotifier.html) diff --git a/doc/articles/de/Navigation/HowTo-Defining-UI-NavigationView-de.md b/doc/articles/de/Navigation/HowTo-Defining-UI-NavigationView-de.md new file mode 100644 index 0000000..f5148e9 --- /dev/null +++ b/doc/articles/de/Navigation/HowTo-Defining-UI-NavigationView-de.md @@ -0,0 +1,146 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de +--- + +# Tutorial: Erstellen des UI mit einer `NavigationView` in Xaml + +In diesem Teil des Tutorials, wollen wir uns anschauen, wie man eine einfache Seitennavigation mittels einer `NavigationView` erstellen kann. + +**Was zuvor geschah...** + +Wir haben uns nun zuvor im Intro angeschaut, was wir mit der `Uno.Extensions.Navigation` und der `NavigationView` alles machen können und im anschluss das Setup der Anwendung angepasst oder diese erstellt. Nun wollen wir uns anschauen wie man dann dann auch umsetzen kann! + +## Tutorial Video: Navigation mit `NavigationView` in MVUX und XAML + +In diesem Video werden wir uns zusammen anschauen, wie du ein `NavigationView`-Steuerelement in einer XAML-Markup-App einrichtest und verwendest. Wir werden die Navigation zwischen verschiedenen Seiten implementieren und dabei die MVUX-Prinzipien anwenden. Den Code kannst du dabei direkt aus dem Code hierunter kopieren und in deine Anwendung einfügen, wenn du möchtest, aber aus eigener Erfahrung heraus hilft es dir mehr, den Code selber zu schreiben und dabei zuzuschauen, wie es funktioniert. So kannst du auch besser verstehen, was du tust und warum. + +![Navigation-in-Xaml-und-Mvux-mit-Navigation-View](https://youtube.com/embed/knt2oOjHH30) + +## Implementierung der NavigationView + +Wir werden zuerst einmal eine einfache `NavigationView` hierfür auf der `MainPage` der Anwendung hinzufügen. Dort sollte bisher bereits ein `Grid` mit einem `StackPanel` sein, wenn du eine Anwendung vom Template erstellt hast. + +Von diesem Ausgangspunkt, entferne zunächst das `StackPanel` inklusive der darin enthaltenen Steuerelemente und füge anstelle dessen diese einfache Definition der `NavigationView` ein: + +```xml + + + + + + + + + + + + + + + +``` + +> [!NOTE] +> Wenn deine Anwendung nicht das Uno Toolkit Feature enthält, kannst du das `utu:SafeArea.Insets="VisibleBounds">` in der ersten Zeile einfach entfernen bzw. weg lassen. + +## Namespaces und erweiterte Eigenschaften + +Nun wollen wir die von der Extension ermöglichten Eigenschaften, sogenannte `Attached Properties` hinzufügen. + +1. Hierzu füge zuerst im oberen Bereich deiner Seite `xmlns:uen="using:Uno.Extensions.Navigation.UI` der Sammlung hinzu. +1. Anschließend füge sowohl in den Eigenschaften des `Grid`, als auch in denen der `NavigationView` selber, aber auch in dem `Grid` im `Content`-Bereich der `NavigationView`, die Eigenschaft `uen:Region.Attached="True"` hinzu. Hiermit teilen wir dem Navigator mit, dass innerhalb dieses Steuerelements eine Navigationsroute bzw. verschachtelte Navigationsdarstellung erwartet und verwendet werden soll. + + Das sollte dann so aussehen: + + ```diff + + + + + + + + + + + + + + + + + + + ``` + +1. Nun fügen wir mittels `uen:Region.Name="..."` ein paar Routen Bezeichner Namen ein. + + ```diff + + + + + + + + + + + + + + + ``` + +1. Zu guter Letzt benötigt das `Grid`, welches wir für die Navigation des Content der `NavigationView` verwenden wollen nun noch zwei letzte weitere und sehr wichtige Eigenschaften setzen, ohne welche es gut möglich ist, dass unser Vorhaben misslingt. + + Wir müssen: + + 1. `uen:Region.Navigator="Visibility"` anhängen + 2. die Eigenschaft `Visibility` auf sichtbar setzen + + Und das geht so: + + ```diff + + + + ``` + + **Als kurze Erklärung zu den hinzugefügten Eigenschaften dort:** + + - **Die `Visibility`-Eigenschaft:** + + Mit setzen der sorgen wir dafür, dass der Inhalt dieser Route zu Beginn erst einmal Sichtbar ist. + + - **Der Navigator Bezeichner Name:** + + Hiermit sagen wir den Funktionen, welche uns die Extension zur Verfügung stellt, dass wir die Elemente, welche hiermit gekennzeichnet werden Sichtbar und Unsichtbar machen wollen, wenn wir die zugehörige Navigationsroute aufrufen. + + *Die Namensgebung ist also keineswegs Zufall!* + + >[!NOTE] + > Der "Visibility"-Navigator ist gemäß der Dokumentation verfügbare Bezeichner für diese Eigenschaft. + +## Nächste Schritte + +Nun haben wir die `NavigationView` eingerichtet und können diese nun auch verwenden, um zwischen den Seiten zu navigieren. Im nächsten Schritt werden wir uns anschauen, wie wir die Routen definieren und die Navigation zwischen den Seiten implementieren können. + +[**Routen definieren und Navigation implementieren**](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.de) \ No newline at end of file diff --git a/doc/articles/de/Navigation/HowTo-ModelDefinition-de.md b/doc/articles/de/Navigation/HowTo-ModelDefinition-de.md new file mode 100644 index 0000000..000c9aa --- /dev/null +++ b/doc/articles/de/Navigation/HowTo-ModelDefinition-de.md @@ -0,0 +1,99 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-DefiningModelOrViewModel.de +--- + +# Anleitung: Navigation im Model oder ViewModel + +Nun wollen wir uns einmal anschauen, wie wir passend zur Uno Extensions Navigation unser Model bzw. ViewModel aufbauen müssen. + +## Voraussetzungen + +1. Erstelle hierfür zu aller erst ein Model bzw. ViewModel Element. + + [!INCLUDE [Anleitung zur Erstellung eines grundlegenden Model bzw. ViewModels](../HowTo-Adding-New-VM-Class-Record-de.md)] + +2. Füge nun noch den `INavigator` als **DependencyInjection** Konstruktor Parameter hinzu. + + [!INCLUDE [Anleitung: Nutze Konstruktor Parameter für DependencyInjection](../HowTo-Using-DI-in-ctor-de.md)] + +## Navigation im Xaml + +Grundsätzlich benötigst du tatsächlich nicht unbedingt einen Navigations-Code im ViewModel / Model, wenn du wie in der [Anleitung: Definieren des UI mit NavigationView für ExtensionsNavigation](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de) die `Attached Properties` nutzt! + +In diesem Fall wären es klassischerweise nur dann die Title Eigenschaften oder andere, die du von View zu ViewModel bindest und du wärst fertig. Und genau das ist auch ein großer Vorteil dieser Extension meiner Meinung nach. + +## Binden der View UI Steuerelemente an Eigenschaften im ViewModel bzw. Model + +Nun haben wir zuvor den `Title` der NavigationView manuell festgelegt, aber wie sieht es mit anderen Eigenschaften aus, die wir in der View binden wollen? Und du hast in der Template App vielleicht auch den `Name` gesehen, der in der `Dashboard(View)Model` definiert ist. + +Wenn du nicht vom Template startest, füge diese Eigenschaft hinzu, um sie in der View zu binden. + +```csharp +public string? Name { get; set; } +``` + +### [Mvvm](#tab/mvvm) + +```csharp +public partial class DashboardViewModel : ObservableObject +{ + private readonly INavigator _navigator; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(NavigateSecondAsyncCommand))] + private string? name; + + public DashboardViewModel(INavigator navigator) + { + _navigator = navigator; + NavigateSecondAsyncCommand = new AsyncRelayCommand(NavigateSecondAsync); + } + + public IAsyncRelayCommand NavigateSecondAsyncCommand { get; } + + [RelayCommand(CanExecute = nameof(CanExecuteNavigateSecondAsync))] + private async Task NavigateSecondAsync() + { + await _navigator.NavigateViewModelAsync(this, data: new Entity(Name!)); + } + + private bool CanExecuteNavigateSecondAsync() + { + return !string.IsNullOrWhiteSpace(Name); + } +} +``` + +### [Mvux](#tab/mvux) + +```csharp +namespace Mvux.XamlNavigationApp.Presentation; + +public partial record MainModel +{ + private INavigator _navigator; + + public DashboardModel(INavigator navigator) + { + _navigator = navigator; + Title = "Dashboard"; + } + + public string? Title { get; } + + public IState Name => State.Value(this, () => string.Empty); + + public async Task NavigateSecondAsync() + { + var name = await Name; + await _navigator.NavigateViewModelAsync(this, data: new Entity(name!)); + } + +} +``` + +Mit diesem Code ist es dir möglich, die `Name` Eigenschaft in der View zu binden und den `NavigateSecondAsyncCommand` zu verwenden, um zur `SecondViewModel` zu navigieren. + +Hierbei kannst du einen Button oder ein anderes Steuerelement in der View verwenden, um die Navigation auszulösen, aber indem du die `IsEnabled` Eigenschaft des Steuerelements an den `CanExecute` Status des Befehls bindest, kannst du die Navigation nur dann ausführen, wenn der Name nicht leer ist. + +--- diff --git a/doc/articles/de/Navigation/HowTo-RegisterRoutes-de.md b/doc/articles/de/Navigation/HowTo-RegisterRoutes-de.md new file mode 100644 index 0000000..5164b08 --- /dev/null +++ b/doc/articles/de/Navigation/HowTo-RegisterRoutes-de.md @@ -0,0 +1,80 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.de +--- + +# Anleitung: Registrieren und Verwalten von Routen + +Mit der `Uno.Extensions.Navigation` verwenden wir eine zentrale Definition der **Routen Registrierung** in der App Klasse [`App.xaml.cs`(source link)](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs) gehandhabt, was man sich vereinfacht schlichtweg wie eine Landkarte vorstellen kann. + +## Voraussetzungen + +Bevor du mit der Routen Registrierung beginnst, brauchst du noch zwei Dinge: + +1. Eine oder mehrere Seiten (`View`), die du in deiner App verwenden möchtest. + + - [Neue Seiten Elemente zu deiner Anwendung hinzufügen](xref:DevTKSS.Uno.Setup.HowTo-AddingNewPages.de) + +2. Ein oder mehrere zugehörige `ViewModel` oder `Model`, die du für die Seiten verwenden möchtest. (optional, aber empfohlen) + + - [Neue Klasse oder Record Definitionen für ein ViewModel oder Model hinzufügen](xref:DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.de) + +## RegisterRoutes Methode + +Füge die dafür benötigte Methode wie folgt in deine App Klasse unterhalb der `OnLaunched` Methode ein: + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs#L82)] + +## Definieren der `ViewMap`'s + +Hiermit teilen wir dem Navigator mit, welche Seite (`View`) mit welchem (`View`-)`Model` zusammengehört, worin wir Eigenschaften und Funktionen definieren, die die View dort aufrufen kann. Hierfür findest du den Abschnitt `views.Register` bisher in deiner Anwendung, bzw. kannst ihn noch hinzufügen, wenn deine Anwendung ge-upgraded wird. + +```csharp +{ + views.Register( + new ViewMap(ViewModel: typeof(ShellModel)), + new ViewMap(), + new DataViewMap() +``` + +Wenn zusätzliche Daten Objekte bei der Navigation dieser Route erforderlich sind, dann konvertierst du diese als `DataViewMap` beispielsweise so wie in der letzten Zeile. + +So sieht das zum Beispiel dann in der XamlNavigationApp aus, wo ich `Entity` nicht mehr benötigt habe und diese Route entsprechend zurück konvertiert habe: + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs#L83-L89)] + +## Hierarchisch aufgebaute `RoutesMap`'s + +Nun schauen wir uns an, welche Routen von welchem übergeordneten Element erreichbar sind: + +In diesem Beispiel aus einer Mvux nutzenden vom Template erstellten Anwendung, siehst du anhand des `Nested:` Parameter Namen, aber auch anhand der Struktur des Abschnitts, wie eine solche Hierarchie der Routen aussehen kann. + +```csharp + routes.Register( + new RouteMap("", View: views.FindByViewModel(), + Nested: + [ + new RouteMap("Main", View: views.FindByViewModel(), IsDefault:true), + new RouteMap("Second", View: views.FindByViewModel()) + ] + ) + ); +} +``` + +Nun wollen wir aber auf der `MainPage` vielleicht eine TabBar, NavigationBar, einen Frame innerhalb eines Grid oder auch eine NavigationView mit navigierbarer Inhalt (Content) Eigenschaft verwenden. Dieser Inhalt würde aber vielleicht keinen Sinn auf der `SecondPage` machen. In diesem Fall sollten wir also sicherstellen, dass diese Routen nur dort Verfügbar sein werden. + +**Das machen wir beispielsweise so:** + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs#L96-L101)] + +Hier siehst du, dass ich eine weitere Seite hinzugefügt habe, die `DashboardPage` und ein Model dazu erstellt habe namens `DashboardModel`. Außerdem habe ich die Route `Second` in die `RouteMap` der `Main`-Route verschachtelt. + +## Nützliche Informationen + +Bei der Benennung macht es immer Sinn, die Routen- und Seiten Element-Namen gleich zu halten. Eine `DashboardPage` würde somit klassisch `Dashboard` als Routen-Namen erhalten. + +Wenn du anstelle von **MVVM** das **MVUX** verwendest, solltest du darauf achten, das zur Seite oder `View` zugehörige **Model** nicht fälschlicherweise `DashboardViewModel` für die `DashboardPage` zu nennen, sondern `DashboardModel`, da der Mvux Source Code Generator das für dich erstellte `DashboardViewModel` genau so nennen wird und es sonst zu unerwarteten Problemen kommen kann. + +## Anwendung starten + +Nun sind wir auch schon fertig mit der Routen Registrierung und können die Anwendung starten. Wenn du nun die App startest, solltest du in der Lage sein, die `MainPage` zu sehen und von dort aus zu den anderen Seiten zu navigieren. diff --git a/doc/articles/de/Navigation/HowTo-UpgradeExistingApp-de.md b/doc/articles/de/Navigation/HowTo-UpgradeExistingApp-de.md new file mode 100644 index 0000000..7b49f0e --- /dev/null +++ b/doc/articles/de/Navigation/HowTo-UpgradeExistingApp-de.md @@ -0,0 +1,86 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.UpgradeExistingApp.de +--- + +# Hinzufügen von Uno Extensions Navigation in eine bestehende Anwendung + +Solltest du schon eine existierende Uno Anwendung haben, kannst du die Extensions Navigation natürlich hinzufügen. + +In der Projektdatei, zu erkennen an der Endung `.csproj`, brauchst du dafür neben dem `Uno.Sdk` folgende `UnoFeatures` Elemente: + +# [Mvux](#tab/mvux) + +```xml + + Hosting; + Mvux; + Navigation; + +``` + +# [Mvvm](#tab/mvvm) + +```xml + + Hosting; + Mvvm; + Navigation; + Toolkit; + +``` + +# [On Launched](#tab/mvux/on-launched) + +Füge deiner Datei `App.xaml.cs` folgenden Inhalt hinzu, wenn nicht bereits enthalten: + +```diff ++ protected async override void OnLaunched(LaunchActivatedEventArgs args) ++ { ++ var builder = this.CreateBuilder(args) ++ // Fügt Unterstützung für weitere Navigations-Steuerelemente wie TabBar and NavigationView hinzu ++ .UseToolkitNavigation() ++ .Configure(host => host ++ // Füge den Callback zur Methode RegisterRoutes hinzu, diese wird die Routen in der Anwendung definieren. ++ .UseNavigation(ReactiveViewModelMappings.ViewModelMappings, RegisterRoutes) ++ ); + MainWindow = builder.Window; + +#if DEBUG + MainWindow.UseStudio(); +#endif + MainWindow.SetWindowIcon(); + ++ Host = await builder.NavigateAsync(); + } +``` + +# [On Launched](#tab/mvvm/on-launched) + +Füge deiner Datei `App.xaml.cs` folgenden Inhalt hinzu, wenn nicht bereits enthalten: + +```diff ++ protected async override void OnLaunched(LaunchActivatedEventArgs args) ++ { ++ var builder = this.CreateBuilder(args) ++ // Fügt Unterstützung für weitere Navigations-Steuerelemente wie TabBar and NavigationView hinzu ++ .UseToolkitNavigation() ++ .Configure(host => host ++ // Füge den Callback zur Methode RegisterRoutes hinzu, diese wird die Routen in der Anwendung definieren. ++ .UseNavigation(RegisterRoutes) ++ ); + MainWindow = builder.Window; + +#if DEBUG + MainWindow.UseStudio(); +#endif + MainWindow.SetWindowIcon(); + ++ Host = await builder.NavigateAsync(); + } +``` + +--- + +## Nächste Schritte + +- [Registriere die Routen in deiner App](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.de) diff --git a/doc/articles/de/Navigation/Navigation-Options-de.md b/doc/articles/de/Navigation/Navigation-Options-de.md new file mode 100644 index 0000000..279d532 --- /dev/null +++ b/doc/articles/de/Navigation/Navigation-Options-de.md @@ -0,0 +1,14 @@ +--- +uid: DevTKSS.Uno.Navigation.Navigation-Options.de +--- + +# Möglichkeiten für die Navigation in einer Uno App + +Jede Anwendung, die mehr als eine einzige Seite umfasst profitiert von dem vorhanden sein einer durchdachten **Navigation**. + +In Uno Apps können wir hierfür zwei Arten der Navigation verwenden: + +- `Frame`-Navigation (wie in WinUI Apps) +- `Regions`, also unter Verwendung der `Uno.Extensions.Navigation` + +Um einen guten Überblick zu bekommen über die Möglichkeiten, die dir die `Uno.Extensions.Navigation` bietet, kannst du dir das [Tutorial: Navigation mit Uno Extensions](xref:DevTKSS.Uno.ExtensionsNavigation.Overview.de) zum beispiel anschauen. Dort werden wir uns anschauen, wie man mit der `Uno.Extensions.Navigation` und der `NavigationView` in einer Xaml-basierten Uno Anwendung umgeht bzw. diese implementiert. diff --git a/doc/articles/de/Navigation/toc.yml b/doc/articles/de/Navigation/toc.yml new file mode 100644 index 0000000..628fd7d --- /dev/null +++ b/doc/articles/de/Navigation/toc.yml @@ -0,0 +1,27 @@ +items: + - name: Möglichkeiten für die Navigation in einer Uno App + uid: DevTKSS.Uno.Navigation.Navigation-Options.de + href: Navigation-Options-de.md + - name: Navigation mit Uno Extensions + uid: DevTKSS.Uno.ExtensionsNavigation.Overview.de + href: Extensions-Navigation-de.md + - name: Erstellen oder upgraden + items: + - name: "App erstellen (Wizard/CLI)" + uid: DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.de + href: ../HowTo-CreateApp-de.md + - name: "Eine bestehende App upgraden" + uid: DevTKSS.Uno.ExtensionsNavigation.UpgradeExistingApp.de + href: HowTo-UpgradeExistingApp-de.md + - name: "UI mit NavigationView definieren" + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.de + href: HowTo-Defining-UI-NavigationView-de.md + - name: "Routen registrieren" + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.de + href: HowTo-RegisterRoutes-de.md + - name: Definieren einer Navigation im Model oder ViewModel + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-DefiningModelOrViewModel.de + href: HowTo-ModelDefinition-de.md + - name: Reagieren auf Routen Änderungen + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-ChangeRoutes.de + href: HowTo-ChangeRoutes-de.md \ No newline at end of file diff --git a/doc/articles/de/Uno-resources-lookup-de.md b/doc/articles/de/Uno-resources-lookup-de.md new file mode 100644 index 0000000..050b556 --- /dev/null +++ b/doc/articles/de/Uno-resources-lookup-de.md @@ -0,0 +1,128 @@ +--- +uid: DevTKSS.Uno.ResourcesLookup.de +--- + +# Link-Sammlung für den Einstieg in die Uno App Entwicklung + +Willkommen in der Uno Platform Entwickler-Community! + +Hier erfährst du, wie und du mit der Entwicklung in deiner Uno App starten kannst: https://aka.platform.uno/get-started + +Verschaffe dir einen Überblick über all die großartigen Funktionen, die Uno bietet: https://platform.uno/docs/articles/intro.html + +Weitere Informationen zur Verwendung des Uno.Sdk oder zum Aktualisieren der Uno Platform-Pakete in deiner Lösung findest du hier: https://aka.platform.uno/using-uno-sdk + +## Inhaltsverzeichnis dieser Seite + +- [Link-Sammlung zur Uno Platform-Dokumentation](#link-sammlung-zur-uno-platform-dokumentation) + - [Allgemeine Links](#allgemeine-links) + - [WinUI als Base](#winui-als-basis) +- [Entdecke Uno Studio Optionen für deine Anwendung](#entdecke-die-möglichkeiten-mit-uno-studio-deine-app-entwicklung) + - [Hot Design](#hot-design) + - [Hot Reload](#hot-reload) + - [Design zu Code](#design-zu-code) +- [Mehr über `Uno.Extensions` erfahren](#mehr-über-unoextensions-erfahren) +- [Uno.Resizetizer](#unoresizetizer) +- [Hilfe erhalten](#hilfe-erhalten) +- [Zur Uno Platform beitragen](#zur-uno-platform-beitragen) + +## Link-Sammlung zur Uno Platform-Dokumentation + +### Allgemeine Links + +- [Best Practices für die Entwicklung mit der Uno Platform](https://platform.uno/docs/articles/best-practices-uno.html) +- [Entwicklung mit der Uno Platform](https://platform.uno/docs/articles/using-uno-ui.html) + - [Uno Platform Features](https://platform.uno/docs/articles/supported-features.html) + - [Liste der in Uno implementierten Steuerelemente](https://platform.uno/docs/articles/implemented-views.html) + - [Spezielle Hinweise zur WinAppSDK](https://platform.uno/docs/articles/features/winapp-sdk-specifics.html) +- [Aktualisieren von Uno Platform NuGet-Paketen](https://platform.uno/docs/articles/upgrading-nuget-packages.html) – hier findest du auch die aktuelle stabile Version von **Uno.Sdk**! +- [Tutorials](https://platform.uno/docs/articles/samples-tutorials-overview.html) +- [Beispiele](https://platform.uno/docs/articles/external/uno.samples/doc/samples.html) +- [Weitere Ressourcen](https://platform.uno/docs/articles/get-started-next-steps.html) +- [Veröffentlichen einer Uno-App](https://platform.uno/docs/articles/uno-publishing-overview.html) + +### WinUI als Basis + +Falls du nicht nur neu bei der Uno Platform bist, sondern auch noch nie mit WinUI-basiertem XAML gearbeitet hast (falls du mit C#-Markup entwickelst, beachte, dass die Properties trotzdem dieselbe Struktur wie bei XAML-Markup haben), findest du hier eine Sammlung an Links für deinen Einstieg: + +- [Links zur WinUI-Dokumentation](https://platform.uno/docs/articles/winui-doc-links.html) +- [WinUI 3 und Uno Platform](https://platform.uno/docs/articles/uwp-vs-winui3.html) + +## Entdecke die Möglichkeiten mit Uno Studio deine App-Entwicklung + +**Uno Platform Studio** revolutioniert die Art und Weise, wie Entwickler ihre Anwendungen entwerfen, bauen und iterieren. + +Es beinhaltet drei Hauptwerkzeuge, die gezielt entwickelt wurden, um deinen Workflow zu vereinfachen: + +### [Hot Design®](https://platform.uno/docs/articles/studio/Hot%20Design/hot-design-overview.html) + +Der erste visuelle Designer zur Laufzeit für plattformübergreifende .NET-Anwendungen. Hot Design verwandelt deine laufende App in einen Designer – aus jeder IDE, auf jedem Betriebssystem – und ermöglicht es dir, mühelos hochwertige Benutzeroberflächen zu erstellen. + +[➜ Mehr über Hot Design® erfahren](https://platform.uno/docs/articles/studio/Hot%20Design/hot-design-getstarted-guide.html) + +### [Hot Reload](https://platform.uno/docs/articles/studio/Hot%20Reload/hot-reload-overview.html) + +Aktualisiere zuverlässig jeden Code in deiner App und erhalte sofortige Rückmeldung, dass deine Änderungen übernommen wurden – mit einem neuen Hot Reload-Indikator zur Überwachung deiner Änderungen während der Entwicklung. + +[➜ Einstieg in Hot Reload](https://platform.uno/docs/articles/studio/Hot%20Reload/get-started-with-hot-reload.html) + +### [Design-zu-Code](https://platform.uno/docs/articles/external/figma-docs/download.html) + +Erzeuge mit einem Klick direkt aus deinen Figma-Designs einsatzbereites, gut strukturiertes XAML oder C#-Markup – und erspare dir die manuelle Übergabe von Designs. + +[➜ Mehr über Design-to-Code erfahren](https://platform.uno/docs/articles/external/figma-docs/get-started.html) + +## Mehr über `Uno.Extensions` erfahren + +- [Authentifizierung](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Authentication/AuthenticationOverview.html) +- [Konfiguration](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Configuration/ConfigurationOverview.html) +- [Hosting](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Hosting/HostingOverview.html) +- [HTTP](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Http/HttpOverview.html) +- [Lokalisierung](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Localization/LocalizationOverview.html) +- [Logging](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Logging/LoggingOverview.html) +- [Navigation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/NavigationOverview.html) +- [Serialisierung](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Serialization/SerializationOverview.html) +- [Speicherung](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Storage/StorageOverview.html) +- [Validierung](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Validation/ValidationOverview.html) +- [C# Markup](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Markup/Overview.html) +- [.NET MAUI-Einbettung](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Maui/MauiOverview.html) +- [Theme Service](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/ThemeService/HowTo-UseThemeService.html) + +## Uno.Resizetizer + +> [!NOTE] +> Wenn du mit Visual Studio arbeitest, kannst du `*.png`- und `*.svg`-Dateien in deine App einfügen, ohne sie mit dem Uno.Resizetizer konvertieren zu müssen – dieser ist in jeder Uno-App bereits enthalten. + +So funktioniert’s (Kurzfassung): + +1. Füge die Bilddatei im **Projektmappen Explorer** in den Ordner **Assets** ein – z. B. unter **Images**, **Icons** oder **Splash** (erstelle diese, falls sie nicht existieren). +2. Öffne das **Eigenschaften Fenster** der Datei und stelle sicher, dass die **Build Action** auf **`UnoImage`** gesetzt ist. + +> [!NOTE] +> Du kannst dies auch alternativ direkt in der `*.csproj`-Datei deiner Uno-App konfigurieren: +> +> ```xml +> +> +> +> ``` + +Mehr Infos findest du unter: [Get Started with Uno.Resizetizer](https://platform.uno/docs/articles/external/uno.resizetizer/doc/using-uno-resizetizer.html). + +## Hilfe erhalten + +Falls du beim Entwickeln deiner Uno-App auf Probleme stößt, kannst du dich über Discord oder GitHub mit dem Core-Team und der Community in Verbindung setzen. + +Je nach Schwierigkeit deines Problems wirst du möglicherweise gebeten, ein Reproduktionsprojekt (auch „Repro“ genannt) bereitzustellen, damit andere dein Problem nachvollziehen und dir gezielt helfen können. + +Wie du so ein Repro-Projekt erstellst, erfährst du hier: https://platform.uno/docs/articles/uno-howto-create-a-repro.html + +## Zur Uno Platform beitragen + +Jede*r ist eingeladen, zur Uno Platform beizutragen. Hier findest du hilfreiche Informationen für neue und wiederkehrende Mitwirkende. + +Zu Beginn lies am besten den [Verhaltenskodex](https://github.com/unoplatform/uno/blob/master/CODE_OF_CONDUCT.md), welcher das Bekenntnis zu einer offenen, freundlichen und belästigungsfreien Uno Platform Community festhält. + +Wenn du nicht weißt, wo du anfangen sollst: [Lies mehr über Möglichkeiten zur Mitwirkung](https://github.com/unoplatform/uno/blob/master/doc/articles/contributing/ways-to-contribute.md) oder sieh dir die Liste der [Einsteigerfreundlichen offenen Probleme](https://github.com/unoplatform/Uno/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). + +Weitere Infos findest du in der offiziellen Dokumentation: https://platform.uno/docs/articles/uno-development/contributing-intro.html diff --git a/doc/articles/de/toc.yml b/doc/articles/de/toc.yml new file mode 100644 index 0000000..c159e9c --- /dev/null +++ b/doc/articles/de/toc.yml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/toc.schema.json +- name: Willkommen + uid: DevTKSS.Uno.SampleApps.Intro.de + href: Introduction-de.md +- name: Link-Sammlung zu Uno Platform + uid: DevTKSS.Uno.ResourcesLookup.de + href: Uno-resources-lookup-de.md +- name: Mvux Gallery Übersicht + uid: DevTKSS.Uno.SampleApps.MvuxGallery.Overview.de + href: MvuxGallery-Overview-de.md +- name: "Erste Schritte & Basics" + items: + - name: Einrichten der Entwicklungsumgebung + uid: DevTKSS.Uno.Setup.DevelopmentEnvironment.de + href: HowTo-Setup-DevelopmentEnvironment-de.md + - name: "Erstellen einer neuen Uno App" + uid: DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.de + href: HowTo-CreateApp-de.md + - name: "Hinzufügen von Seiten" + uid: DevTKSS.Uno.Setup.HowTo-AddingNewPages.de + href: HowTo-Adding-New-Pages-de.md + - name: "Neue Klassen oder Record ViewModel's definieren" + uid: DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.de + href: HowTo-Adding-New-VM-Class-Record-de.md +- name: "Navigation in Uno Apps" + href: Navigation/toc.yml diff --git a/doc/articles/en/HowTo-Adding-New-Pages-en.md b/doc/articles/en/HowTo-Adding-New-Pages-en.md new file mode 100644 index 0000000..cfd8d12 --- /dev/null +++ b/doc/articles/en/HowTo-Adding-New-Pages-en.md @@ -0,0 +1,45 @@ +--- +uid: DevTKSS.Uno.Setup.HowTo-AddingNewPages.en +--- + +## How To: Add a Page + +In this guide, we will add a new page with sample content to our Uno app together. + +1. **Add a new item:** + 1. Right-click on the **Presentation** folder in the Solution Explorer on the right + 2. Select **Add** + 3. Then click on **New Item** + + ![Adding-new-Item-to-sln](../.attachments/Adding-new-Item-to-sln-en.png) + +2. **Create a Page element:** + 1. Select the **`Page (Uno Platform)`** element at the top of the list and give it a name with the Page suffix. For example: `SamplePage.xaml`. This suffix is mandatory for Uno applications. + 2. Now click **Add**. + + ![Adding-new-Item-Page](../.attachments/Adding-new-Item-page-de.png) + +### Adding Sample Content + +To see that we are actually on the desired page, we now add simple sample content: + +```xml + + + + + +``` + +This way, the text `Hello World` will be displayed on this page. Of course, you are free to use any content you like. + +--- diff --git a/doc/articles/en/HowTo-Adding-New-VM-Class-Record-en.md b/doc/articles/en/HowTo-Adding-New-VM-Class-Record-en.md new file mode 100644 index 0000000..be6b4ef --- /dev/null +++ b/doc/articles/en/HowTo-Adding-New-VM-Class-Record-en.md @@ -0,0 +1,49 @@ +--- +uid: DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.en +--- + +## How To: Create a ViewModel or Model from Classes + +In this guide, we will look at how to create a new class element in Visual Studio and then create either a ViewModel or a Model for use in an Uno Platform application with **MVUX**. + +For the following steps, let's assume the page that the element to be created belongs to is called **SamplePage.xaml** + +1. **Add a new item (for use as Model or ViewModel):** + 1. Right-click on the **Presentation** folder in the Solution Explorer on the right + 2. Select **Add** + 3. Then click on **New Item** + + ![Adding-new-Item-to-sln](../.attachments/Adding-new-Item-to-sln-en.png) + +2. **Create a Class element:** + 1. Select the **`Class`** element in the list and name it according to the following scheme: + + **Your application uses:** + - **Mvvm:** `SampleViewModel.cs` + - **Mvux:** `SampleModel.cs` + +3. Now click **Add**. + + ![Adding-new-Item-Class](../.attachments/Adding-new-Item-Class.png) + +### [Create a Model **Mvux**](#tab/create-mvux-model) + +To create a Model suitable for Mvux: + +1. Insert `partial` before the current `class`. +2. Replace `class` with `record` +3. With the snippet shortcut `ctor` you can also automatically insert a (secondary) constructor. + +![Renaming-Class-to-Mvux-Model](../.attachments/renaming-class-to-record-mvux.png) + +### [Create a ViewModel](#tab/create-mvvm-viewmodel) + +To create a ViewModel suitable for Mvvm: + +1. Insert `partial` before `class`. +2. Add `: ObservableObject` after your ViewModel name +3. With the snippet shortcut `ctor` you can also automatically insert a (secondary) constructor. + +![Converting-Class-to-ViewModel-Mvvm](../.attachments/converting-class-to-vm-mvvm.png) + +--- diff --git a/doc/articles/en/HowTo-CreateApp-en.md b/doc/articles/en/HowTo-CreateApp-en.md new file mode 100644 index 0000000..07f4f01 --- /dev/null +++ b/doc/articles/en/HowTo-CreateApp-en.md @@ -0,0 +1,88 @@ +--- +uid: DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.en +--- + +## How To: Create a New Uno Application + +In this guide, you will learn how to create an Uno Platform application using the Wizard or dotnet CLI to follow, for example, the [Xaml Navigation App Tutorial](./Navigation/Extensions-Navigation-en.md). + +To follow along, you should have previously completed the [Development Environment Setup Guide](xref:DevTKSS.Uno.Setup.DevelopmentEnvironment.en). + +## Video Tutorial on Configuration + +> [!NOTE] +> This video is currently only available in German, but transcriptions have been added to the video description, which should be usable through YouTube's auto-translate feature. You can also enable auto-translated subtitles in YouTube to follow along in your preferred language. + +![How To: Konfigurieren unserer Uno App Visual Studio Wizard](https://youtu.be/UGKidrvdKpQ) + +## Create and Configure an Uno App via Template + +In the following, you will learn how to configure an Uno app by selecting the desired options. You can either use the Visual Studio Wizard or the dotnet CLI tool. For the latter, it is recommended to visit the [Web Wizard](https://new.platform.uno/) to make configuration easier and get the appropriate `dotnet new` command! + +### [Visual Studio 2022](#tab/vs-wizard) + +#### Select Template + +1. Open Visual Studio 2022 and select **"Create a new project"** in the start window. +2. Search for the template **"Uno App"** and select it. Click **"Next"**. + + ![select-template](../.attachments/select-template-de.png) + +3. Give your project a name and enable the option **"Place solution and project in the same directory"**. Then click **"Create"**. + + ![place-project-in-sln](../.attachments/place-project-in-sln-de.png) + +#### The Template Wizard + +**Select the following options in the Visual Studio Wizard to configure your app:** *(using the Xaml Navigation App Tutorial as an example)* + +1. Use the preset **`recommended`** +2. Target Framework: **`net9.0`** + +3. As `Platform` select at least **Desktop** or **Skia Desktop**. + +4. Markup: **`Xaml`** + + ![select-Xaml](../.attachments/select-xaml.png) + +5. Presentation: **`MVUX`** + + ![select-MVUX](../.attachments/select-presentation-mvux.png) + +6. Select the **Material Design Theme** under **Themes**. + + ![select-theme-optional-themeservice](../.attachments/select-theme-optional-themeservice.png) + + > [!TIP] + > By default, **ThemeService** is also selected, which would allow you to switch between light and dark UI later. It is not directly required here, but you can leave it in if you like. + +7. Extensions: **`Regions`**, **`DependencyInjection`** + + ![select-extensions](../.attachments/select-regions-di-optional-localization.png) + +8. *(Optional)* select the **Uno Toolkit**. + + ![select-toolkit-optional-vscode-debugging](../.attachments/select-toolkit-optional-vscode-debugging.png) + + > [!TIP] + > If you want to keep the option open to develop in Visual Studio Code later, you should also select `Visual Studio Code Debugging` here. + +9. Finally, click **`Create`** to generate the app. + +### [The dotnet CLI Tool](#tab/dotnet-cli) + +1. Optionally open the [Uno Platform Web Wizard](https://new.platform.uno/) in your browser to make configuration easier and get the appropriate `dotnet new` command. Alternatively, you can always view all possible options via `dotnet new unoapp --help` in the terminal! +2. Open a terminal and navigate to the desired directory. +3. With the following command, you get the minimum configuration to create a new app for the [**Xaml Navigation App Tutorial**](./Navigation/Extensions-Navigation-en.md): + + ```bash + dotnet new unoapp -o XamlNavigationApp -preset "recommended" -platforms "desktop" -config False -http "none" -loc False -dsp False -theme-service False + ``` + + Alternatively, if you want to use all the options shown in the video, you can use the following command: + + ```bash + dotnet new unoapp -o XamlNavigationApp -preset "recommended" -platforms "desktop" -http "none" + ``` + +--- diff --git a/doc/articles/en/HowTo-Setup-DevelopmentEnvironment-en.md b/doc/articles/en/HowTo-Setup-DevelopmentEnvironment-en.md new file mode 100644 index 0000000..fdfa678 --- /dev/null +++ b/doc/articles/en/HowTo-Setup-DevelopmentEnvironment-en.md @@ -0,0 +1,84 @@ +--- +uid: DevTKSS.Uno.Setup.DevelopmentEnvironment.en +--- + +## How To: Set Up Your Development Environment for Uno Platform Apps + +In the following, we will look together at how to easily set up the development environment for application development with Uno Platform, or rather, how the Command Line Interface (**CLI**) tool `dotnet tool uno-check` can take care of this routine task for us. + +> [!TIP] +> Since the v6 release of Uno (SDK & Extension), this is already included in the Visual Studio Uno Platform extension from the start! + +> [!TIP] +> If you have problems running the tool, you can find the associated [Official Guide to Uno-Check from Uno Platform](https://platform.uno/docs/articles/external/uno.check/doc/using-uno-check.html) here. + +### Video Tutorial + +> [!NOTE] +> This video is currently only available in German, but transcriptions have been added to the video description, which should be usable through YouTube's auto-translate feature. You can also enable auto-translated subtitles in YouTube to follow along in your preferred language. + +![How To: Einrichten unserer Uno Platform Entwicklungsumgebung](https://youtu.be/oI6IZVOeQBI) + +> [!NOTE] +> The most up-to-date guide for getting started with Uno Platform can always be found in the official [Quick Start Guide](https://platform.uno/docs/articles/get-started.html). + +--- + +### Step-by-Step Setup Guide + +1. **Choose and install your preferred IDE** + + > [!NOTE] + > This guide uses Visual Studio 2022 Community Edition. If you work with Rider or Visual Studio Code, please refer to the previously linked Quick Start Guide for any differences! + + [Official Visual Studio Installation Page - also VS Code](https://visualstudio.microsoft.com) + + **IDE**: Integrated Development Environment + +2. **Install the Uno Platform Extension** + + Available in the [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=nventive.unoplatform) + +3. **Install `Uno.Check` via the Command Line** + + ```bash + dotnet tool install -g Uno.Check + ``` + +4. **Run `Uno.Check` to verify your environment** + + Either via the terminal you used before: + + ```bash + uno-check + ``` + + Or as mentioned earlier, since version 6 of the Visual Studio Extension from Uno Platform, we can already use `Uno.Check` automatically there in our IDE. So whenever we open our solution, it runs automatically, or we can also trigger it manually in the Extensions drop-down menu in Visual Studio > Uno Platform > `Run Uno.Check`. It then checks which target devices we have specified in our project file and verifies all the necessary installations for existence, but also whether we are working with the latest available versions. This is especially helpful when bug fixes have taken place and of course also when there was a new major release. + + ![Find the Uno Extensions Menu in Visual Studio](../.attachments/Finding-Uno-VS2022-Extension-Menu-de.png) + +### Configuration Options for Uno Check + +If you only want to develop your applications for specific `targets`, i.e. target devices, and therefore don't need all other workloads, for example for the [XamlNavigation Tutorial](./Navigation/Extensions-Navigation-en.md) + +> [!TIP] +> To get an overview of the available commands, configurations and optional associated parameters, you can type `uno-check -h` in the terminal. + +> [!NOTE] +> You can find more information about configuration options in the [Uno.Check Documentation](https://platform.uno/docs/articles/external/uno.check/doc/configuring-uno-check.html)! + +### **Problems During Setup?** + +Check out the [Troubleshooting Guide](https://platform.uno/docs/articles/external/uno.check/doc/troubleshooting-uno-check.html). + +--- + +### Next Steps + +Once your environment is set up, in addition to the tutorials here, you can also start with the [Counter Workshop](https://platform.uno/docs/articles/getting-started/counterapp/get-started-counter.html) and learn these basics: + +- The structure of an Uno app +- Handling assets (images/icons) via **`Uno.Resizetizer`** +- Using commands and bindings + +--- diff --git a/doc/articles/en/HowTo-Using-DI-in-ctor-en.md b/doc/articles/en/HowTo-Using-DI-in-ctor-en.md new file mode 100644 index 0000000..ca40687 --- /dev/null +++ b/doc/articles/en/HowTo-Using-DI-in-ctor-en.md @@ -0,0 +1,22 @@ +--- +uid: DevTKSS.Uno.Setup.Using-DI-in-ctor.en +--- +## Guide: Use Constructor Parameters for Dependency Injection + +This guide assumes you've already created a Model, ViewModel, or a service class. If not, here's a quick guide to do that: (xref:DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.en) + +To use Dependency Injection in your Model, ViewModel, or any class, simply add the required (ideally) interfaces and/or service classes as constructor parameters. The DI container will provide them at runtime. + +## [In MVUX](#tab/model-with-di-params) + +![Adding-DI-parameters-via-constructor-MVUX](../.attachments/Adding-mvux-model-constructor-DI.png) + +## [In MVVM](#tab/viewmodel-with-di-params) + +![Adding-DI-parameters-via-constructor-MVVM](../.attachments/Adding-mvvm-viewmodel-constructor-DI.png) + +## [Other classes or services](#tab/classes-with-di-params) + +![Adding-DI-parameters-via-constructor-Classes](../.attachments/Adding-service-constructor-DI.png) + +--- diff --git a/doc/articles/en/Introduction-en.md b/doc/articles/en/Introduction-en.md new file mode 100644 index 0000000..5b866f2 --- /dev/null +++ b/doc/articles/en/Introduction-en.md @@ -0,0 +1,26 @@ +--- +uid: DevTKSS.Uno.SampleApps.Intro.en +--- + +# Hello and Welcome to the Documentation and Tutorials + +This documentation provides insights into various sample applications built using the Uno Platform. These samples are designed to assist developers of all skill levels in understanding and implementing the showcased concepts effectively. + +The samples in this Repository are meant to help other Developers, independent to their pre-knowledge, get an Idea of how to use the shown things. + + + +## Current Samples List + +To give you a quick overview of this Documentation, here is a List of quick links to the included Sample Apps. For future and more detailed Information, please lookup the depending Chapter via the Table of Contents. + +- MvuxGallery + - [Docs](xref:DevTKSS.Uno.SampleApps.MvuxGallery.Overview.en) + - [source code](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/) +- Mvux.XamlNavigationApp + - [Docs](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en) + - [source code](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.XamlNavigationApp-1/) + +## Next Steps + +- [How To: Setup Development Environment for Uno Platform App Development](xref:DevTKSS.Uno.Setup.DevelopmentEnvironment.en) diff --git a/doc/articles/en/MvuxGallery-Overview-en.md b/doc/articles/en/MvuxGallery-Overview-en.md new file mode 100644 index 0000000..a80d809 --- /dev/null +++ b/doc/articles/en/MvuxGallery-Overview-en.md @@ -0,0 +1,96 @@ +--- +uid: DevTKSS.Uno.SampleApps.MvuxGallery.Overview.en +--- + +# Mvux Gallery Overview + +![MvuxGallery](../.attachments/DevTKSS%20Uno%20Mvux%20Samples%20Gallery%20App-Thumbnail.png) + +The [Mvux Gallery (source link)](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/) should give you a impression of whats possible to achieve with the Mvux and Uno.Extensions packages in your Uno Platform App. + +As it contains already a lot of Controls and Features, I decided to create some Tutorials to guide you through the process of building this App with some Sample Apps and added Tutorials. Take a look at the Table of Contents and NavigationBar in these Docs to see what is already available. + +## Sampled Controls + +Here is a list of Controls and Features you can explore in the MvuxGallery App with links to their Source code in the MvuxGallery App: + +- [Card](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/SimpleCardsPage.xaml) +- [Counter](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/CounterPage.xaml) +- [FeedView + GridView](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml) +- [FeedView + ListView](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/ListboardPage.xaml) +- [DataTemplate centralized Resource Definition](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Styles/Generic.xaml) +- [`ItemOverlayTemplate` DataTemplate](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Styles/Generic.xaml) (*Layout replicated from WinUI 3 Gallery*) +- [TabBar and TabBarItem](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml) and [Model for Binding Items to ListFeed](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/DashboardPage.xaml.cs) + +## Sampled Uno.Extensions + +- Mvux + - ListFeed + - State + + --> Almost every Model, detailed overview will follow. + +- Navigation + - via Xaml + - NavigationView + - [MainPage.xaml](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/Views/MainPage.xaml) see [DE Tutorial](xref:DevTKSS.Uno.ExtensionsNavigation.Overview.de) + - Via Model + - (planned) + +- Hosting + - [App.xaml.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/App.xaml.cs) + +- DependencyInjection + - Service Registration + - [App.xaml.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/App.xaml.cs) + - Service Definition + - [CodeSampleService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) + - [ICodeSampleService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/ICodeSampleService.cs) + - Data Model Definition + - [SampleCode.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/SampleCode.cs) + - [CodeSampleOption.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOption.cs) + - [CodeSampleOptionsConfiguration.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) + +- Serialization + - JsonSerializerContext of each DataModel + - [CodeSampleOptionsContext](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOption.cs) + - [CodeSampleOptionsConfiguration](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) + + > [!NOTE] + > Currently `ValueTuple` and `Dictionary` Definitions of IOptions loaded Settings could'nt get successfully loaded, therefore this is defined as Array for Workaround. + +- Configuration + - Data for Serialization + - [appsettings.sampledata.json](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/appsettings.sampledata.json) + - [`IOptions` in Service](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleOptionsConfiguration.cs) + +- Storage + - Via Model + - [DashboardModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) + - Via Service + - [CodeSampleService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs) + - Via [own StorageExtensions](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Extensions.Uno/StorageExtensions.cs) and [IEnumerableExtensions](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Extensions.Uno/Storage/Enumerable/EnumerableExtensions.string.cs) (*temporary imported until PR might get merged or Package gets published*) + - Via Uno.Extensions.Storage.StorageExtensions + - added as PR to Uno.Extensions [#2734](https://github.com/unoplatform/uno.extensions/pull/2734) + +- Localization + - **IStringLocalizer** + - Resources Dictionaries (*I recommend to lookup those links using Visual Studio 2022*) + - [en](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Strings/en/) + - [de](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Strings/de/) + - Binding current value in `IState` and to corresponding View + - [DashboardModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs) + - [ListboardModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs) + - [MainModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs) + - [CounterModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/CounterModel.cs) + - Requesting localized Items via FeedView + - Service Definition + - [GalleryImageService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageService.cs) + - [IGalleryImageService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/IGalleryImageService.cs) + - Data Model Definition + - [GalleryImageModel.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageModel.cs) + - **ILocalizationService** + - Requesting current culture + - [GalleryImageService.cs](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.Samples.MvuxGallery/Models/GalleryImages/GalleryImageService.cs) + - Switching culture + - (planned) diff --git a/doc/articles/en/Navigation/Extensions-Navigation-en.md b/doc/articles/en/Navigation/Extensions-Navigation-en.md new file mode 100644 index 0000000..d75cb6a --- /dev/null +++ b/doc/articles/en/Navigation/Extensions-Navigation-en.md @@ -0,0 +1,60 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.Overview.en +--- + +# How To: Navigation with Uno Extensions + +![Mvux XamlNavigationApp](../../.attachments/DevTKSS.Uno.XamlNavigationApp.png) + +## Content of this Tutorial + +- A `NavigationView` control for navigation. +- Routes defined in the `App.xaml` file. +- A `MainPage.xaml` that serves as the entry point for navigation. +- `DashboardPage` and `SecondPage` as example pages for navigation. +- Each page binds to an `IState` property in the associated Model to demonstrate state management according to MVUX. + +Since this sample app was created as part of a community tutorial video series on YouTube, you can follow the videos and understand the app's structure step by step. + +> [!NOTE] +> The tutorial videos are currently only available in German, but transcriptions have been added to the video descriptions, which should be usable through YouTube's auto-translate feature. You can also enable auto-translated subtitles in YouTube to follow along in your preferred language. + +- [Go to the Playlist on YouTube](https://youtube.com/playlist?list=PLEL6kb4Bivm_g81iKBl-f0eYPNr5h2dFX&si=qHkpAUMSW9s8GZCO) + +## Showcase of Possibilities + +Let's first take a look at what you can create in a Xaml-based Uno application, using the MvuxGallery as an example. + +![MvuxGallery Showcase](https://youtu.be/vVvnK02r2ug) + +--- + +## Prerequisites + +This tutorial series builds on the assumption that your development environment is already fully set up and the command `uno-check --tfm net9.0-desktop` executed in your terminal gives you a green light. Here you can also check these again: + +- [Tutorial: Setting up the Development Environment](xref:DevTKSS.Uno.Setup.DevelopmentEnvironment.en) + +## Next Steps + +In the next steps, you will find guides with which you can learn how to implement navigation in an Uno Platform application using the Uno feature `Navigation`, i.e. the `Uno.Extensions.Navigation` NuGet. For this, you can simply use the footer navigation to go through the individual steps. + +**I start with...** + +[**A new Uno Platform App**](xref:DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.en) | [**An existing Uno Platform App**](xref:DevTKSS.Uno.ExtensionsNavigation.UpgradeExistingApp.en) + +Once you have completed this step, we will continue with the implementation of navigation using the `NavigationView` control. + +[**Implementation of Navigation via NavigationView**](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en) + +--- + +- [Here you can find the source code of the sample application XamlNavigationApp used](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.XamlNavigationApp-1) + +### Uno Documentation Links + +- [How-To: Navigate in Xaml](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-NavigateInXAML.html) +- [How-To: Define Routes](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-DefineRoutes.html) +- [How-To: Regions](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/HowTo-Regions.html) +- [How-To: Use NavigationView to Switch Views](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-UseNavigationView.html) +- [How-To: IRouteNotifier](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-IRouteNotifier.html) diff --git a/doc/articles/en/Navigation/HowTo-ChangeRoutes-en.md b/doc/articles/en/Navigation/HowTo-ChangeRoutes-en.md new file mode 100644 index 0000000..0373362 --- /dev/null +++ b/doc/articles/en/Navigation/HowTo-ChangeRoutes-en.md @@ -0,0 +1,148 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-ChangeRoutes.en +--- + +# How-To: React to Route Changes + +If we now have routes registered in our application, we may also want to react to changes in the route, for example to execute certain actions or load data. + +For this, we can use the `IRouteNotifier` to inform us about changes to the current route. It contains the `RouteChanged` event, which is triggered when the route changes. In the following example, I will show you how to implement this in your application. + +## Prerequisites + +Before you start with the implementation, you need the Uno feature "Navigation" in your application, i.e. the `Uno.Extensions.Navigation` library, but also have one or more [routes registered](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.en) and have created a ViewModel or Model class with an associated page, i.e. View, and be able to navigate there. For simplicity, I will assume that you have already successfully completed the following three tutorials: + +- [Tutorial: Creating the UI with a `NavigationView` in Xaml](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en) +- [Tutorial: Registering Routes in the App](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.en) +- [Tutorial: Navigation in the Model or ViewModel](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-DefiningModelOrViewModel.en) + +## Tutorial Video: Reacting to Route Changes + +In this video, we will look at how you can react to route changes in your application by using the `IRouteNotifier`. We will see how to subscribe to the `RouteChanged` event and respond to it. You can copy the code directly from the code below and paste it into your application if you want, but from my own experience, it helps you more to write the code yourself and watch how it works. This way you can also better understand what you are doing and why. + +> [!NOTE] +> This video is currently only available in German, but transcriptions have been added to the video description, which should be usable through YouTube's auto-translate feature. You can also enable auto-translated subtitles in YouTube to follow along in your preferred language. + +![Responding-to-Route-Changes-with-IRouteNotifier](https://www.youtube.com/embed/RZ3RirA7jhk) + +## Requesting IRouteNotifier in the Model Constructor + +To use the `IRouteNotifier` in your Model or ViewModel, you need to request it as a dependency in the constructor. Here is an example of how you can do this in a ViewModel: + +```csharp +public partial record MainModel +{ + private readonly IRouteNotifier _routeNotifier; + + public MainModel(IRouteNotifier routeNotifier) + { + _routeNotifier = routeNotifier; + _routeNotifier.RouteChanged += OnRouteChanged; + } + + private void OnRouteChanged(object sender, RouteChangedEventArgs e) + { + // Here you can later react to the route change + } +} +``` + +> [!IMPORTANT] +> In my experience, the most reliable approach is to extract the event into a separate method, rather than registering it as a lambda expression in the constructor. Although the same thing should happen, I often had the problem that the method was not called when I wrote it as a lambda expression. + +## Linking the Route Name with an `IState` in the Model + +To store and access the current route name in your Model or ViewModel, you can use an `IState`. Here is an example of how you can implement this: + +```csharp +public IState Title => State.Value(() => "Dashboard"); +``` + +Now the current content is hardcoded, of course. But what if we change our mind in the meantime and rename the page? And do we even want the title, in this case our current route name, to depend on what our Model is called? Let's assume that this is not the case. + +1. So, if we want to use the current route name as the initial value without hardcoding the name, we first need an `INavigator`, if we haven't requested it before: + + ```diff + public partial record MainModel + { + private readonly IRouteNotifier _routeNotifier; + + private readonly INavigator _navigator; + + public MainModel( + IRouteNotifier routeNotifier, + + INavigator navigator) + { + _routeNotifier = routeNotifier; + _routeNotifier.RouteChanged += Main_OnRouteChanged; + + _navigator = navigator; + } + } + ``` + +2. And then we can directly query our current route on which we are located: + + ```csharp + public IState Title => State.Value(this, () => _navigator.Route?.ToString() ?? string.Empty); + ``` + + **What happens here?** + What we have effectively changed now is that we now: + 1. Query the `Route` property from our Navigator, which returns the current `Route` object or (according to the compiler) possibly also `null`. + 2. The `Route` type has an override of the `ToString()` method, which returns the route name as a `string` when queried. + 3. If this value itself or as a result of a `null` value of the `Route` property should be `null`, we return an empty string instead using the null-coalescing operator `??`. + +And so we already have our current route name readily stored in our Model in the `Title`. + +But of course, this doesn't help our user in the Model itself, so we still have to display it somehow in the UI. Do you remember that I showed you in the [Tutorial: Creating the UI with a `NavigationView` in Xaml](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en) how to bind the header of the `NavigationView` to a property in the Model? Coincidentally, this property was called exactly `Title`. Perfect! + +If you haven't done this yet, it's very easy to do it afterwards: + +```diff + + + + + + + + + +``` + +## Reacting to Route Changes + +Now we only need the actual reaction to the route change. We do this in the `OnRouteChanged` method, which we registered in the constructor earlier. Here is an example of how you can implement this: + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/MainModel.cs#L19-L22)] + +**What happens here?** + +1. An `IState` has the `SetAsync` method, with which we can change the value of the state. This is asynchronous, so we use the `await` keyword before it. +2. In the RouteChangedEventArgs `e` we get the `Navigator`, which, as before when [linking the route name](#linking-the-route-name-with-an-istatestring-in-the-model), returns the current route name as a `string` in the overload of the `Route.ToString()` method. +3. We then pass this directly to the `SetAsync` method and let Mvux handle the update of the state and thus also the UI for us. + +> [!TIP] +> Did you notice that we had to use `async void` here for the EventHandler `OnRouteChanged`? This is because EventHandlers must always return `void`. In such cases, it is common to use `async void` to perform asynchronous operations. However, you should only use `async void` in such cases with EventHandlers and otherwise always prefer `async Task` or `ValueTask` for better error handling and control over asynchronous operations. Without the `async` keyword, we couldn't use `await`, which is absolutely necessary here to call the asynchronous method `SetAsync` without getting a message from the compiler that we should use `await`. + +## Starting the Application + +Now we are done creating our code and can simply start the application. + +If you now click on another menu item in the NavigationView and have correctly registered the routes beforehand, you should see that the text in the header of the NavigationView changes accordingly and displays the current route name. + +Congratulations! You have successfully learned how to respond to route changes in your application by using the `IRouteNotifier` and storing the current route name in your Model. + +**Here is the complete code you should have in your Model from this tutorial:** + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/MainModel.cs#L3-L25)] + +## Links to Uno Documentation + +- [IRouteNotifier Documentation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/Advanced/HowTo-IRouteNotifier.html) diff --git a/doc/articles/en/Navigation/HowTo-Defining-UI-NavigationView-en.md b/doc/articles/en/Navigation/HowTo-Defining-UI-NavigationView-en.md new file mode 100644 index 0000000..dc936b6 --- /dev/null +++ b/doc/articles/en/Navigation/HowTo-Defining-UI-NavigationView-en.md @@ -0,0 +1,149 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en +--- + +# How To: Create the UI with a `NavigationView` in XAML + +In this part of the tutorial, we will look at how to create simple page navigation using a `NavigationView`. + +**Previously in this tutorial...** + +We have previously looked at what we can do with `Uno.Extensions.Navigation` and the `NavigationView` in the intro, and then adjusted the setup of the application or created it. Now we want to see how to actually implement it! + +## Tutorial Video: Navigation with `NavigationView` in MVUX and XAML + +In this video, we will look together at how to set up and use a `NavigationView` control in a XAML Markup App. We will implement navigation between different pages while applying MVUX principles. You can copy the code directly from the code below and paste it into your application if you want, but from personal experience, it helps you more to write the code yourself and watch how it works. This way you can also better understand what you are doing and why. + +> [!NOTE] +> This video is currently only available in German, but transcriptions have been added to the video description, which should be usable through YouTube's auto-translate feature. You can also enable auto-translated subtitles in YouTube to follow along in your preferred language. + +![Navigation-in-Xaml-und-Mvux-mit-Navigation-View](https://youtube.com/embed/knt2oOjHH30) + +## Implementing the NavigationView + +We will first add a simple `NavigationView` to the `MainPage` of the application. There should already be a `Grid` with a `StackPanel` if you created an application from the template. + +From this starting point, first remove the `StackPanel` including the controls it contains and add this simple definition of the `NavigationView` instead: + +```xml + + + + + + + + + + + + + + + +``` + +> [!NOTE] +> If your application does not include the Uno Toolkit feature, you can simply remove or omit `utu:SafeArea.Insets="VisibleBounds">` in the first line. + +## Namespaces and Extended Properties + +Now we want to add the properties enabled by the extension, so-called `Attached Properties`. + +1. To do this, first add `xmlns:uen="using:Uno.Extensions.Navigation.UI` to the collection at the top of your page. +2. Then add the property `uen:Region.Attached="True"` to the properties of the `Grid`, as well as to those of the `NavigationView` itself, but also in the `Grid` in the `Content` area of the `NavigationView`. With this, we tell the navigator that a navigation route or nested navigation display is expected and should be used within this control. + + This should then look like this: + + ```diff + + + + + + + + + + + + + + + + + + + ``` + +3. Now we add a few route identifier names using `uen:Region.Name="..."`. + + ```diff + + + + + + + + + + + + + + + ``` + +4. Finally, the `Grid` that we want to use for the navigation of the `NavigationView` content now needs two more very important properties set, without which it is quite possible that our plan will fail. + + We need to: + + 1. Append `uen:Region.Navigator="Visibility"` + 2. Set the `Visibility` property to visible + + And this is how: + + ```diff + + + + ``` + + **As a brief explanation of the properties added there:** + + - **The `Visibility` property:** + + By setting this, we ensure that the content of this route is initially visible. + + - **The Navigator identifier name:** + + With this, we tell the functions provided by the extension that we want to make the elements marked with this visible and invisible when we call the associated navigation route. + + *The naming is by no means a coincidence!* + + >[!NOTE] + > The "Visibility" navigator is the available identifier for this property according to the documentation. + +## Next Steps + +Now we have set up the `NavigationView` and can use it to navigate between pages. In the next step, we will look at how we can define routes and implement navigation between pages. + +[**Define Routes and Implement Navigation**](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.en) diff --git a/doc/articles/en/Navigation/HowTo-ModelDefinition-en.md b/doc/articles/en/Navigation/HowTo-ModelDefinition-en.md new file mode 100644 index 0000000..7615635 --- /dev/null +++ b/doc/articles/en/Navigation/HowTo-ModelDefinition-en.md @@ -0,0 +1,99 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-DefiningModelOrViewModel.en +--- + +# How-To: Navigation in the Model or ViewModel + +Now let's take a look at how we need to structure our Model or ViewModel to work with Uno Extensions Navigation. + +## Prerequisites + +1. First of all, create a Model or ViewModel element. + + [!INCLUDE [Guide to creating a basic Model or ViewModel](../HowTo-Adding-New-VM-Class-Record-en.md)] + +2. Now add the `INavigator` as a **DependencyInjection** constructor parameter. + + [!INCLUDE [Guide: Use Constructor Parameters for DependencyInjection](../HowTo-Using-DI-in-ctor-en.md)] + +## Navigation in Xaml + +Basically, you don't actually need navigation code in the ViewModel / Model if you use the `Attached Properties` as described in the [Guide: Defining the UI with NavigationView for ExtensionsNavigation](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en)! + +In this case, it would typically only be the Title properties or others that you bind from View to ViewModel and you would be done. And that is also a big advantage of this extension in my opinion. + +## Binding View UI Controls to Properties in the ViewModel or Model + +Now we have previously set the `Title` of the NavigationView manually, but what about other properties that we want to bind in the View? And you may have also seen the `Name` defined in the `Dashboard(View)Model` in the template app. + +If you're not starting from the template, add this property to bind it in the View. + +```csharp +public string? Name { get; set; } +``` + +### [Mvvm](#tab/mvvm) + +```csharp +public partial class DashboardViewModel : ObservableObject +{ + private readonly INavigator _navigator; + + [ObservableProperty] + [NotifyCanExecuteChangedFor(nameof(NavigateSecondAsyncCommand))] + private string? name; + + public DashboardViewModel(INavigator navigator) + { + _navigator = navigator; + NavigateSecondAsyncCommand = new AsyncRelayCommand(NavigateSecondAsync); + } + + public IAsyncRelayCommand NavigateSecondAsyncCommand { get; } + + [RelayCommand(CanExecute = nameof(CanExecuteNavigateSecondAsync))] + private async Task NavigateSecondAsync() + { + await _navigator.NavigateViewModelAsync(this, data: new Entity(Name!)); + } + + private bool CanExecuteNavigateSecondAsync() + { + return !string.IsNullOrWhiteSpace(Name); + } +} +``` + +### [Mvux](#tab/mvux) + +```csharp +namespace Mvux.XamlNavigationApp.Presentation; + +public partial record MainModel +{ + private INavigator _navigator; + + public DashboardModel(INavigator navigator) + { + _navigator = navigator; + Title = "Dashboard"; + } + + public string? Title { get; } + + public IState Name => State.Value(this, () => string.Empty); + + public async Task NavigateSecondAsync() + { + var name = await Name; + await _navigator.NavigateViewModelAsync(this, data: new Entity(name!)); + } + +} +``` + +With this code, you can bind the `Name` property in the View and use the `NavigateSecondAsyncCommand` to navigate to the `SecondViewModel`. + +You can use a button or another control in the View to trigger navigation, but by binding the `IsEnabled` property of the control to the `CanExecute` status of the command, you can only execute navigation when the name is not empty. + +--- diff --git a/doc/articles/en/Navigation/HowTo-RegisterRoutes-en.md b/doc/articles/en/Navigation/HowTo-RegisterRoutes-en.md new file mode 100644 index 0000000..1477701 --- /dev/null +++ b/doc/articles/en/Navigation/HowTo-RegisterRoutes-en.md @@ -0,0 +1,80 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.en +--- + +# How-To: Register and Manage Routes + +With `Uno.Extensions.Navigation`, we use a central definition of **route registration** handled in the App class [`App.xaml.cs`(source link)](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps/blob/master/src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs), which can simply be thought of as a map. + +## Prerequisites + +Before you start with route registration, you need two things: + +1. One or more pages (`View`) that you want to use in your app. + + - [Add new page elements to your application](xref:DevTKSS.Uno.Setup.HowTo-AddingNewPages.en) + +2. One or more associated `ViewModel` or `Model` that you want to use for the pages. (optional, but recommended) + + - [Add new class or record definitions for a ViewModel or Model](xref:DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.en) + +## RegisterRoutes Method + +Add the required method to your App class below the `OnLaunched` method as follows: + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs#L82)] + +## Defining the `ViewMap`'s + +This tells the Navigator which page (`View`) belongs to which (`View`-)`Model`, where we define properties and functions that the View can call. For this, you will find the `views.Register` section in your application so far, or you can still add it if your application is being upgraded. + +```csharp +{ + views.Register( + new ViewMap(ViewModel: typeof(ShellModel)), + new ViewMap(), + new DataViewMap() +``` + +If additional data objects are required when navigating this route, you convert them as `DataViewMap`, for example, as in the last line. + +For example, this is what it looks like in the XamlNavigationApp, where I no longer needed `Entity` and converted this route back accordingly: + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs#L83-L89)] + +## Hierarchically Structured `RoutesMap`'s + +Now let's look at which routes are accessible from which parent element: + +In this example from a Mvux-using application created from the template, you can see from the `Nested:` parameter name, but also from the structure of the section, what such a hierarchy of routes can look like. + +```csharp + routes.Register( + new RouteMap("", View: views.FindByViewModel(), + Nested: + [ + new RouteMap("Main", View: views.FindByViewModel(), IsDefault:true), + new RouteMap("Second", View: views.FindByViewModel()) + ] + ) + ); +} +``` + +Now, on the `MainPage`, we might want to use a TabBar, NavigationBar, a Frame within a Grid, or even a NavigationView with navigable content property. However, this content might not make sense on the `SecondPage`. In this case, we should ensure that these routes will only be available there. + +**We do this, for example, like this:** + +[!code-csharp[](../../../../src/DevTKSS.Uno.XamlNavigationApp-1/App.xaml.cs#L96-L101)] + +Here you can see that I added another page, the `DashboardPage`, and created a Model for it named `DashboardModel`. I also nested the `Second` route into the `RouteMap` of the `Main` route. + +## Useful Information + +When naming, it always makes sense to keep the route and page element names the same. A `DashboardPage` would thus typically receive `Dashboard` as the route name. + +If you are using **MVUX** instead of **MVVM**, you should make sure not to mistakenly name the **Model** associated with the page or `View` `DashboardViewModel` for the `DashboardPage`, but `DashboardModel`, because the Mvux source code generator will name the `DashboardViewModel` it creates for you exactly that and otherwise unexpected problems can occur. + +## Starting the Application + +Now we are done with the route registration and can start the application. If you now start the app, you should be able to see the `MainPage` and navigate from there to the other pages. diff --git a/doc/articles/en/Navigation/HowTo-UpgradeExistingApp-en.md b/doc/articles/en/Navigation/HowTo-UpgradeExistingApp-en.md new file mode 100644 index 0000000..c63a49d --- /dev/null +++ b/doc/articles/en/Navigation/HowTo-UpgradeExistingApp-en.md @@ -0,0 +1,86 @@ +--- +uid: DevTKSS.Uno.ExtensionsNavigation.UpgradeExistingApp.en +--- + +# How To: Add Uno Extensions Navigation to an Existing Application + +If you already have an existing Uno application, you can of course add Extensions Navigation. + +In the project file, recognizable by the `.csproj` extension, you need the following `UnoFeatures` elements in addition to the `Uno.Sdk`: + +# [Mvux](#tab/mvux) + +```xml + + Hosting; + Mvux; + Navigation; + +``` + +# [Mvvm](#tab/mvvm) + +```xml + + Hosting; + Mvvm; + Navigation; + Toolkit; + +``` + +# [On Launched](#tab/mvux/on-launched) + +Add the following content to your `App.xaml.cs` file if not already included: + +```diff ++ protected async override void OnLaunched(LaunchActivatedEventArgs args) ++ { ++ var builder = this.CreateBuilder(args) ++ // Adds support for additional navigation controls like TabBar and NavigationView ++ .UseToolkitNavigation() ++ .Configure(host => host ++ // Add the callback to the RegisterRoutes method, which will define the routes in the application. ++ .UseNavigation(ReactiveViewModelMappings.ViewModelMappings, RegisterRoutes) ++ ); + MainWindow = builder.Window; + +#if DEBUG + MainWindow.UseStudio(); +#endif + MainWindow.SetWindowIcon(); + ++ Host = await builder.NavigateAsync(); + } +``` + +# [On Launched](#tab/mvvm/on-launched) + +Add the following content to your `App.xaml.cs` file if not already included: + +```diff ++ protected async override void OnLaunched(LaunchActivatedEventArgs args) ++ { ++ var builder = this.CreateBuilder(args) ++ // Adds support for additional navigation controls like TabBar and NavigationView ++ .UseToolkitNavigation() ++ .Configure(host => host ++ // Add the callback to the RegisterRoutes method, which will define the routes in the application. ++ .UseNavigation(RegisterRoutes) ++ ); + MainWindow = builder.Window; + +#if DEBUG + MainWindow.UseStudio(); +#endif + MainWindow.SetWindowIcon(); + ++ Host = await builder.NavigateAsync(); + } +``` + +--- + +## Next Steps + +- [Register the routes in your app](xref:DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.en) diff --git a/doc/articles/en/Navigation/Navigation-Options-en.md b/doc/articles/en/Navigation/Navigation-Options-en.md new file mode 100644 index 0000000..c8ee8f7 --- /dev/null +++ b/doc/articles/en/Navigation/Navigation-Options-en.md @@ -0,0 +1,14 @@ +--- +uid: DevTKSS.Uno.Navigation.Navigation-Options.en +--- + +# How To: Choose Navigation Options for an Uno App + +Every application that comprises more than a single page benefits from the presence of a well-thought-out **navigation**. + +In Uno Apps, we can use two types of navigation: + +- `Frame` navigation (as in WinUI Apps) +- `Regions`, i.e. using `Uno.Extensions.Navigation` + +To get a good overview of the possibilities that `Uno.Extensions.Navigation` offers you, you can, for example, take a look at the [Tutorial: Navigation with Uno Extensions](xref:DevTKSS.Uno.ExtensionsNavigation.Overview.en). There we will look at how to handle or implement the `Uno.Extensions.Navigation` and the `NavigationView` in a Xaml-based Uno application. diff --git a/doc/articles/en/Navigation/toc.yml b/doc/articles/en/Navigation/toc.yml new file mode 100644 index 0000000..0875654 --- /dev/null +++ b/doc/articles/en/Navigation/toc.yml @@ -0,0 +1,27 @@ +items: + - name: "Navigation Options in an Uno App" + uid: DevTKSS.Uno.Navigation.Navigation-Options.en + href: Navigation-Options-en.md + - name: "Navigation with Uno Extensions" + uid: DevTKSS.Uno.ExtensionsNavigation.Overview.en + href: Extensions-Navigation-en.md + - name: Create or Upgrade + items: + - name: "Create App (Wizard/CLI)" + uid: DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.en + href: ../HowTo-CreateApp-en.md + - name: "Upgrade an Existing App" + uid: DevTKSS.Uno.ExtensionsNavigation.UpgradeExistingApp.en + href: HowTo-UpgradeExistingApp-en.md + - name: "Define UI with NavigationView" + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-Defining-UI.en + href: HowTo-Defining-UI-NavigationView-en.md + - name: "Register Routes" + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-RegisterRoutes.en + href: HowTo-RegisterRoutes-en.md + - name: "Define Navigation in Model or ViewModel" + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-DefiningModelOrViewModel.en + href: HowTo-ModelDefinition-en.md + - name: "React to Route Changes" + uid: DevTKSS.Uno.ExtensionsNavigation.HowTo-ChangeRoutes.en + href: HowTo-ChangeRoutes-en.md \ No newline at end of file diff --git a/doc/articles/en/Uno-resources-lookup-en.md b/doc/articles/en/Uno-resources-lookup-en.md new file mode 100644 index 0000000..b0b86f9 --- /dev/null +++ b/doc/articles/en/Uno-resources-lookup-en.md @@ -0,0 +1,128 @@ +--- +uid: DevTKSS.Uno.ResourcesLookup.en +--- + +# Resource Collection for Getting Started with Uno App Development + +Welcome to the Uno Platform Developer Community! + +Here you will learn how to get started with development in your Uno app: https://aka.platform.uno/get-started + +Get an overview of all the great features Uno offers: https://platform.uno/docs/articles/intro.html + +For more information on using Uno.Sdk or updating Uno Platform packages in your solution, see: https://aka.platform.uno/using-uno-sdk + +## Table of Contents + +- [Uno Platform Documentation Resource Collection](#uno-platform-documentation-resource-collection) + - [General Links](#general-links) + - [WinUI as Base](#winui-as-base) +- [Discover Uno Studio Options for Your Application](#discover-uno-studio-options-for-your-application-development) + - [Hot Design](#hot-design) + - [Hot Reload](#hot-reload) + - [Design to Code](#design-to-code) +- [Learn More About `Uno.Extensions`](#learn-more-about-unoextensions) +- [Uno.Resizetizer](#unoresizetizer) +- [Get Help](#get-help) +- [Contribute to Uno Platform](#contribute-to-uno-platform) + +## Uno Platform Documentation Resource Collection + +### General Links + +- [Best Practices for Development with Uno Platform](https://platform.uno/docs/articles/best-practices-uno.html) +- [Development with Uno Platform](https://platform.uno/docs/articles/using-uno-ui.html) + - [Uno Platform Features](https://platform.uno/docs/articles/supported-features.html) + - [List of Controls Implemented in Uno](https://platform.uno/docs/articles/implemented-views.html) + - [Special Notes on WinAppSDK](https://platform.uno/docs/articles/features/winapp-sdk-specifics.html) +- [Updating Uno Platform NuGet Packages](https://platform.uno/docs/articles/upgrading-nuget-packages.html) – here you will also find the current stable version of **Uno.Sdk**! +- [Tutorials](https://platform.uno/docs/articles/samples-tutorials-overview.html) +- [Samples](https://platform.uno/docs/articles/external/uno.samples/doc/samples.html) +- [Additional Resources](https://platform.uno/docs/articles/get-started-next-steps.html) +- [Publishing an Uno App](https://platform.uno/docs/articles/uno-publishing-overview.html) + +### WinUI as Base + +If you are not only new to Uno Platform, but have also never worked with WinUI-based XAML (if you develop with C# Markup, note that the properties still have the same structure as with XAML Markup), you will find a collection of links here to get you started: + +- [Links to WinUI Documentation](https://platform.uno/docs/articles/winui-doc-links.html) +- [WinUI 3 and Uno Platform](https://platform.uno/docs/articles/uwp-vs-winui3.html) + +## Discover Uno Studio Options for Your Application Development + +**Uno Platform Studio** revolutionizes how developers design, build, and iterate on their applications. + +It includes three main tools specifically developed to simplify your workflow: + +### [Hot Design®](https://platform.uno/docs/articles/studio/Hot%20Design/hot-design-overview.html) + +The first runtime visual designer for cross-platform .NET applications. Hot Design transforms your running app into a designer – from any IDE, on any operating system – allowing you to effortlessly create high-quality user interfaces. + +[➜ Learn More About Hot Design®](https://platform.uno/docs/articles/studio/Hot%20Design/hot-design-getstarted-guide.html) + +### [Hot Reload](https://platform.uno/docs/articles/studio/Hot%20Reload/hot-reload-overview.html) + +Reliably update any code in your app and get instant feedback that your changes have been applied – with a new Hot Reload indicator to monitor your changes during development. + +[➜ Get Started with Hot Reload](https://platform.uno/docs/articles/studio/Hot%20Reload/get-started-with-hot-reload.html) + +### [Design-to-Code](https://platform.uno/docs/articles/external/figma-docs/download.html) + +Generate production-ready, well-structured XAML or C# Markup directly from your Figma designs with a single click – and save yourself the manual design handoff. + +[➜ Learn More About Design-to-Code](https://platform.uno/docs/articles/external/figma-docs/get-started.html) + +## Learn More About `Uno.Extensions` + +- [Authentication](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Authentication/AuthenticationOverview.html) +- [Configuration](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Configuration/ConfigurationOverview.html) +- [Hosting](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Hosting/HostingOverview.html) +- [HTTP](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Http/HttpOverview.html) +- [Localization](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Localization/LocalizationOverview.html) +- [Logging](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Logging/LoggingOverview.html) +- [Navigation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Navigation/NavigationOverview.html) +- [Serialization](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Serialization/SerializationOverview.html) +- [Storage](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Storage/StorageOverview.html) +- [Validation](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Validation/ValidationOverview.html) +- [C# Markup](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Markup/Overview.html) +- [.NET MAUI Embedding](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/Maui/MauiOverview.html) +- [Theme Service](https://platform.uno/docs/articles/external/uno.extensions/doc/Learn/ThemeService/HowTo-UseThemeService.html) + +## Uno.Resizetizer + +> [!NOTE] +> When working with Visual Studio, you can insert `*.png` and `*.svg` files into your app without having to convert them with Uno.Resizetizer – it is already included in every Uno app. + +Here's how it works (short version): + +1. Insert the image file into the **Assets** folder in **Solution Explorer** – e.g. under **Images**, **Icons** or **Splash** (create these if they don't exist). +2. Open the file's **Properties Window** and make sure the **Build Action** is set to **`UnoImage`**. + +> [!NOTE] +> Alternatively, you can also configure this directly in your Uno app's `*.csproj` file: +> +> ```xml +> +> +> +> ``` + +For more information, see: [Get Started with Uno.Resizetizer](https://platform.uno/docs/articles/external/uno.resizetizer/doc/using-uno-resizetizer.html). + +## Get Help + +If you encounter problems while developing your Uno app, you can connect with the core team and community via Discord or GitHub. + +Depending on the difficulty of your problem, you may be asked to provide a reproduction project (also called a "repro") so that others can understand your problem and help you specifically. + +You can learn how to create such a repro project here: https://platform.uno/docs/articles/uno-howto-create-a-repro.html + +## Contribute to Uno Platform + +Everyone is invited to contribute to Uno Platform. Here you will find helpful information for new and returning contributors. + +To begin, it's best to read the [Code of Conduct](https://github.com/unoplatform/uno/blob/master/CODE_OF_CONDUCT.md), which establishes the commitment to an open, friendly, and harassment-free Uno Platform community. + +If you don't know where to start: [Read more about ways to contribute](https://github.com/unoplatform/uno/blob/master/doc/articles/contributing/ways-to-contribute.md) or check out the list of [beginner-friendly open issues](https://github.com/unoplatform/Uno/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). + +For more information, see the official documentation: https://platform.uno/docs/articles/uno-development/contributing-intro.html diff --git a/doc/articles/en/toc.yml b/doc/articles/en/toc.yml new file mode 100644 index 0000000..c848deb --- /dev/null +++ b/doc/articles/en/toc.yml @@ -0,0 +1,26 @@ +# yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/toc.schema.json +- name: Welcome + uid: DevTKSS.Uno.SampleApps.Intro.en + href: Introduction-en.md +- name: Uno Platform Resource Collection + uid: DevTKSS.Uno.ResourcesLookup.en + href: Uno-resources-lookup-en.md +- name: Mvux Gallery Overview + uid: DevTKSS.Uno.SampleApps.MvuxGallery.Overview.en + href: MvuxGallery-Overview-en.md +- name: "Getting Started & Basics" + items: + - name: Set Up Development Environment + uid: DevTKSS.Uno.Setup.DevelopmentEnvironment.en + href: HowTo-Setup-DevelopmentEnvironment-en.md + - name: "Create a New Uno App" + uid: DevTKSS.Uno.Setup.HowTo-CreateNewUnoApp.en + href: HowTo-CreateApp-en.md + - name: "Add Pages" + uid: DevTKSS.Uno.Setup.HowTo-AddingNewPages.en + href: HowTo-Adding-New-Pages-en.md + - name: "Define New Class or Record ViewModels" + uid: DevTKSS.Uno.Setup.HowTo-AddingNew-VM-Class-Record.en + href: HowTo-Adding-New-VM-Class-Record-en.md +- name: "Navigation in Uno Apps" + href: Navigation/toc.yml diff --git a/doc/articles/getting-started.md b/doc/articles/getting-started.md deleted file mode 100644 index e0562ff..0000000 --- a/doc/articles/getting-started.md +++ /dev/null @@ -1,31 +0,0 @@ -# Getting Started - -To setup your Development Environment for Uno Apps, please make sure, to follow the [Quick Start Guide](https://platform.uno/docs/articles/get-started.html) provided by Uno Platform which will include: - -- Download latest dotnet -- Install your desired IDE - - > [!NOTE] - > I will use Visual Studio 2022 Community Edition for the Guides described in here. - -- Get the Uno Extension from the Visual Studio Marketplace -- Install Uno.Check via your Commandline: `dotnet tool install -g Uno.Check` -- Run `uno-check` which will suggest you to get or fix missing Workloads for you, to ensure a smooth start unto development every day. - - > [!NOTE] - > There are configurations available to be applied onto the uno-check command. You can research them in the [Uno.Check Documentation](https://platform.uno/docs/articles/external/uno.check/doc/configuring-uno-check.html) or get them in your Commandline by typing `uno-check -h` - -- In case, you run in Problems while this, make sure to check out the [Troubleshooting](https://platform.uno/docs/articles/external/uno.check/doc/troubleshooting-uno-check.html) - -All done? Great! - -I recommend you to do at least the [Counter Workshop](https://platform.uno/docs/articles/getting-started/counterapp/get-started-counter.html) to get a base understanding of: - -- Application Structure -- Assets (Images/Icons) handling with Uno.Resizetizer -- Commands and Bindings - - > [!TIP] - > Depending on the targeted Tutorial you would like to do in here, you should coose the appropriate kind of the workshop, as it is letting you choose between XAML or C# for Markup and MVVM or MVUX as Presentation / Application Structure. - -See you soon in the mested Tutorials here! diff --git a/doc/articles/introduction.md b/doc/articles/introduction.md deleted file mode 100644 index 16c9917..0000000 --- a/doc/articles/introduction.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -uid: DevTKSS.Uno.SampleApps.Intro -_layout: landing ---- - -# Hello and Welcome! - -This documentation provides insights into various sample applications built using the Uno Platform. These samples are designed to assist developers of all skill levels in understanding and implementing the showcased concepts effectively. - -The samples in this Repository are meant to help other Developers, independent to their pre-knowledge, get an Idea of how to use the shown things. - -Visit the [API Documentation](../api/) for a Reference created from the Sourcecode - -## Current Samples List - -To give you a quick overview of this Documentation, here is a List of quick links to the included Sample Apps. For future and more detailed Information, please lookup the depending Chapter via the Table of Contents. - -- MvuxGallery - - [Docs](./MvuxGallery/Overview.md) - - [source code:](../src/DevTKSS.Uno.Samples.MvuxGallery/) - -## Next Steps - -- [Getting started!](./getting-started.md) - diff --git a/doc/articles/toc.yml b/doc/articles/toc.yml index 1c27061..9a2a141 100644 --- a/doc/articles/toc.yml +++ b/doc/articles/toc.yml @@ -1,9 +1,6 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/toc.schema.json -topicHref: introduction.md items: -- name: Introduction - href: introduction.md -- name: Sample Apps - items: - - name: Mvux Gallery - href: MvuxGallery/ + - name: Deutsch + href: de/toc.yml + - name: English + href: en/toc.yml diff --git a/doc/docfx.json b/doc/docfx.json index 1a50951..7899119 100644 --- a/doc/docfx.json +++ b/doc/docfx.json @@ -4,53 +4,102 @@ { "src": [ { - "src": "../src", "files": [ - "**/DevTKSS.*.csproj" - ] + "**/DevTKSS.Extensions.Uno.Extensions.csproj", + "**/DevTKSS.Uno.Samples.MvuxGallery.csproj" + ], + "src": "../src" } ], - "output": "api" + "includeExplicitInterfaceImplementations": false, + "disableDefaultFilter": false, + "filter": "Resources/filterConfig.yml", + // "codeSourceBasePath": "../", + "noRestore": true, + "output": "api", + "memberLayout": "samePage", + "outputFormat": "apiPage" } ], "build": { + "globalMetadata": { + "_appTitle": "DevTKSS Sample Apps & Tutorials for Uno Platform Development", + "_appName": "DevTKSS.Uno.SampleApps", + "_appFaviconPath": "images/logo/styled-logo.ico", + "_appLogoPath": "images/logo/styled-logo-small.png", + "_copyrightFooter": "© 2025 Sonja Schweitzer, DevTKSS, TKSS Development, All rights reserved.", + "_ownerName": "TKSS Development", + "_githubProfileLink": "https://github.com/DevTKSS", + "_enableSearch": true, + "_disableAffix": false, + "_disableBreadcrumb": false, + "_disableNextArticle": false, + "_disableTocFilter": false, + "_lang": "csharp", // this gets unrecognized for metadata somehow + "pdf": false + }, "content": [ + { + "files":[ + "api/**.yml", + "api/index.md" + ] + }, { "files": [ - "**/*.{md,yml}" - ], - "exclude": [ - "_site/**", - "api/Uno.Resizetizer*.yml" + "articles/**.{md,yml}", + "toc.yml", + "index.md", + "../README.md" ] } ], "resource": [ { "files": [ - "images/**" + "images/logo/*.{png,ico}", + "articles/.attachments/*.{png,gif}" + ], + "dot": true + } + ], + "overwrite": [ + { + "files":[ + "api/**.md", + // "api/**.yml", + "articles/**.md", + "articles/**.yml", + "index.md" + ], + "exclude":[ + "obj/**", + "_site/**" ] } ], - "output": "_site", "template": [ "default", - "modern" + "modern"//, + // "templates/singulinkfx" ], + "xref": [ "https://learn.microsoft.com/en-us/dotnet/.xrefmap.json" ], "markdownEngineProperties": { "markdigExtensions": [ "yaml", "definitionlists", - "bootstrap", - "globalization", - "advanced" + "diagrams", + "advanced", + "alerts", + "emojis", + "footers", + "footnotes", + "medialinks" ] }, - "globalMetadata": { - "_appName": "DevTKSS.Uno.SampleApps", - "_appTitle": "DevTKSS.Uno.SampleApps", - "_enableSearch": false, - "pdf": false + "output": "_site", + "sitemap": { + "baseUrl": "https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc/" } } } diff --git a/doc/images/logo/styled-logo-small.png b/doc/images/logo/styled-logo-small.png new file mode 100644 index 0000000..f7eecfd Binary files /dev/null and b/doc/images/logo/styled-logo-small.png differ diff --git a/doc/images/logo/styled-logo.ico b/doc/images/logo/styled-logo.ico new file mode 100644 index 0000000..fa6ccbd Binary files /dev/null and b/doc/images/logo/styled-logo.ico differ diff --git a/doc/index.md b/doc/index.md new file mode 100644 index 0000000..b8ed7f5 --- /dev/null +++ b/doc/index.md @@ -0,0 +1,6 @@ + + + +[!INCLUDE [landing-page](../README.md)] diff --git a/doc/templates/singulinkfx/layout/_master.tmpl b/doc/templates/singulinkfx/layout/_master.tmpl new file mode 100644 index 0000000..32d4927 --- /dev/null +++ b/doc/templates/singulinkfx/layout/_master.tmpl @@ -0,0 +1,74 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} +{{!include(/^styles/.*/)}} +{{!include(/^fonts/.*/)}} +{{!include(favicon.ico)}} +{{!include(logo.svg)}} +{{!include(search-stopwords.json)}} + + + + {{>partials/head}} + + + +
+
+ + + + + {{>partials/logo}} +
+ +
+
+ +
+
+ {{>partials/navbar}} +
+ {{^_disableToc}} + {{>partials/toc}} + {{/_disableToc}} +
+ {{>partials/footer}} +
+ +
+ {{#_enableSearch}} + {{>partials/searchResults}} + {{/_enableSearch}} + + + +
+ {{^_disableBreadcrumb}} + {{>partials/breadcrumb}} + {{/_disableBreadcrumb}} + + {{^_disableContribution}} +
+ {{#docurl}} + {{__global.improveThisDoc}} + {{/docurl}} +
+ {{/_disableContribution}} + +
+ {{!body}} +
+
+ + {{#_copyrightFooter}} +
+ {{_copyrightFooter}} +
+ {{/_copyrightFooter}} +
+
+ + {{>partials/scripts}} + + diff --git a/doc/templates/singulinkfx/partials/footer.tmpl.partial b/doc/templates/singulinkfx/partials/footer.tmpl.partial new file mode 100644 index 0000000..5c6f48f --- /dev/null +++ b/doc/templates/singulinkfx/partials/footer.tmpl.partial @@ -0,0 +1,4 @@ +
+ {{{_appFooter}}} + {{^_appFooter}}Powered byDocFX + {{ _ownerName }}{{/_appFooter}} +
\ No newline at end of file diff --git a/doc/templates/singulinkfx/partials/head.tmpl.partial b/doc/templates/singulinkfx/partials/head.tmpl.partial new file mode 100644 index 0000000..2b0dd67 --- /dev/null +++ b/doc/templates/singulinkfx/partials/head.tmpl.partial @@ -0,0 +1,23 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + + + + + {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}} + + + + {{#_description}}{{/_description}} + + + + + + + + + + {{#_noindex}}{{/_noindex}} + {{#_enableSearch}}{{/_enableSearch}} + {{#_enableNewTab}}{{/_enableNewTab}} + \ No newline at end of file diff --git a/doc/templates/singulinkfx/partials/li.tmpl.partial b/doc/templates/singulinkfx/partials/li.tmpl.partial new file mode 100644 index 0000000..2c8a3d0 --- /dev/null +++ b/doc/templates/singulinkfx/partials/li.tmpl.partial @@ -0,0 +1,31 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +
    + {{#items}} + {{^dropdown}} +
  • + {{^leaf}} + + {{/leaf}} + {{#topicHref}} + {{name}} + {{/topicHref}} + {{^topicHref}} + {{{name}}} + {{/topicHref}} + + {{^leaf}} + {{>partials/li}} + {{/leaf}} +
  • + {{/dropdown}} + {{#dropdown}} +
  • + {{name}} +
      + {{>partials/dd-li}} +
    +
  • + {{/dropdown}} + {{/items}} +
diff --git a/doc/templates/singulinkfx/partials/logo.tmpl.partial b/doc/templates/singulinkfx/partials/logo.tmpl.partial new file mode 100644 index 0000000..738ab5b --- /dev/null +++ b/doc/templates/singulinkfx/partials/logo.tmpl.partial @@ -0,0 +1,6 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + + + {{_appName}} + {{_appName}} + \ No newline at end of file diff --git a/doc/templates/singulinkfx/partials/namespace.tmpl.partial b/doc/templates/singulinkfx/partials/namespace.tmpl.partial new file mode 100644 index 0000000..42d64e6 --- /dev/null +++ b/doc/templates/singulinkfx/partials/namespace.tmpl.partial @@ -0,0 +1,13 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +

{{>partials/title}}

+
{{{summary}}}
+
{{{conceptual}}}
+
{{{remarks}}}
+{{#children}} +

{{>partials/namespaceSubtitle}}

+ {{#children}} +
+
{{{summary}}}
+ {{/children}} +{{/children}} diff --git a/doc/templates/singulinkfx/partials/navbar.tmpl.partial b/doc/templates/singulinkfx/partials/navbar.tmpl.partial new file mode 100644 index 0000000..cfddfd8 --- /dev/null +++ b/doc/templates/singulinkfx/partials/navbar.tmpl.partial @@ -0,0 +1,19 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +
+
+ {{>partials/logo}} +
+ + {{#_enableSearch}} +
+
+ + +
+
+ {{/_enableSearch}} + +
+
+
\ No newline at end of file diff --git a/doc/templates/singulinkfx/partials/scripts.tmpl.partial b/doc/templates/singulinkfx/partials/scripts.tmpl.partial new file mode 100644 index 0000000..8ef7f26 --- /dev/null +++ b/doc/templates/singulinkfx/partials/scripts.tmpl.partial @@ -0,0 +1,13 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/templates/singulinkfx/partials/searchResults.tmpl.partial b/doc/templates/singulinkfx/partials/searchResults.tmpl.partial new file mode 100644 index 0000000..9f08c90 --- /dev/null +++ b/doc/templates/singulinkfx/partials/searchResults.tmpl.partial @@ -0,0 +1,9 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +
+

{{__global.searchResults}}

+
+

+
+
    +
    \ No newline at end of file diff --git a/doc/templates/singulinkfx/partials/toc.tmpl.partial b/doc/templates/singulinkfx/partials/toc.tmpl.partial new file mode 100644 index 0000000..c660966 --- /dev/null +++ b/doc/templates/singulinkfx/partials/toc.tmpl.partial @@ -0,0 +1,5 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +
    +
    +
    diff --git a/doc/templates/singulinkfx/styles/config.css b/doc/templates/singulinkfx/styles/config.css new file mode 100644 index 0000000..cb39b51 --- /dev/null +++ b/doc/templates/singulinkfx/styles/config.css @@ -0,0 +1,124 @@ +/* Theme Configuration Options */ + +:root +{ + /* General */ + + --base-font-size: 16px; + --smalldevice-base-font-size: 14px; /* Base font size for devices < 1024px */ + + --main-bg-color: #1f1f23; + --footer-bg-color: rgba(0,0,0,.4); + --separator-color: #42474f; + + --table-strip-bg-color: #151515; + --table-header-bg-color: black; + --table-header-color: hsla(0,0%,100%,.8); + --table-header-border-color: #040405; + + /* Text */ + + --appname-color: white; + + --h1-color: white; + --h2-color: #f2f2f2; + --h3-color: #e3e3e3; + --h4-color: #ffffff; + --h5-color: #e0e0e0; + + --text-color: #e1e1e1; + --link-color: #00b0f4; + --link-hover-color: #2ec4ff; + + /* Mobile Topbar */ + + --topbar-bg-color: #18191c; + + /* Button */ + + --button-color: #747f8d; + + /* Sidebar */ + + --sidebar-width: 400px; + --sidebar-bg-color: #292B30; + + --search-color: #bdbdbd; + --search-bg-color: #1b1e21; + --search-searchicon-color: #e3e3e3; + --search-border-color: black; + + --sidebar-item-color: white; + --sidebar-active-item-color: #00b0f4; + --sidebar-level1-item-bg-color: #222429; + --sidebar-level1-item-hover-bg-color: #1D1F22; + + --toc-filter-color: #bdbdbd; + --toc-filter-bg-color: #1b1e21; + --toc-filter-filtericon-color: #e3e3e3; + --toc-filter-clearicon-color: #e68585; + --toc-filter-border-color: black; + + /* Scrollbars */ + + --scrollbar-bg-color: transparent; + --scrollbar-thumb-bg-color: rgba(0,0,0,.4); + --scrollbar-thumb-border-color: transparent; + + /* Alerts and Blocks */ + + --alert-info-border-color: rgba(114,137,218,.5); + --alert-info-bg-color: rgba(114,137,218,.1); + + --alert-warning-border-color: rgba(250,166,26,.5); + --alert-warning-bg-color: rgba(250,166,26,.1); + + --alert-danger-border-color: rgba(240,71,71,.5); + --alert-danger-bg-color: rgba(240,71,71,.1); + + --alert-tip-border-color: rgba(255,255,255,.5); + --alert-tip-bg-color: rgba(255,255,255,.1); + + --blockquote-border-color: rgba(255,255,255,.5); + --blockquote-bg-color: rgba(255,255,255,.1); + + --breadcrumb-bg-color: #2f3136; + + /* Tabs */ + + --nav-tabs-border-width: 1px; + --nav-tabs-border-color: #495057; + --nav-tabs-border-radius: .375rem; + --nav-tabs-link-hover-border-color: #303336 #303336 transparent; + --nav-tabs-link-active-color: white; + --nav-tabs-link-active-bg: var(--main-bg-color); + --nav-tabs-link-active-border-color: var(--nav-tabs-border-color) var(--nav-tabs-border-color) var(--main-bg-color); + + /* Inline Code */ + + --ref-bg-color: black; + --ref-color: #89d4f1; + + /* Code Blocks */ + + --code-bg-color: #151515; + --code-color: #d6deeb; + --code-keyword-color: #569cd6; + --code-comment-color: #57a64a; + --code-macro-color: #beb7ff; + --code-string-color: #d69d85; + --code-string-escape-color: #ffd68f; + --code-field-color: #c8c8c8; + --code-function-color: #dcdcaa; + --code-control-color: #d8a0df; + --code-class-color: #4ec9b0; + --code-number-color: #b5cea8; + --code-params-color: #9a9a9a; + --code-breakpoint-color: #8c2f2f; +} + +/* Code Block Overrides */ + +pre, legend { + --scrollbar-thumb-bg-color: #333; +} \ No newline at end of file diff --git a/doc/templates/singulinkfx/styles/down-arrow.svg b/doc/templates/singulinkfx/styles/down-arrow.svg new file mode 100644 index 0000000..e086126 --- /dev/null +++ b/doc/templates/singulinkfx/styles/down-arrow.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/templates/singulinkfx/styles/jquery.twbsPagination.js b/doc/templates/singulinkfx/styles/jquery.twbsPagination.js new file mode 100644 index 0000000..332c01c --- /dev/null +++ b/doc/templates/singulinkfx/styles/jquery.twbsPagination.js @@ -0,0 +1,317 @@ +/*! + * jQuery pagination plugin v1.4.1 + * http://esimakin.github.io/twbs-pagination/ + * + * Copyright 2014-2016, Eugene Simakin + * Released under Apache 2.0 license + * http://apache.org/licenses/LICENSE-2.0.html + */ +(function ($, window, document, undefined) { + + 'use strict'; + + var old = $.fn.twbsPagination; + + // PROTOTYPE AND CONSTRUCTOR + + var TwbsPagination = function (element, options) { + this.$element = $(element); + this.options = $.extend({}, $.fn.twbsPagination.defaults, options); + + if (this.options.startPage < 1 || this.options.startPage > this.options.totalPages) { + throw new Error('Start page option is incorrect'); + } + + this.options.totalPages = parseInt(this.options.totalPages); + if (isNaN(this.options.totalPages)) { + throw new Error('Total pages option is not correct!'); + } + + this.options.visiblePages = parseInt(this.options.visiblePages); + if (isNaN(this.options.visiblePages)) { + throw new Error('Visible pages option is not correct!'); + } + + if (this.options.onPageClick instanceof Function) { + this.$element.first().on('page', this.options.onPageClick); + } + + // hide if only one page exists + if (this.options.hideOnlyOnePage && this.options.totalPages == 1) { + this.$element.trigger('page', 1); + return this; + } + + if (this.options.totalPages < this.options.visiblePages) { + this.options.visiblePages = this.options.totalPages; + } + + if (this.options.href) { + this.options.startPage = this.getPageFromQueryString(); + if (!this.options.startPage) { + this.options.startPage = 1; + } + } + + var tagName = (typeof this.$element.prop === 'function') ? + this.$element.prop('tagName') : this.$element.attr('tagName'); + + if (tagName === 'UL') { + this.$listContainer = this.$element; + } else { + this.$listContainer = $('
      '); + } + + this.$listContainer.addClass(this.options.paginationClass); + + if (tagName !== 'UL') { + this.$element.append(this.$listContainer); + } + + if (this.options.initiateStartPageClick) { + this.show(this.options.startPage); + } else { + this.render(this.getPages(this.options.startPage)); + this.setupEvents(); + } + + return this; + }; + + TwbsPagination.prototype = { + + constructor: TwbsPagination, + + destroy: function () { + this.$element.empty(); + this.$element.removeData('twbs-pagination'); + this.$element.off('page'); + + return this; + }, + + show: function (page) { + if (page < 1 || page > this.options.totalPages) { + throw new Error('Page is incorrect.'); + } + this.currentPage = page; + + this.render(this.getPages(page)); + this.setupEvents(); + + this.$element.trigger('page', page); + + return this; + }, + + buildListItems: function (pages) { + var listItems = []; + + if (this.options.first) { + listItems.push(this.buildItem('first', 1)); + } + + if (this.options.prev) { + var prev = pages.currentPage > 1 ? pages.currentPage - 1 : this.options.loop ? this.options.totalPages : 1; + listItems.push(this.buildItem('prev', prev)); + } + + for (var i = 0; i < pages.numeric.length; i++) { + listItems.push(this.buildItem('page', pages.numeric[i])); + } + + if (this.options.next) { + var next = pages.currentPage < this.options.totalPages ? pages.currentPage + 1 : this.options.loop ? 1 : this.options.totalPages; + listItems.push(this.buildItem('next', next)); + } + + if (this.options.last) { + listItems.push(this.buildItem('last', this.options.totalPages)); + } + + return listItems; + }, + + buildItem: function (type, page) { + var $itemContainer = $('
    • '), + $itemContent = $(''), + itemText = this.options[type] ? this.makeText(this.options[type], page) : page; + + $itemContainer.addClass(this.options[type + 'Class']); + $itemContainer.data('page', page); + $itemContainer.data('page-type', type); + $itemContainer.append($itemContent.attr('href', this.makeHref(page)).addClass(this.options.anchorClass).html(itemText)); + + return $itemContainer; + }, + + getPages: function (currentPage) { + var pages = []; + + var half = Math.floor(this.options.visiblePages / 2); + var start = currentPage - half + 1 - this.options.visiblePages % 2; + var end = currentPage + half; + + // handle boundary case + if (start <= 0) { + start = 1; + end = this.options.visiblePages; + } + if (end > this.options.totalPages) { + start = this.options.totalPages - this.options.visiblePages + 1; + end = this.options.totalPages; + } + + var itPage = start; + while (itPage <= end) { + pages.push(itPage); + itPage++; + } + + return {"currentPage": currentPage, "numeric": pages}; + }, + + render: function (pages) { + var _this = this; + this.$listContainer.children().remove(); + var items = this.buildListItems(pages); + jQuery.each(items, function(key, item){ + _this.$listContainer.append(item); + }); + + this.$listContainer.children().each(function () { + var $this = $(this), + pageType = $this.data('page-type'); + + switch (pageType) { + case 'page': + if ($this.data('page') === pages.currentPage) { + $this.addClass(_this.options.activeClass); + } + break; + case 'first': + $this.toggleClass(_this.options.disabledClass, pages.currentPage === 1); + break; + case 'last': + $this.toggleClass(_this.options.disabledClass, pages.currentPage === _this.options.totalPages); + break; + case 'prev': + $this.toggleClass(_this.options.disabledClass, !_this.options.loop && pages.currentPage === 1); + break; + case 'next': + $this.toggleClass(_this.options.disabledClass, + !_this.options.loop && pages.currentPage === _this.options.totalPages); + break; + default: + break; + } + + }); + }, + + setupEvents: function () { + var _this = this; + this.$listContainer.off('click').on('click', 'li', function (evt) { + var $this = $(this); + if ($this.hasClass(_this.options.disabledClass) || $this.hasClass(_this.options.activeClass)) { + return false; + } + // Prevent click event if href is not set. + !_this.options.href && evt.preventDefault(); + _this.show(parseInt($this.data('page'))); + }); + }, + + makeHref: function (page) { + return this.options.href ? this.generateQueryString(page) : "#"; + }, + + makeText: function (text, page) { + return text.replace(this.options.pageVariable, page) + .replace(this.options.totalPagesVariable, this.options.totalPages) + }, + getPageFromQueryString: function (searchStr) { + var search = this.getSearchString(searchStr), + regex = new RegExp(this.options.pageVariable + '(=([^&#]*)|&|#|$)'), + page = regex.exec(search); + if (!page || !page[2]) { + return null; + } + page = decodeURIComponent(page[2]); + page = parseInt(page); + if (isNaN(page)) { + return null; + } + return page; + }, + generateQueryString: function (pageNumber, searchStr) { + var search = this.getSearchString(searchStr), + regex = new RegExp(this.options.pageVariable + '=*[^&#]*'); + if (!search) return ''; + return '?' + search.replace(regex, this.options.pageVariable + '=' + pageNumber); + + }, + getSearchString: function (searchStr) { + var search = searchStr || window.location.search; + if (search === '') { + return null; + } + if (search.indexOf('?') === 0) search = search.substr(1); + return search; + } + + }; + + // PLUGIN DEFINITION + + $.fn.twbsPagination = function (option) { + var args = Array.prototype.slice.call(arguments, 1); + var methodReturn; + + var $this = $(this); + var data = $this.data('twbs-pagination'); + var options = typeof option === 'object' ? option : {}; + + if (!data) $this.data('twbs-pagination', (data = new TwbsPagination(this, options) )); + if (typeof option === 'string') methodReturn = data[ option ].apply(data, args); + + return ( methodReturn === undefined ) ? $this : methodReturn; + }; + + $.fn.twbsPagination.defaults = { + totalPages: 1, + startPage: 1, + visiblePages: 5, + initiateStartPageClick: true, + hideOnlyOnePage: false, + href: false, + pageVariable: '{{page}}', + totalPagesVariable: '{{total_pages}}', + page: null, + first: 'First', + prev: 'Previous', + next: 'Next', + last: 'Last', + loop: false, + onPageClick: null, + paginationClass: 'pagination', + nextClass: 'page-item next', + prevClass: 'page-item prev', + lastClass: 'page-item last', + firstClass: 'page-item first', + pageClass: 'page-item', + activeClass: 'active', + disabledClass: 'disabled', + anchorClass: 'page-link' + }; + + $.fn.twbsPagination.Constructor = TwbsPagination; + + $.fn.twbsPagination.noConflict = function () { + $.fn.twbsPagination = old; + return this; + }; + + $.fn.twbsPagination.version = "1.4.1"; + +})(window.jQuery, window, document); diff --git a/doc/templates/singulinkfx/styles/jquery.twbsPagination.min.js b/doc/templates/singulinkfx/styles/jquery.twbsPagination.min.js new file mode 100644 index 0000000..a9e11c6 --- /dev/null +++ b/doc/templates/singulinkfx/styles/jquery.twbsPagination.min.js @@ -0,0 +1,8 @@ +/*! + * jQuery pagination plugin v1.4.1 + * http://esimakin.github.io/twbs-pagination/ + * + * Copyright 2014-2016, Eugene Simakin + * Released under Apache 2.0 license + * http://apache.org/licenses/LICENSE-2.0.html + */ !function(t,s,i,e){"use strict";var a=t.fn.twbsPagination,o=function(s,i){if(this.$element=t(s),this.options=t.extend({},t.fn.twbsPagination.defaults,i),this.options.startPage<1||this.options.startPage>this.options.totalPages)throw Error("Start page option is incorrect");if(this.options.totalPages=parseInt(this.options.totalPages),isNaN(this.options.totalPages))throw Error("Total pages option is not correct!");if(this.options.visiblePages=parseInt(this.options.visiblePages),isNaN(this.options.visiblePages))throw Error("Visible pages option is not correct!");if(this.options.onPageClick instanceof Function&&this.$element.first().on("page",this.options.onPageClick),this.options.hideOnlyOnePage&&1==this.options.totalPages)return this.$element.trigger("page",1),this;this.options.totalPages"),this.$listContainer.addClass(this.options.paginationClass),"UL"!==e&&this.$element.append(this.$listContainer),this.options.initiateStartPageClick?this.show(this.options.startPage):(this.render(this.getPages(this.options.startPage)),this.setupEvents()),this};o.prototype={constructor:o,destroy:function(){return this.$element.empty(),this.$element.removeData("twbs-pagination"),this.$element.off("page"),this},show:function(t){if(t<1||t>this.options.totalPages)throw Error("Page is incorrect.");return this.currentPage=t,this.render(this.getPages(t)),this.setupEvents(),this.$element.trigger("page",t),this},buildListItems:function(t){var s=[];if(this.options.first&&s.push(this.buildItem("first",1)),this.options.prev){var i=t.currentPage>1?t.currentPage-1:this.options.loop?this.options.totalPages:1;s.push(this.buildItem("prev",i))}for(var e=0;e"),a=t(""),o=this.options[s]?this.makeText(this.options[s],i):i;return e.addClass(this.options[s+"Class"]),e.data("page",i),e.data("page-type",s),e.append(a.attr("href",this.makeHref(i)).addClass(this.options.anchorClass).html(o)),e},getPages:function(t){var s=[],i=Math.floor(this.options.visiblePages/2),e=t-i+1-this.options.visiblePages%2,a=t+i;e<=0&&(e=1,a=this.options.visiblePages),a>this.options.totalPages&&(e=this.options.totalPages-this.options.visiblePages+1,a=this.options.totalPages);for(var o=e;o<=a;)s.push(o),o++;return{currentPage:t,numeric:s}},render:function(s){var i=this;this.$listContainer.children().remove();var e=this.buildListItems(s);jQuery.each(e,function(t,s){i.$listContainer.append(s)}),this.$listContainer.children().each(function(){var e=t(this),a=e.data("page-type");switch(a){case"page":e.data("page")===s.currentPage&&e.addClass(i.options.activeClass);break;case"first":e.toggleClass(i.options.disabledClass,1===s.currentPage);break;case"last":e.toggleClass(i.options.disabledClass,s.currentPage===i.options.totalPages);break;case"prev":e.toggleClass(i.options.disabledClass,!i.options.loop&&1===s.currentPage);break;case"next":e.toggleClass(i.options.disabledClass,!i.options.loop&&s.currentPage===i.options.totalPages)}})},setupEvents:function(){var s=this;this.$listContainer.off("click").on("click","li",function(i){var e=t(this);if(e.hasClass(s.options.disabledClass)||e.hasClass(s.options.activeClass))return!1;s.options.href||i.preventDefault(),s.show(parseInt(e.data("page")))})},makeHref:function(t){return this.options.href?this.generateQueryString(t):"#"},makeText:function(t,s){return t.replace(this.options.pageVariable,s).replace(this.options.totalPagesVariable,this.options.totalPages)},getPageFromQueryString:function(t){var s=this.getSearchString(t),i=RegExp(this.options.pageVariable+"(=([^&#]*)|&|#|$)").exec(s);return i&&i[2]?(i=parseInt(i=decodeURIComponent(i[2])),isNaN(i))?null:i:null},generateQueryString:function(t,s){var i=this.getSearchString(s),e=RegExp(this.options.pageVariable+"=*[^&#]*");return i?"?"+i.replace(e,this.options.pageVariable+"="+t):""},getSearchString:function(t){var i=t||s.location.search;return""===i?null:(0===i.indexOf("?")&&(i=i.substr(1)),i)}},t.fn.twbsPagination=function(s){var i,e=Array.prototype.slice.call(arguments,1),a=t(this),n=a.data("twbs-pagination");return n||a.data("twbs-pagination",n=new o(this,"object"==typeof s?s:{})),"string"==typeof s&&(i=n[s].apply(n,e)),void 0===i?a:i},t.fn.twbsPagination.defaults={totalPages:1,startPage:1,visiblePages:5,initiateStartPageClick:!0,hideOnlyOnePage:!1,href:!1,pageVariable:"{{page}}",totalPagesVariable:"{{total_pages}}",page:null,first:"First",prev:"Previous",next:"Next",last:"Last",loop:!1,onPageClick:null,paginationClass:"pagination",nextClass:"page-item next",prevClass:"page-item prev",lastClass:"page-item last",firstClass:"page-item first",pageClass:"page-item",activeClass:"active",disabledClass:"disabled",anchorClass:"page-link"},t.fn.twbsPagination.Constructor=o,t.fn.twbsPagination.noConflict=function(){return t.fn.twbsPagination=a,this},t.fn.twbsPagination.version="1.4.1"}(window.jQuery,window,document); \ No newline at end of file diff --git a/doc/templates/singulinkfx/styles/main.css b/doc/templates/singulinkfx/styles/main.css new file mode 100644 index 0000000..e69de29 diff --git a/doc/templates/singulinkfx/styles/main.js b/doc/templates/singulinkfx/styles/main.js new file mode 100644 index 0000000..e69de29 diff --git a/doc/templates/singulinkfx/styles/singulink.css b/doc/templates/singulinkfx/styles/singulink.css new file mode 100644 index 0000000..b1b79a7 --- /dev/null +++ b/doc/templates/singulinkfx/styles/singulink.css @@ -0,0 +1,1033 @@ +@keyframes showThat { + 0% { + opacity: 0; + visibility: hidden + } + + 1% { + opacity: 0; + visibility: visible + } + + to { + opacity: 1; + visibility: visible + } +} + +@keyframes hideThat { + 0% { + opacity: 1; + visibility: visible + } + + 99% { + opacity: 0; + visibility: visible + } + + to { + opacity: 0; + visibility: hidden + } +} + +::-webkit-scrollbar { + width: 10px +} + +::-webkit-scrollbar-track { + background: var(--scrollbar-bg-color) +} + +::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb-bg-color); + border-color: var(--scrollbar-thumb-border-color); + border-radius: 5px +} + +::marker { + unicode-bidi: isolate; + font-variant-numeric: tabular-nums; + text-transform: none; + text-indent: 0!important; + text-align: start!important; + text-align-last: start!important +} + +*,:after,:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box +} + +body,html { + padding: 0; + margin: 0; + font: 15px/150%"Roboto",sans-serif; + color: var(--text-color); + background-color: var(--main-bg-color) +} + +img { + max-width: 100% +} + +ol>li,ul>li { + display: list-item +} + +h1 { + color: var(--link-active-color) +} + +h1,h2,h3,h4,h5 { + position: relative +} + +h1,h2 { + margin-block-start: 2em +} + +h3 { + color: var(--h3-color) +} + +h4 { + opacity: 1; + color: var(--h4-color); + border-bottom: 2px solid var(--separator-color); + margin: 20px 0 0 +} + +h5 { + margin-block-end: .8em; + margin-block-start: 1em; + font-weight: 500; + color: var(--h5-color) +} + +h6 { + font-size: .75em; + margin: 0 +} + +p { + font-weight: 400 +} + +ul { + position: relative +} + +ol,ul { + padding-inline-start: 2.5em +} + +ul span.term { + font-weight: bold; +} + +ul span.term:after { + content: ' - '; +} + +ul.level1 { + list-style-type: none; + padding-inline-start: 0 +} + +ul.level2,ul.level3 { + list-style-type: none; + font-size: .9em +} + +a { + color: var(--link-color); + text-decoration: none; + transition: color .25s +} + +a:focus,a:hover { + color: var(--link-hover-color); + text-decoration: underline +} + +a.anchorjs-link:hover { + text-decoration: none +} + +a.active,a:active { + color: var(--link-active-color) +} + +.body-content { + display: flex; + flex-direction: row; + height: 100%; + overflow-x: hidden; + overflow-y: hidden +} + +.footer>h4,.page-title { + margin-block-start: 0 +} + +nav { + transition: left .5s ease-out; + position: fixed; + left: -350px; + top: 40px; + bottom: 0; + background-color: var(--sidebar-bg-color); + overflow-y: auto; + display: flex; + flex-direction: column; + z-index: 1000 +} + +h1:first-child { + margin-top: 1.1em +} + +.sidebar { + flex: 1 +} + +.sidebar-item { + font-size: 1em; + font-weight: 400; + display: block; + padding: 4px 16px; + color: var(--sidebar-item-color) +} + +#navbar .sidebar-item,.sidebar-item.large { + padding: 8px 16px +} + +a.sidebar-item:focus,a.sidebar-item:hover { + color: var(--link-active-color); + text-decoration: none +} + +a.sidebar-item.active { + color: var(--link-active-color) +} + +ul.level1>li>a.sidebar-item { + background-color: transparent; + border-radius: 4px +} + +#toc ul.level1>li>a.sidebar-item.active { + background-color: var(--link-active-bg-color) +} + +.sidebar-item-separator { + height: 2px; + width: 100%; + background-color: var(--separator-color); + opacity: .8 +} + +span.sidebar-item { + font-weight: 700; + text-transform: uppercase; + font-size: .8em; + color: var(--text-color); + margin-block-start: 1.25em +} + +.main-panel { + background-color: var(--main-bg-color); + flex: 1; + overflow-x: hidden; +} + +.top-navbar { + display: flex; + flex-direction: row; + align-items: center; + background-color: var(--topbar-bg-color) +} + +.burger-icon { + color: var(--button-color) +} + +.burger-icon:focus,.burger-icon:hover { + color: var(--link-active-color) +} + +.burger-icon.active,.burger-icon:active { + color: var(--link-active-color) +} + +.brand { + display: flex; + align-items: center; + justify-content: start +} + +.logomark { + height: 28px +} + +.brand-title { + padding: 0 .5em; + font-size: .9em; + color: var(--link-active-color) +} + +.blackout,.footer { + background-color: var(--footer-bg-color) +} + +.footer { + margin: 0 20px 20px; + border-radius: 8px +} + +.blackout { + display: block; + visibility: hidden; + position: absolute; + z-index: 100; + bottom: 0; + left: 0; + right: 0 +} + +.showThat { + animation: showThat .5s forwards +} + +.hideThat { + animation: hideThat .5s forwards +} + +@media only screen and (min-width:1024px) { + nav { + position: fixed; + left: 0!important; + top: 0; + bottom: 0 + } + + .blackout,.top-navbar { + display: none + } +} + +.table-responsive { + overflow-x: auto +} + +table { + background-color: var(--code-bg-color); + border-collapse: collapse; + width: 100%; + table-layout: auto +} + +table.table-striped tbody tr:nth-child(2n) { + background-color: var(--table-strip-bg-color) +} + +table thead { + background: var(--table-header-bg-color) +} + +table th { + color: var(--table-header-color); + text-transform: uppercase; + line-height: 15px; + border-bottom: 1px solid var(--table-header-border-color); + font-size: 14px; + padding: 9px 10px +} + +.table-condensed th { + text-align: left +} + +table td { + padding: 6px 10px +} + +.mainContainer[dir=rtl] main ul[role=tablist],table td>p { + margin: 0 +} + +.alert,blockquote { + border-radius: 4px; + padding: 8px; + margin: 25px 0 +} + +.alert>h5 { + display: none; + margin: 0 +} + +.alert>p,blockquote>p { + margin: 0; + font-size: 13px +} + +.alert>p,table td { + font-weight: 300 +} + +.alert.alert-info { + border: 2px solid var(--alert-info-border-color); + background: var(--alert-info-bg-color) +} + +.alert.alert-warning { + border: 2px solid var(--alert-warning-border-color); + background: var(--alert-warning-bg-color) +} + +.alert.alert-danger { + border: 2px solid var(--alert-danger-border-color); + background: var(--alert-danger-bg-color) +} + +.TIP.alert.alert-info { + border: 2px solid var(--alert-tip-border-color); + background: var(--alert-tip-bg-color) +} + +blockquote { + margin: 8px 0; + border-left: 4px solid var(--blockquote-border-color); + background: var(--blockquote-bg-color) +} + +blockquote>p { + font-style: italic +} + +#breadcrumb { + padding: 8px 16px; + background: var(--breadcrumb-bg-color); + border-radius: 4px; + overflow: scroll; + margin-bottom: 0 +} + +#breadcrumb:empty { + display: none +} + +ul.breadcrumb { + display: flex; + flex-direction: row; + margin: 0 +} + +ul.breadcrumb>li { + margin-right: 6px +} + +ul.breadcrumb>li::before { + content: "/"; + margin-right: 5px +} + +ul.breadcrumb>li:first-child::before { + content: ""; + margin: 0 +} + +legend,pre { + display: block; + background-color: var(--code-bg-color); + border-radius: 4px; + padding: 6px +} + +.hljs { + background: 0 0 +} + +.small { + font-size: .9em +} + +.pull-right { + float: right +} + +#breadcrumb wbr,.hide,.sidetoc li>ul,ul.level1>li>.expand-stub { + display: none +} + +@media only screen and (max-width:1023.98px) { + .mobile-hide { + display: none + } +} + +li { + position: relative +} + +.expand-stub { + cursor: pointer; + position: absolute; + width: 20px; + height: 20px; + left: -10px +} + +.toc .nav>li.active>.expand-stub::before,.toc .nav>li>.expand-stub::before { + content: " "; + position: absolute; + transform: rotate(-90deg); + background-repeat: no-repeat; + background: url(down-arrow.svg) +} + +.toc .nav>li.active>.expand-stub::before,.toc .nav>li.filtered>.expand-stub::before,.toc .nav>li.in.active>.expand-stub::before,.toc .nav>li.in>.expand-stub::before { + transform: none +} + +li,li.in>ul { + display: block +} + +ul.level2>li>a.sidebar-item { + font-size: .95em; + padding: 0 +} + +ul.level3>li>a.sidebar-item { + padding: 0 +} + +ul.level2>li>a.sidebar-item:focus,ul.level2>li>a.sidebar-item:hover,ul.level3>li>a.sidebar-item:focus,ul.level3>li>a.sidebar-item:hover { + color: var(--link-active-color); + text-decoration: underline +} + +ul.level2>li>a.sidebar-item.active,ul.level3>li>a.sidebar-item.active { + color: var(--link-active-color) +} + +.inheritance div { + display: inline-block; +} + +.inheritance div:not(:last-child):after { + content: " → "; +} + +body { + font-size: var(--base-font-size) +} + +@media only screen and (max-width:1024px) { + body { + font-size: var(--smalldevice-base-font-size) + } +} + +h1,h2,h3,h4,h5 { + line-height: initial +} + +h1,h1:first-child { + font-size: 2.25em; + letter-spacing: .5px; + color: var(--h1-color); + margin-block-start: 1em; + margin-block-end: -.05em +} + +.article h1 { + margin-block-end: -.2em +} + +h2 { + font-size: 2.1em; + color: var(--h2-color) +} + +.article h2 { + margin-block-start: 1.3em; + padding-bottom: 6px; + border-bottom: 1px solid var(--separator-color) +} + +.article h3,h3 { + font-size: 1.95em; + font-weight: 500; + margin-block-start: 1.7em +} + +.article h3 { + font-size: 1.85em; + margin-block-start: 1.2em; + margin-block-end: .9em +} + +h4 { + font-size: 1.8em; + font-weight: 400; + margin-block-start: 2em; + padding-bottom: 10px +} + +.article h4 { + font-size: 1.5em; + font-weight: 300; + margin-block-start: 1em; + margin-block-end: 1em; + padding-bottom: 0; + border-bottom: none +} + +h5 { + font-size: 1.1em +} + +.article h5 { + font-size: 1.13em; + font-weight: 400; + text-decoration: underline; + margin-block-start: 1.5em; + margin-block-end: 1em +} + +a.brand:hover { + text-decoration: none +} + +a.brand .brand-title { + font-size: 1.4em; + font-weight: 500; + letter-spacing: .5px; + color: var(--appname-color); + margin-top: 1px; + padding: 0 0 0 .4em +} + +@media only screen and (min-width:1024px) { + a.brand .brand-title { + font-size: 1.55em + } +} + +a.brand .logomark { + height: 35px +} + +.top-navbar { + height: 60px; + padding: 0 0 0 10px +} + +.burger-icon { + margin-right: 10px +} + +.sidebar { + padding: 25px 17px 32px +} + +.blackout { + top: 60px +} + +@media only screen and (max-width:1023.98px) { + .navbar-nav { + margin-top: 0 + } +} + +nav { + width: 94%; + max-width: var(--sidebar-width); + left: calc(var(--sidebar-width)*-1) +} + +@media only screen and (max-width:1023.98px) { + nav { + top: 60px + } +} + +nav ul { + list-style-type: none +} + +nav .nav a,nav .nav a:hover { + text-decoration: none; + cursor: pointer; + display: block +} + +nav a.sidebar-item { + padding: 4px 0 4px 10px; + cursor: pointer +} + +.footer a:focus,.footer a:hover,nav a.sidebar-item:focus,nav a.sidebar-item:hover,nav a:focus { + text-decoration: underline +} + +nav a,nav a:focus,nav a:hover { + color: var(--sidebar-item-color)!important +} + +nav a.active,nav a.active:focus,nav a.active:hover { + color: var(--sidebar-active-item-color)!important +} + +.sidebar-item-separator { + margin: 20px 0 +} + +#toc ul li a { + padding: 0 0 0 10px +} + +.search { + background: var(--search-bg-color); + border: 1px solid var(--search-border-color); + border-radius: 5px; + position: relative; + margin-block-start: 25px +} + +@media (max-width:1023.98px) { + .search { + margin-block-start: 0; + margin-block-end: 15px + } +} + +.search>input { + font-size: .95em; + color: var(--search-color); + border: 0; + background: 0 0; + padding: 11px 30px 10px 37px; + width: 100% +} + +.search>input:focus,.toc-filter>input:focus { + outline: 0 +} + +.search>.search-icon,.toc-filter>.filter-icon { + font-size: 1.2em; + color: var(--search-searchicon-color); + position: absolute; + top: 9px; + left: 9px +} + +.toc-filter { + background: var(--toc-filter-bg-color); + border: 1px solid var(--toc-filter-border-color); + border-radius: 5px; + position: relative +} + +.toc-filter>input { + font-size: .95em; + color: var(--toc-filter-color); + border: 0; + background: 0 0; + padding: 11px 30px 10px 37px; + width: 100% +} + +.toc-filter>.filter-icon { + color: var(--toc-filter-filtericon-color) +} + +.toc-filter>.clear-icon { + color: var(--toc-filter-clearicon-color); + position: absolute; + top: 9px; + right: 9px; + cursor: pointer +} + +.toc .nav>li.active>.expand-stub::before,.toc .nav>li>.expand-stub::before { + width: 8px; + height: 8px; + top: 6px; + left: 6px +} + +#toc ul.level2 { + margin-bottom: 20px +} + +#toc ul.level1>li>a { + font-weight: 500; + margin-bottom: 10px; + padding: 5px 10px +} + +#toc ul.level1>li>a,#toc ul.level1>li>a.active { + background-color: var(--sidebar-level1-item-bg-color)!important; + border-radius: 2px +} + +#toc ul.level1>li>a.active:focus,#toc ul.level1>li>a.active:hover,#toc ul.level1>li>a:focus,#toc ul.level1>li>a:hover { + background-color: var(--sidebar-level1-item-hover-bg-color)!important; + text-decoration: none +} + +ul.level2 { + padding-inline-start: .7em +} + +ul.level2 .expand-stub { + top: 1px +} + +ul.level2>li>a,ul.level2>li>a.sidebar-item { + font-weight: 400; + color: var(--sidebar-item-color); + margin: 4px 0 +} + +ul.level3 { + padding-inline-start: 1em +} + +ul.level3>li>a,ul.level3>li>a.sidebar-item,ul.level4>li>a,ul.level4>li>a.sidebar-item { + font-size: 1.05em; + color: var(--sidebar-item-color); + margin: 4px 0 +} + +ul.level4 { + padding-inline-start: 0; + margin-bottom: 12px +} + +ul.level4>li>a,ul.level4>li>a.sidebar-item { + margin: 5px 0 5px 10px +} + +.subnav.navbar { + margin: 0-15px +} + +#breadcrumb::-webkit-scrollbar { + display: none +} + +#breadcrumb a { + white-space: nowrap +} + +#search-results h1 { + margin-block-start: .5em +} + +#search-results .item-title { + font-size: 1.3em; + margin-top: 1.5em +} + +#search-results .item-href { + font-size: .85em +} + +#search-results .item-brief { + margin-top: .7em +} + +#search-results ul.pagination { + text-align: center; + padding: 10px 0 0; + margin-block-start: 40px; + border-top: 1px solid var(--separator-color) +} + +#search-results ul.pagination>li { + display: inline-block; + margin: 0 10px +} + +#search-results ul.pagination>li.disabled a,#search-results ul.pagination>li.disabled a:hover { + color: var(--text-color); + cursor: txt; + text-decoration: none +} + +.main-panel { + margin-bottom: 60px; + padding: 20px +} + +@media only screen and (min-width:1024px) { + .main-panel { + margin-bottom: 0; + margin-left: var(--sidebar-width); + padding: 20px 40px + } +} + +.pull-right { + margin-top: 70px; + position: relative; + z-index: 1 +} + +.divider { + margin-left: 4px +} + +article ol li,article ul li { + margin-bottom: 10px +} + +.hljs { + color: var(--code-color) +} + +.hljs::-webkit-scrollbar { + height: 6px +} + +.hljs-built_in,.hljs-keyword,.hljs-title { + font-style: normal +} + +code,p .xref { + background-color: var(--ref-bg-color); + color: var(--ref-color); + padding: 2px 3px; + font-size: .95em; + border-radius: 6px +} + +code,p .xref,span.parametername { + font-family: monospace +} + +.table { + width: auto +} + +.table-responsive { + margin-bottom: 0 +} + +table td p { + font-weight: 300 +} + +.footer { + text-align: center; + color: var(--text-color); + padding: 10px +} + +.copyright-footer { + font-size: .85em; + font-weight: 700; + text-align: center; + margin-block-start: 30px +} + +.contribution { + float: right; + margin-top: 1.1em; + position: relative; + z-index: 999 +} + +.tabGroup { + margin-top: 1rem; + margin-bottom: 1rem +} + +.tabGroup ul[role=tablist] { + margin: 0; + padding: 0; + list-style: none; + border-bottom: var(--nav-tabs-border-width) solid var(--nav-tabs-border-color) +} + +.tabGroup ul[role=tablist]>li { + list-style: none; + display: inline-block; + margin-bottom: 0 +} + +.tabGroup ul[role=tablist] .dropdown-menu { + margin-top: calc(-1*var(--nav-tabs-border-width)); + border-top-left-radius: 0; + border-top-right-radius: 0 +} + +.tabGroup a[role=tab] { + display: block; + text-decoration: none; + padding: .5rem 1rem; + margin-bottom: calc(-1*var(--nav-tabs-border-width)); + border: var(--nav-tabs-border-width) solid transparent; + border-top-left-radius: var(--nav-tabs-border-radius); + border-top-right-radius: var(--nav-tabs-border-radius) +} + +.tabGroup a[role=tab]:focus,.tabGroup a[role=tab]:hover { + isolation: isolate; + border-color: var(--nav-tabs-link-hover-border-color) +} + +.tabGroup a[role=tab][aria-selected=true] { + color: var(--nav-tabs-link-active-color); + background-color: var(--nav-tabs-link-active-bg); + border-color: var(--nav-tabs-link-active-border-color) +} + +.tabGroup a[role=tab]:disabled { + color: var(--nav-link-disabled-color); + background-color: transparent; + border-color: transparent +} + +.tabGroup section[role=tabpanel] { + padding: 15px; + margin: 0; + overflow: hidden; + border: var(--nav-tabs-border-width) solid var(--nav-tabs-border-color); + border-top: none; + border-bottom-left-radius: var(--nav-tabs-border-radius); + border-bottom-right-radius: var(--nav-tabs-border-radius) +} + +.tabGroup section[role=tabpanel]>.codeHeader,.tabGroup section[role=tabpanel]>pre { + margin-left: -16px; + margin-right: -16px +} + +.tabGroup section[role=tabpanel]>:first-child { + margin-top: 0 +} + +.tabGroup section[role=tabpanel]>pre:last-child { + display: block; + margin-bottom: -16px +} + +.tabGroup>section { + margin: 0; + padding: 1rem; + border-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0 +} \ No newline at end of file diff --git a/doc/templates/singulinkfx/styles/singulink.js b/doc/templates/singulinkfx/styles/singulink.js new file mode 100644 index 0000000..07cda60 --- /dev/null +++ b/doc/templates/singulinkfx/styles/singulink.js @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information. + +function toggleMenu() { + + var sidebar = document.getElementById("sidebar"); + var blackout = document.getElementById("blackout"); + + if (sidebar.style.left === "0px") + { + sidebar.style.left = "-" + sidebar.getBoundingClientRect().width + "px"; + blackout.classList.remove("showThat"); + blackout.classList.add("hideThat"); + } + else + { + sidebar.style.left = "0px"; + blackout.classList.remove("hideThat"); + blackout.classList.add("showThat"); + } +} + +// jQuery .deepest(): https://gist.github.com/geraldfullam/3a151078b55599277da4 + +(function ($) { + $.fn.deepest = function (selector) { + var deepestLevel = 0, + $deepestChild, + $deepestChildSet; + + this.each(function () { + $parent = $(this); + $parent + .find((selector || '*')) + .each(function () { + if (!this.firstChild || this.firstChild.nodeType !== 1) { + var levelsToParent = $(this).parentsUntil($parent).length; + if (levelsToParent > deepestLevel) { + deepestLevel = levelsToParent; + $deepestChild = $(this); + } else if (levelsToParent === deepestLevel) { + $deepestChild = !$deepestChild ? $(this) : $deepestChild.add(this); + } + } + }); + $deepestChildSet = !$deepestChildSet ? $deepestChild : $deepestChildSet.add($deepestChild); + }); + + return this.pushStack($deepestChildSet || [], 'deepest', selector || ''); + }; +}(jQuery)); + +$(function() { + $('table').each(function(a, tbl) { + var currentTableRows = $(tbl).find('tbody tr').length; + $(tbl).find('th').each(function(i) { + var remove = 0; + var currentTable = $(this).parents('table'); + + var tds = currentTable.find('tr td:nth-child(' + (i + 1) + ')'); + tds.each(function(j) { if ($(this).text().trim() === '') remove++; }); + + if (remove == currentTableRows) { + $(this).hide(); + tds.hide(); + } + }); + }); + + function scrollToc() { + var activeTocItem = $('.sidebar').deepest('.sidebar-item.active')[0] + + if (activeTocItem) { + activeTocItem.scrollIntoView({ block: "center" }); + } + else{ + setTimeout(scrollToc, 500); + } + } + + setTimeout(scrollToc, 500); +}); \ No newline at end of file diff --git a/doc/templates/singulinkfx/styles/url.min.js b/doc/templates/singulinkfx/styles/url.min.js new file mode 100644 index 0000000..8057e0a --- /dev/null +++ b/doc/templates/singulinkfx/styles/url.min.js @@ -0,0 +1 @@ +/*! url - v1.8.6 - 2013-11-22 */window.url=function(){function a(a){return!isNaN(parseFloat(a))&&isFinite(a)}return function(b,c){var d=c||window.location.toString();if(!b)return d;b=b.toString(),"//"===d.substring(0,2)?d="http:"+d:1===d.split("://").length&&(d="http://"+d),c=d.split("/");var e={auth:""},f=c[2].split("@");1===f.length?f=f[0].split(":"):(e.auth=f[0],f=f[1].split(":")),e.protocol=c[0],e.hostname=f[0],e.port=f[1]||("https"===e.protocol.split(":")[0].toLowerCase()?"443":"80"),e.pathname=(c.length>3?"/":"")+c.slice(3,c.length).join("/").split("?")[0].split("#")[0];var g=e.pathname;"/"===g.charAt(g.length-1)&&(g=g.substring(0,g.length-1));var h=e.hostname,i=h.split("."),j=g.split("/");if("hostname"===b)return h;if("domain"===b)return/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/.test(h)?h:i.slice(-2).join(".");if("sub"===b)return i.slice(0,i.length-2).join(".");if("port"===b)return e.port;if("protocol"===b)return e.protocol.split(":")[0];if("auth"===b)return e.auth;if("user"===b)return e.auth.split(":")[0];if("pass"===b)return e.auth.split(":")[1]||"";if("path"===b)return e.pathname;if("."===b.charAt(0)){if(b=b.substring(1),a(b))return b=parseInt(b,10),i[0>b?i.length+b:b-1]||""}else{if(a(b))return b=parseInt(b,10),j[0>b?j.length+b:b]||"";if("file"===b)return j.slice(-1)[0];if("filename"===b)return j.slice(-1)[0].split(".")[0];if("fileext"===b)return j.slice(-1)[0].split(".")[1]||"";if("?"===b.charAt(0)||"#"===b.charAt(0)){var k=d,l=null;if("?"===b.charAt(0)?k=(k.split("?")[1]||"").split("#")[0]:"#"===b.charAt(0)&&(k=k.split("#")[1]||""),!b.charAt(1))return k;b=b.substring(1),k=k.split("&");for(var m=0,n=k.length;n>m;m++)if(l=k[m].split("="),l[0]===b)return l[1]||"";return null}}return""}}(),"undefined"!=typeof jQuery&&jQuery.extend({url:function(a,b){return window.url(a,b)}}); \ No newline at end of file diff --git a/doc/templates/singulinkfx/toc.html.primary.tmpl b/doc/templates/singulinkfx/toc.html.primary.tmpl new file mode 100644 index 0000000..f4deb5e --- /dev/null +++ b/doc/templates/singulinkfx/toc.html.primary.tmpl @@ -0,0 +1,22 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +
      +
      + {{^_disableSideFilter}} +
      +
      + + + +
      +
      + {{/_disableSideFilter}} +
      +
      + {{^leaf}} + {{>partials/li}} + {{/leaf}} +
      +
      +
      +
      diff --git a/doc/toc.yml b/doc/toc.yml index 6b7182d..91d402c 100644 --- a/doc/toc.yml +++ b/doc/toc.yml @@ -1,5 +1,7 @@ # yaml-language-server: $schema=https://raw.githubusercontent.com/dotnet/docfx/main/schemas/toc.schema.json -- name: Documentation and Tutorials +- name: Home + href: index.md +- name: "Documentation & Tutorials" href: articles/ - name: API href: api/ diff --git a/src/.vscode/launch.json b/src/.vscode/launch.json index 37c732b..6efab40 100644 --- a/src/.vscode/launch.json +++ b/src/.vscode/launch.json @@ -1,14 +1,14 @@ { // Use IntelliSense to find out which attributes exist for C# debugging // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/main/debugger-launchjson.md "version": "0.2.0", "configurations": [ { // Use IntelliSense to find out which attributes exist for C# debugging // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "name": "Uno Platform Desktop Debug", + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/main/debugger-launchjson.md + "name": "Uno Platform Desktop Debug (MvuxGallery)", "type": "coreclr", "request": "launch", "preLaunchTask": "build-desktop", @@ -24,5 +24,25 @@ "console": "internalConsole", "stopAtEntry": false }, + { + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/main/debugger-launchjson.md + "name": "Uno Platform Desktop Debug (XamlNavigationApp)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build-desktop", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/DevTKSS.Uno.XamlNavigationApp-1/bin/Debug/net9.0-desktop/DevTKSS.Uno.XamlNavigationApp.dll", + "args": [], + "launchSettingsProfile": "DevTKSS.Uno.XamlNavigationApp (Desktop)", + "env": { + "DOTNET_MODIFIABLE_ASSEMBLIES": "debug" + }, + "cwd": "${workspaceFolder}/DevTKSS.Uno.XamlNavigationApp-1", + // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console + "console": "internalConsole", + "stopAtEntry": false + }, ] } \ No newline at end of file diff --git a/src/.vscode/tasks.json b/src/.vscode/tasks.json index daba540..2614aac 100644 --- a/src/.vscode/tasks.json +++ b/src/.vscode/tasks.json @@ -2,7 +2,7 @@ "version": "2.0.0", "tasks": [ { - "label": "build-desktop", + "label": "build-desktop MvuxGallery", "command": "dotnet", "type": "process", "args": [ @@ -15,7 +15,7 @@ "problemMatcher": "$msCompile" }, { - "label": "publish-desktop", + "label": "publish-desktop MvuxGallery", "command": "dotnet", "type": "process", "args": [ @@ -26,6 +26,32 @@ "/consoleloggerparameters:NoSummary" ], "problemMatcher": "$msCompile" + }, + { + "label": "build-desktop XamlNavigationApp", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/DevTKSS.Uno.XamlNavigationApp-1/DevTKSS.Uno.XamlNavigationApp.csproj", + "/property:GenerateFullPaths=true", + "/property:TargetFramework=net9.0-desktop", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "publish-desktop XamlNavigationApp", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/DevTKSS.Uno.XamlNavigationApp-1/DevTKSS.Uno.XamlNavigationApp.csproj", + "/property:GenerateFullPaths=true", + "/property:TargetFramework=net9.0-desktop", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" } ] } \ No newline at end of file diff --git a/src/DevTKSS.Extensions.Uno.Storage/EnumerableExtensions.string.cs b/src/DevTKSS.Extensions.Uno.Storage/EnumerableExtensions.string.cs index a9817ba..0df96fe 100644 --- a/src/DevTKSS.Extensions.Uno.Storage/EnumerableExtensions.string.cs +++ b/src/DevTKSS.Extensions.Uno.Storage/EnumerableExtensions.string.cs @@ -70,14 +70,14 @@ public static string GetItemsWithinRange(this IEnumerable sourceItems, ( return string.Empty; } - var baseItem = isNullBased ? 0 : 1; + var resultBase = isNullBased ? 0 : 1; var startIndex = Math.Clamp( - value: range.Start - baseItem, - min: baseItem, + value: range.Start - resultBase, + min: 0, max: list.Count); var endIndex = Math.Clamp( - value: range.End - baseItem, + value: range.End - resultBase, min: startIndex, max: list.Count); // Ensure 'End' does not exceed available lines diff --git a/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs b/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs index b2c283b..121a997 100644 --- a/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs +++ b/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/CodeSampleService.cs @@ -39,25 +39,16 @@ public void UpdateOptions(CodeSampleOptions newOptions, string? changedOption) } /// - /// Get a static Collection of Values for + /// Retrieves a static collection of values for . /// - /// - /// A CancellationToken to make it compileable - /// - /// since `ListFeed.Async` requires a CancellationToken even if Uno Documentation remarks this parameter to be optional.
      - /// CS0411
      - ///
      - /// adding then the type string or IImmutableList to the ListFeed like `ListFeed.Async(...)`, - /// or to the Async Extension itself like `ListFeed.Async` results in a type mismatch.
      - /// CS1503 - ///
      - /// An awaitable providing a of with the Sample Names to select from + /// A to make the method compileable. + /// An awaitable providing an of with the sample names to select from. public async ValueTask> GetCodeSampleOptionsAsync(CancellationToken ct = default) { await Task.Delay(1, ct); _logger.LogTrace("Collecting available code sample options for '{ServiceName}' from configuration...", Name ); var sampleOptions = _options.Samples.Select(sample => sample.SampleID).ToImmutableList(); - + if (_logger.IsEnabled(LogLevel.Debug)) { // Log available options @@ -72,6 +63,12 @@ public async ValueTask> GetCodeSampleOptionsAsync(Cancell return sampleOptions; } + /// + /// Retrieves the code sample content based on the provided sample ID. + /// + /// The unique identifier for the code sample to fetch. + /// A cancellation token for the operation. + /// An awaitable containing the code sample content as a . public async ValueTask GetCodeSampleAsync(string? sampleID, CancellationToken ct = default) { if (_options.Samples.FirstOrDefault(sample => sample.SampleID == sampleID) is CodeSample sampleOption) diff --git a/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/ServiceCollectionExtension.cs b/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/ServiceCollectionExtension.cs index 67d0c1c..efeea7e 100644 --- a/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/ServiceCollectionExtension.cs +++ b/src/DevTKSS.Uno.Samples.MvuxGallery/Models/CodeSamples/ServiceCollectionExtension.cs @@ -13,7 +13,7 @@ public static class ServiceCollectionExtension /// The optional configuration section name. If not provided, is used. /// The for chaining. /// - /// This method assumes configuration for the named is provided (e.g., via UseConfiguration().Section()). + /// This method assumes configuration for the named is provided (e.g., via UseConfiguration().Section<T>()). /// It registers a keyed singleton that consumes those named options. /// public static IServiceCollection AddKeyedSingletonCodeService(this IServiceCollection services, string serviceName, string? sectionName = null) diff --git a/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs b/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs index 475819a..784f04a 100644 --- a/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs +++ b/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/DashboardModel.cs @@ -27,37 +27,35 @@ public DashboardModel( public IListFeed GalleryImagesWithResw => ListFeed.Async(_galleryImageService.GetGalleryImagesWithReswAsync); #region CodeSample import directly in the Model - /// + /// /// Holds a static Collection of to bind to - /// + /// /// /// Projects the selected item to /// public IListFeed CodeSampleOptions => ListFeed.Async(GetCodeSampleOptionsAsync) .Selection(SelectedOption); - /// + /// /// Represents the selected item in the - /// + /// /// /// Executes when the selected item changes /// public IState SelectedOption => State.Value(this, () => "FeedView + GridView XAML") .ForEach(SwitchCodeSampleAsync); - /// + /// /// Represents the currently selected code sample to bind to and default to an empty string - /// + /// public IState CurrentCodeSample => State.Value(this, () => string.Empty); /// - /// Get a static Collection of Values for + /// Retrieves a static collection of values for . /// - /// - /// A as the FeedList.Async requires a CancellationToken - /// - /// The available Values to select from. + /// A to make the method compileable. + /// An awaitable providing an of with the sample names to select from. public static async ValueTask> GetCodeSampleOptionsAsync(CancellationToken ct = default) { // since `ListFeed.Async` requires a CancellationToken even if Uno Documentation remarks this parameter to be optional.< br /> @@ -89,6 +87,9 @@ public static async ValueTask> GetCodeSampleOptionsAsync( /// A ValueTask to be awaited /// /// Uses switch expression to select the correct code sample which provides better performance and less boilerplate code. + /// + /// The switch expression maps the selected option to the corresponding code sample file path. If the selected option does not match any predefined cases, it defaults to an empty string. + /// /// public async ValueTask SwitchCodeSampleAsync([FeedParameter(nameof(SelectedOption))] string? selectedOption, CancellationToken ct = default) { diff --git a/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs b/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs index 26c6df7..928dae9 100644 --- a/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs +++ b/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/ListboardModel.cs @@ -54,7 +54,9 @@ public ListboardModel( /// Represents a static collection of code sample options to bind to. /// /// - /// The ListFeed is generic (`ListFeed.Async`) and the service function returns a collection of strings. + /// The `CodeSampleOptions` property provides a feed of selectable code sample options. + /// It uses the `ListFeed.Async` method to asynchronously retrieve the options from the sample service. + /// The selected option is projected to for further processing. /// public IListFeed CodeSampleOptions => ListFeed.Async(_sampleService.GetCodeSampleOptionsAsync) .Selection(SelectedOption); diff --git a/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs b/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs index 2a23e40..002e3e7 100644 --- a/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs +++ b/src/DevTKSS.Uno.Samples.MvuxGallery/Presentation/ViewModels/MainModel.cs @@ -1,4 +1,5 @@ namespace DevTKSS.Uno.Samples.MvuxGallery.Presentation.ViewModels; + public partial record MainModel { private readonly IStringLocalizer _stringLocalizer; @@ -40,7 +41,7 @@ public async ValueTask UpdateCurrentHeaderAsync([FeedParameter(nameof(CurrentNot } else { - _logger.LogTrace("{CurrentNotifierRoute} was empty, setting default header using 'WelcomeGreeting' Key",nameof(currentNotifierRoute)); + _logger.LogTrace("{CurrentNotifierRoute} was empty, setting default header using 'WelcomeGreeting' Key", nameof(currentNotifierRoute)); await CurrentHeader.SetAsync(_stringLocalizer["WelcomeGreeting"]); } } diff --git a/src/DevTKSS.Uno.Samples.MvuxGallery/ReadMe.md b/src/DevTKSS.Uno.Samples.MvuxGallery/ReadMe.md index 93482da..c9f2b75 100644 --- a/src/DevTKSS.Uno.Samples.MvuxGallery/ReadMe.md +++ b/src/DevTKSS.Uno.Samples.MvuxGallery/ReadMe.md @@ -1,7 +1,24 @@ -# Getting Started +# DevTKSS.Uno.Samples.MvuxGallery -Welcome to the Uno Platform! +Welcome to the MvuxGallery App powered by the Uno Platform! -To discover how to get started with your new app: https://aka.platform.uno/get-started +This app showcases various features and controls available in the Uno Platform, particularly focusing on the Mvux (Model-View-Update) architecture. -For more information on how to use the Uno.Sdk or upgrade Uno Platform packages in your solution: https://aka.platform.uno/using-uno-sdk \ No newline at end of file +The MvuxGallery is designed to help developers understand how to implement Mvux in their applications, providing a hands-on experience with sample code and interactive examples. + +## Target Audience + +This App is part of the DevTKSS.Uno.SampleApps repository, which targets to provide a collection of Uno Platform sample applications, but also localized Community Tutorials, sampling and explaining how to do those things you can explore in the included samples. + +You are not required to have any prior knowledge of the Uno Platform or Mvux to use this app, but basic familiarity with C# and XAML will be beneficial for understanding the examples and concepts presented. + +## Documentation and Tutorials of the DevTKSS.Uno.SampleApps + +* [Discover the DevTKSS.Uno.SampleApps Repository on GitHub](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps) +* [Explore the DevTKSS.Uno.SampleApps Documentation in the Browser](https://devtkss.github.io/DevTKSS.Uno.SampleApps/doc) + +## Official Documentation links + +To discover how to get started with Uno App development, check out: https://aka.platform.uno/get-started + +For more information on how to use the Uno.Sdk or upgrade Uno Platform packages in your solution: https://aka.platform.uno/using-uno-sdk diff --git a/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardModel.cs b/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardModel.cs index 6f1a411..239d52e 100644 --- a/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardModel.cs +++ b/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardModel.cs @@ -3,7 +3,7 @@ public partial record DashboardModel { public DashboardModel() { - + } private async ValueTask> GetMembers(CancellationToken ct) => _listMembers; diff --git a/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardPage.xaml b/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardPage.xaml index d9b0f68..1487e5f 100644 --- a/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardPage.xaml +++ b/src/DevTKSS.Uno.XamlNavigationApp-1/Presentation/DashboardPage.xaml @@ -6,7 +6,6 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:utu="using:Uno.Toolkit.UI" - xmlns:mvux="using:Uno.Extensions.Reactive.UI" mc:Ignorable="d" Background="{ThemeResource BackgroundBrush}"> diff --git a/src/DevTKSS.Uno.XamlNavigationApp-1/Properties/launchSettings.json b/src/DevTKSS.Uno.XamlNavigationApp-1/Properties/launchSettings.json index 7f16533..0377b5c 100644 --- a/src/DevTKSS.Uno.XamlNavigationApp-1/Properties/launchSettings.json +++ b/src/DevTKSS.Uno.XamlNavigationApp-1/Properties/launchSettings.json @@ -14,7 +14,7 @@ }, "DevTKSS.Uno.XamlNavigationApp (Desktop WSL2)": { "commandName": "WSL2", - "commandLineArgs": "{ProjectDir}/bin/Debug/net9.0-desktop/UnoApp2.dll", + "commandLineArgs": "{ProjectDir}/bin/Debug/net9.0-desktop/DevTKSS.Uno.XamlNavigationApp.dll", "distributionName": "", "compatibleTargetFramework": "desktop" } diff --git a/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.de.md b/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.de.md new file mode 100644 index 0000000..6b0e280 --- /dev/null +++ b/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.de.md @@ -0,0 +1,26 @@ +--- +uid: DevTKSS.Uno.SampleApps.Mvux.XamlNavigationApp +--- + +# DevTKSS.Uno.SampleApps.Mvux.XamlNavigationApp.de + +Willkommen bei der Uno Platform und insbesondere bei diesem Community-Tutorial-Beispiel! + +## Erste Schritte + +Wie du mit deiner neuen App loslegst: [Link zur Uno Doku `Getting Started`](https://aka.platform.uno/get-started) + +Weitere Informationen zur Verwendung des Uno.Sdk oder zum Aktualisieren der Uno Platform-Pakete in deiner Lösung: [Das Uno.Sdk benutzen](https://aka.platform.uno/using-uno-sdk) + +## Tutorial zum Mitmachen + +Diese Beispiel-App ist Teil eines Community-Tutorial-Videos, das dich durch den Prozess des Aufbaus einer XAML-Navigations-App mit der Uno Platform führt. + +Bitte wähle die Sprache deiner Wahl, um dem Tutorial zu folgen: + +- [Deutsch](../../doc/articles/de/Navigation/Extensions-Navigation-de.md) +- [Englisch](../../doc/articles/en/Navigation/HowTo-Defining-UI-NavigationView-en.md) + +## Mitwirken + +Wenn du zu diesem Beispiel beitragen möchtest, wirf einen Blick auf das [GitHub repository](https://github.com/DevTKSS/DevTKSS.Uno.SampleApps) diff --git a/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.en.md b/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.en.md new file mode 100644 index 0000000..6eeb1af --- /dev/null +++ b/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.en.md @@ -0,0 +1,26 @@ +--- +uid: DevTKSS.Uno.SampleApps.Mvux.XamlNavigationApp +--- + +# DevTKSS.Uno.SampleApps.Mvux.XamlNavigationApp.en + +Welcome to the Uno Platform and particularly this Community Tutorial Sample! + +## Getting Started + +To discover how to get started with your new app: [Link to the Uno `Getting Started`](https://aka.platform.uno/get-started) + +For more information on how to use the Uno.Sdk or upgrade Uno Platform packages in your solution: [Using the Uno.Sdk](https://aka.platform.uno/using-uno-sdk) + +## Tutorial to follow along with this sample + +This sample app is part of a Community Tutorial Video that will guide you through the process of building a XAML Navigation App using the Uno Platform. + +Please select the language of your choice to follow along: + +- [English](../../doc/articles/en/Navigation/HowTo-Defining-UI-NavigationView-en.md) +- [German](../../doc/articles/de/Navigation/Extensions-Navigation-de.md) + +## Contributing + +If you want to contribute to this sample, please check out the [GitHub repository](www.github.com/DevTKSS/DevTKSS.Uno.SampleApps) diff --git a/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.md b/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.md deleted file mode 100644 index 93482da..0000000 --- a/src/DevTKSS.Uno.XamlNavigationApp-1/ReadMe.md +++ /dev/null @@ -1,7 +0,0 @@ -# Getting Started - -Welcome to the Uno Platform! - -To discover how to get started with your new app: https://aka.platform.uno/get-started - -For more information on how to use the Uno.Sdk or upgrade Uno Platform packages in your solution: https://aka.platform.uno/using-uno-sdk \ No newline at end of file diff --git a/src/global.json b/src/global.json index e268f19..17ed574 100644 --- a/src/global.json +++ b/src/global.json @@ -1,6 +1,6 @@ { "msbuild-sdks": { - "Uno.Sdk": "6.2.29" + "Uno.Sdk": "6.3.28" }, "sdk": { "allowPrerelease": false