Browse Source

Code style updates

Daniel Chalmers 3 years ago
parent
commit
771ff6c9be

+ 225 - 0
.editorconfig

@@ -0,0 +1,225 @@
+# Remove the line below if you want to inherit .editorconfig settings from higher directories
+root = true
+
+# C# files
+[*.cs]
+
+#### Core EditorConfig Options ####
+
+# Indentation and spacing
+indent_size = 4
+indent_style = space
+tab_width = 4
+
+# New line preferences
+end_of_line = crlf
+insert_final_newline = false
+
+#### .NET Coding Conventions ####
+
+# Organize usings
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+file_header_template = unset
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = false:suggestion
+dotnet_style_qualification_for_field = false
+dotnet_style_qualification_for_method = false:suggestion
+dotnet_style_qualification_for_property = false:suggestion
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:error
+dotnet_style_predefined_type_for_member_access = true:error
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members
+
+# Expression-level preferences
+dotnet_style_coalesce_expression = true
+dotnet_style_collection_initializer = true:silent
+dotnet_style_explicit_tuple_names = true:warning
+dotnet_style_namespace_match_folder = true
+dotnet_style_null_propagation = true
+dotnet_style_object_initializer = true:silent
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:suggestion
+dotnet_style_prefer_compound_assignment = true
+dotnet_style_prefer_conditional_expression_over_assignment = true
+dotnet_style_prefer_conditional_expression_over_return = true
+dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:silent
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true
+dotnet_style_prefer_simplified_boolean_expressions = true
+dotnet_style_prefer_simplified_interpolation = true
+
+# Field preferences
+dotnet_style_readonly_field = true:warning
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = non_public:warning
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+# New line preferences
+dotnet_style_allow_multiple_blank_lines_experimental = false
+dotnet_style_allow_statement_immediately_after_block_experimental = false
+
+#### C# Coding Conventions ####
+
+# var preferences
+csharp_style_var_elsewhere = true:suggestion
+csharp_style_var_for_built_in_types = true:suggestion
+csharp_style_var_when_type_is_apparent = true:suggestion
+
+# Expression-bodied members
+csharp_style_expression_bodied_accessors = true
+csharp_style_expression_bodied_constructors = false
+csharp_style_expression_bodied_indexers = true
+csharp_style_expression_bodied_lambdas = true
+csharp_style_expression_bodied_local_functions = true
+csharp_style_expression_bodied_methods = true
+csharp_style_expression_bodied_operators = true
+csharp_style_expression_bodied_properties = true
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_as_with_null_check = true
+csharp_style_pattern_matching_over_is_with_cast_check = true
+csharp_style_prefer_extended_property_pattern = true
+csharp_style_prefer_not_pattern = true
+csharp_style_prefer_pattern_matching = true:suggestion
+csharp_style_prefer_switch_expression = true
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true
+csharp_style_prefer_parameter_null_checking = false:error
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:warning
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
+
+# Code-block preferences
+csharp_prefer_braces = when_multiline:warning
+csharp_prefer_simple_using_statement = true:silent
+csharp_style_namespace_declarations = file_scoped
+csharp_style_prefer_method_group_conversion = true
+csharp_style_prefer_top_level_statements = true
+
+# Expression-level preferences
+csharp_prefer_simple_default_expression = true
+csharp_style_deconstructed_variable_declaration = true
+csharp_style_implicit_object_creation_when_type_is_apparent = true
+csharp_style_inlined_variable_declaration = true
+csharp_style_prefer_index_operator = true
+csharp_style_prefer_local_over_anonymous_function = true
+csharp_style_prefer_null_check_over_type_check = true:warning
+csharp_style_prefer_range_operator = true
+csharp_style_prefer_tuple_swap = true:silent
+csharp_style_throw_expression = true
+csharp_style_unused_value_assignment_preference = discard_variable:warning
+csharp_style_unused_value_expression_statement_preference = discard_variable
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:error
+
+# New line preferences
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false
+csharp_style_allow_embedded_statements_on_same_line_experimental = false:warning
+
+#### 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
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+
+#### Naming styles ####
+
+# 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_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# 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.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers = 
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers = 
+
+# Naming styles
+
+dotnet_naming_style.pascal_case.required_prefix = 
+dotnet_naming_style.pascal_case.required_suffix = 
+dotnet_naming_style.pascal_case.word_separator = 
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix = 
+dotnet_naming_style.begins_with_i.word_separator = 
+dotnet_naming_style.begins_with_i.capitalization = pascal_case

+ 0 - 63
.gitattributes

@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs     diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following 
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln       merge=binary
-#*.csproj    merge=binary
-#*.vbproj    merge=binary
-#*.vcxproj   merge=binary
-#*.vcproj    merge=binary
-#*.dbproj    merge=binary
-#*.fsproj    merge=binary
-#*.lsproj    merge=binary
-#*.wixproj   merge=binary
-#*.modelproj merge=binary
-#*.sqlproj   merge=binary
-#*.wwaproj   merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg   binary
-#*.png   binary
-#*.gif   binary
-
-###############################################################################
-# diff behavior for common document formats
-# 
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the 
-# entries below.
-###############################################################################
-#*.doc   diff=astextplain
-#*.DOC   diff=astextplain
-#*.docx  diff=astextplain
-#*.DOCX  diff=astextplain
-#*.dot   diff=astextplain
-#*.DOT   diff=astextplain
-#*.pdf   diff=astextplain
-#*.PDF   diff=astextplain
-#*.rtf   diff=astextplain
-#*.RTF   diff=astextplain

+ 1 - 1
DesktopClock/App.xaml

@@ -3,5 +3,5 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              Exit="Application_Exit"
              StartupUri="MainWindow.xaml">
-    <Application.Resources />
+	<Application.Resources />
 </Application>

+ 3 - 5
DesktopClock/DesktopClock.csproj

@@ -1,19 +1,17 @@
-<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
     <OutputType>WinExe</OutputType>
     <TargetFramework>net48</TargetFramework>
     <UseWPF>true</UseWPF>
-    <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
+    <LangVersion>latest</LangVersion>
     <ApplicationIcon>DesktopClock.ico</ApplicationIcon>
   </PropertyGroup>
 
   <PropertyGroup>
     <Company>Daniel Chalmers</Company>
     <Description>A configurable clock for your desktop</Description>
-    <PackageLicenseExpression>MIT</PackageLicenseExpression>
-    <RepositoryUrl>https://github.com/danielchalmers/DesktopClock</RepositoryUrl>
-    <Copyright>© Daniel Chalmers 2021</Copyright>
+    <Copyright>© Daniel Chalmers</Copyright>
     <Version>2.0.0</Version>
   </PropertyGroup>
 

+ 131 - 141
DesktopClock/MainWindow.xaml

@@ -21,145 +21,135 @@
         WindowStyle="None"
         wp:WindowPlacementProperties.Placement="{Binding Placement, Source={x:Static p:Settings.Default}}"
         wp:WindowPlacementProperties.TrackPlacement="True">
-    <Window.DataContext>
-        <local:MainViewModel />
-    </Window.DataContext>
-
-    <Window.ContextMenu>
-        <ContextMenu>
-            <MenuItem Click="MenuItemCopy_OnClick"
-                      Header="_Copy" />
-
-            <Separator />
-
-            <MenuItem Header="Stay on _top"
-                      IsCheckable="True"
-                      IsChecked="{Binding Topmost, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
-
-            <MenuItem Header="Show tas_kbar icon"
-                      IsCheckable="True"
-                      IsChecked="{Binding ShowInTaskbar, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
-
-            <MenuItem Header="Show _background"
-                      IsCheckable="True"
-                      IsChecked="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
-
-            <MenuItem>
-                <MenuItem.Header>
-                    <StackPanel Orientation="Horizontal">
-                        <TextBlock Text="Size: " />
-
-                        <Slider Width="80"
-                                AutoToolTipPlacement="TopLeft"
-                                IsSnapToTickEnabled="True"
-                                Maximum="160"
-                                Minimum="16"
-                                TickFrequency="4"
-                                Value="{Binding Height, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
-                    </StackPanel>
-                </MenuItem.Header>
-            </MenuItem>
-
-            <MenuItem Header="T_heme"
-                      ItemsSource="{x:Static local:App.Themes}">
-                <MenuItem.Resources>
-                    <Style TargetType="MenuItem">
-                        <Setter Property="Command" Value="{Binding DataContext.SetThemeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
-
-                        <Setter Property="CommandParameter" Value="{Binding}" />
-
-                        <Setter Property="DisplayMemberPath" Value="Name" />
-                    </Style>
-                </MenuItem.Resources>
-            </MenuItem>
-
-            <MenuItem Header="Time _Zone"
-                      ItemsSource="{x:Static local:DateTimeUtil.TimeZones}">
-                <MenuItem.Resources>
-                    <Style TargetType="MenuItem">
-                        <Setter Property="Command" Value="{Binding DataContext.SetTimeZoneCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
-
-                        <Setter Property="CommandParameter" Value="{Binding}" />
-                    </Style>
-                </MenuItem.Resources>
-            </MenuItem>
-
-            <MenuItem Header="_Format"
-                      ItemsSource="{x:Static local:DateTimeUtil.DateTimeFormatsAndExamples}">
-                <MenuItem.Resources>
-                    <Style TargetType="MenuItem">
-                        <Setter Property="Command" Value="{Binding DataContext.SetFormatCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
-
-                        <Setter Property="CommandParameter" Value="{Binding Key}" />
-
-                        <Setter Property="DisplayMemberPath" Value="Value" />
-                    </Style>
-                </MenuItem.Resources>
-            </MenuItem>
-
-            <Separator />
-
-            <MenuItem Click="MenuItemSettings_OnClick"
-                      Header="_Settings..." />
-
-            <MenuItem Click="MenuItemCheckForUpdates_OnClick"
-                      Header="Check for _updates..." />
-
-            <MenuItem Click="MenuItemExit_OnClick"
-                      Header="E_xit" />
-        </ContextMenu>
-    </Window.ContextMenu>
-
-    <Viewbox Height="{Binding Height, Source={x:Static p:Settings.Default}, Mode=OneWay}">
-        <Border CornerRadius="2">
-            <Border.Style>
-                <Style TargetType="Border">
-                    <Setter Property="Background">
-                        <Setter.Value>
-                            <SolidColorBrush Opacity="{Binding BackgroundOpacity, Source={x:Static p:Settings.Default}, Mode=OneWay}"
-                                 Color="{Binding OuterColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
-                        </Setter.Value>
-                    </Setter>
-
-                    <Style.Triggers>
-                        <DataTrigger Binding="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=OneWay}"
-                                             Value="False">
-                            <DataTrigger.Setters>
-                                <Setter Property="Background" Value="Transparent" />
-                            </DataTrigger.Setters>
-                        </DataTrigger>
-                    </Style.Triggers>
-                </Style>
-            </Border.Style>
-
-            <local:OutlinedTextBlock x:Name="TimeTextBlock"
-                                     Margin="1"
-                                     HorizontalAlignment="Center"
-                                     Text="{Binding CurrentTimeOrCountdownString}"
-                                     StrokeThickness="0.5">
-
-                <local:OutlinedTextBlock.Fill>
-                    <SolidColorBrush Color="{Binding TextColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
-                </local:OutlinedTextBlock.Fill>
-
-                <local:OutlinedTextBlock.Style>
-                    <Style TargetType="local:OutlinedTextBlock">
-                        <Setter Property="Stroke" Value="Transparent" />
-                        <Style.Triggers>
-                            <DataTrigger Binding="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=OneWay}"
-                                             Value="False">
-                                <DataTrigger.Setters>
-                                    <Setter Property="Stroke">
-                                        <Setter.Value>
-                                            <SolidColorBrush Color="{Binding OuterColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
-                                        </Setter.Value>
-                                    </Setter>
-                                </DataTrigger.Setters>
-                            </DataTrigger>
-                        </Style.Triggers>
-                    </Style>
-                </local:OutlinedTextBlock.Style>
-            </local:OutlinedTextBlock>
-        </Border>
-    </Viewbox>
+	<Window.DataContext>
+		<local:MainViewModel />
+	</Window.DataContext>
+
+	<Window.ContextMenu>
+		<ContextMenu>
+			<MenuItem Click="MenuItemCopy_OnClick" Header="_Copy" />
+
+			<Separator />
+
+			<MenuItem Header="Stay on _top"
+			          IsCheckable="True"
+			          IsChecked="{Binding Topmost, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
+
+			<MenuItem Header="Show tas_kbar icon"
+			          IsCheckable="True"
+			          IsChecked="{Binding ShowInTaskbar, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
+
+			<MenuItem Header="Show _background"
+			          IsCheckable="True"
+			          IsChecked="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
+
+			<MenuItem>
+				<MenuItem.Header>
+					<StackPanel Orientation="Horizontal">
+						<TextBlock Text="Size: " />
+
+						<Slider Width="80"
+						        AutoToolTipPlacement="TopLeft"
+						        IsSnapToTickEnabled="True"
+						        Maximum="160"
+						        Minimum="16"
+						        TickFrequency="4"
+						        Value="{Binding Height, Source={x:Static p:Settings.Default}, Mode=TwoWay}" />
+					</StackPanel>
+				</MenuItem.Header>
+			</MenuItem>
+
+			<MenuItem Header="T_heme" ItemsSource="{x:Static local:App.Themes}">
+				<MenuItem.Resources>
+					<Style TargetType="MenuItem">
+						<Setter Property="Command" Value="{Binding DataContext.SetThemeCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
+
+						<Setter Property="CommandParameter" Value="{Binding}" />
+
+						<Setter Property="DisplayMemberPath" Value="Name" />
+					</Style>
+				</MenuItem.Resources>
+			</MenuItem>
+
+			<MenuItem Header="Time _Zone" ItemsSource="{x:Static local:DateTimeUtil.TimeZones}">
+				<MenuItem.Resources>
+					<Style TargetType="MenuItem">
+						<Setter Property="Command" Value="{Binding DataContext.SetTimeZoneCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
+
+						<Setter Property="CommandParameter" Value="{Binding}" />
+					</Style>
+				</MenuItem.Resources>
+			</MenuItem>
+
+			<MenuItem Header="_Format" ItemsSource="{x:Static local:DateTimeUtil.DateTimeFormatsAndExamples}">
+				<MenuItem.Resources>
+					<Style TargetType="MenuItem">
+						<Setter Property="Command" Value="{Binding DataContext.SetFormatCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
+
+						<Setter Property="CommandParameter" Value="{Binding Key}" />
+
+						<Setter Property="DisplayMemberPath" Value="Value" />
+					</Style>
+				</MenuItem.Resources>
+			</MenuItem>
+
+			<Separator />
+
+			<MenuItem Click="MenuItemSettings_OnClick" Header="_Settings..." />
+
+			<MenuItem Click="MenuItemCheckForUpdates_OnClick" Header="Check for _updates..." />
+
+			<MenuItem Click="MenuItemExit_OnClick" Header="E_xit" />
+		</ContextMenu>
+	</Window.ContextMenu>
+
+	<Viewbox Height="{Binding Height, Source={x:Static p:Settings.Default}, Mode=OneWay}">
+		<Border CornerRadius="2">
+			<Border.Style>
+				<Style TargetType="Border">
+					<Setter Property="Background">
+						<Setter.Value>
+							<SolidColorBrush Opacity="{Binding BackgroundOpacity, Source={x:Static p:Settings.Default}, Mode=OneWay}" Color="{Binding OuterColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
+						</Setter.Value>
+					</Setter>
+
+					<Style.Triggers>
+						<DataTrigger Binding="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=OneWay}" Value="False">
+							<DataTrigger.Setters>
+								<Setter Property="Background" Value="Transparent" />
+							</DataTrigger.Setters>
+						</DataTrigger>
+					</Style.Triggers>
+				</Style>
+			</Border.Style>
+
+			<local:OutlinedTextBlock x:Name="TimeTextBlock"
+			                         Margin="1"
+			                         HorizontalAlignment="Center"
+			                         Text="{Binding CurrentTimeOrCountdownString}"
+			                         StrokeThickness="0.5">
+
+				<local:OutlinedTextBlock.Fill>
+					<SolidColorBrush Color="{Binding TextColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
+				</local:OutlinedTextBlock.Fill>
+
+				<local:OutlinedTextBlock.Style>
+					<Style TargetType="local:OutlinedTextBlock">
+						<Setter Property="Stroke" Value="Transparent" />
+						<Style.Triggers>
+							<DataTrigger Binding="{Binding BackgroundEnabled, Source={x:Static p:Settings.Default}, Mode=OneWay}" Value="False">
+								<DataTrigger.Setters>
+									<Setter Property="Stroke">
+										<Setter.Value>
+											<SolidColorBrush Color="{Binding OuterColor, Source={x:Static p:Settings.Default}, Mode=OneWay}" />
+										</Setter.Value>
+									</Setter>
+								</DataTrigger.Setters>
+							</DataTrigger>
+						</Style.Triggers>
+					</Style>
+				</local:OutlinedTextBlock.Style>
+			</local:OutlinedTextBlock>
+		</Border>
+	</Viewbox>
 </Window>

+ 10 - 8
DesktopClock/OutlinedTextBlock.cs

@@ -201,8 +201,8 @@ namespace DesktopClock
 
             // constrain the formatted text according to the available size
 
-            double w = availableSize.Width;
-            double h = availableSize.Height;
+            var w = availableSize.Width;
+            var h = availableSize.Height;
 
             // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions
             // the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw
@@ -255,13 +255,15 @@ namespace DesktopClock
                 return;
             }
 
+#pragma warning disable CS0618 // Type or member is obsolete
             _FormattedText = new FormattedText(
-              Text ?? "",
-              CultureInfo.CurrentUICulture,
-              FlowDirection,
-              new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
-              FontSize,
-              Brushes.Black);
+                Text ?? "",
+                CultureInfo.CurrentUICulture,
+                FlowDirection,
+                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
+                FontSize,
+                Brushes.Black);
+#pragma warning restore CS0618 // Type or member is obsolete
 
             UpdateFormattedText();
         }

+ 7 - 5
DesktopClock/Properties/Settings.cs

@@ -12,9 +12,9 @@ namespace DesktopClock.Properties
         private DateTime _fileLastUsed = DateTime.UtcNow;
 
         public static readonly string Path = "DesktopClock.settings";
-        private static readonly Lazy<Settings> _default = new Lazy<Settings>(() => TryLoad() ?? new Settings());
+        private static readonly Lazy<Settings> _default = new(() => TryLoad() ?? new Settings());
 
-        private static readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
+        private static readonly JsonSerializerSettings _jsonSerializerSettings = new()
         {
             Formatting = Formatting.Indented
         };
@@ -27,7 +27,9 @@ namespace DesktopClock.Properties
             Theme = App.Themes[random.Next(0, App.Themes.Count)];
         }
 
+#pragma warning disable CS0067 // The event 'Settings.PropertyChanged' is never used
         public event PropertyChangedEventHandler PropertyChanged;
+#pragma warning restore CS0067 // The event 'Settings.PropertyChanged' is never used
 
         public static Settings Default => _default.Value;
 
@@ -49,7 +51,7 @@ namespace DesktopClock.Properties
         [JsonIgnore]
         public Theme Theme
         {
-            get => new Theme("Custom", TextColor.ToString(), OuterColor.ToString());
+            get => new("Custom", TextColor.ToString(), OuterColor.ToString());
             set
             {
                 TextColor = (Color)ColorConverter.ConvertFromString(value.PrimaryColor);
@@ -60,7 +62,7 @@ namespace DesktopClock.Properties
         #endregion "Properties"
 
         /// <summary>
-        /// Saves to the default path in JSON format.
+        /// Saves to the default path.
         /// </summary>
         public void Save()
         {
@@ -79,7 +81,7 @@ namespace DesktopClock.Properties
             File.GetLastWriteTimeUtc(Path) > _fileLastUsed;
 
         /// <summary>
-        /// Loads from the default path in JSON format.
+        /// Loads from the default path.
         /// </summary>
         private static Settings Load()
         {

+ 40 - 0
Settings.XamlStyler

@@ -0,0 +1,40 @@
+{
+    "AttributesTolerance": 2,
+    "KeepFirstAttributeOnSameLine": true,
+    "MaxAttributeCharactersPerLine": 40,
+    "MaxAttributesPerLine": 1,
+    "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransform, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter",
+    "SeparateByGroups": false,
+    "AttributeIndentation": 0,
+    "AttributeIndentationStyle": 1,
+    "RemoveDesignTimeReferences":  false,
+    "EnableAttributeReordering": false,
+    "AttributeOrderingRuleGroups": [
+        "x:Class",
+        "xmlns, xmlns:x",
+        "xmlns:*",
+        "x:Key, Key, x:Name, Name, x:Uid, Uid, Title",
+        "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom",
+        "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight",
+        "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex",
+        "*:*, *",
+        "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint",
+        "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText",
+        "Storyboard.*, From, To, Duration"
+    ],
+    "FirstLineAttributes": "",
+    "OrderAttributesByName": true,
+    "PutEndingBracketOnNewLine": false,
+    "RemoveEndingTagOfEmptyElement": true,
+    "SpaceBeforeClosingSlash": true,
+    "RootElementLineBreakRule": 0,
+    "ReorderVSM": 2,
+    "ReorderGridChildren": false,
+    "ReorderCanvasChildren": false,
+    "ReorderSetters": 0,
+    "FormatMarkupExtension": true,
+    "NoNewLineMarkupExtensions": "x:Bind, Binding",
+    "ThicknessSeparator": 2,
+    "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin",
+    "CommentPadding": 2,
+}