├── .editorconfig ├── .github └── workflows │ ├── build.yml │ └── deploy.yml ├── .gitignore ├── LICENSE ├── Network Monitor.sln ├── Network Monitor ├── App.config ├── App.xaml ├── App.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── MonitorView.xaml ├── MonitorView.xaml.cs ├── Monitors │ ├── BandwidthMonitor.cs │ ├── DownloadMonitor.cs │ ├── DummyMonitor.cs │ ├── LatencyMonitor.cs │ ├── Monitor.cs │ └── UploadMonitor.cs ├── Network Monitor.csproj ├── Network Monitor.ico ├── ObservableObject.cs ├── Properties │ ├── Settings.Designer.cs │ └── Settings.settings ├── SystemClockTimer.cs └── WpfWindowPlacement │ ├── NativeMethods.cs │ ├── Point.cs │ ├── Rectangle.cs │ ├── WindowPlacement.cs │ ├── WindowPlacementFlags.cs │ ├── WindowPlacementFunctions.cs │ ├── WindowPlacementProperties.cs │ └── WindowPlacementShowCommand.cs ├── Product.wxs ├── README.md └── Settings.XamlStyler /.editorconfig: -------------------------------------------------------------------------------- 1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | 7 | #### Core EditorConfig Options #### 8 | 9 | # Indentation and spacing 10 | indent_size = 4 11 | indent_style = space 12 | tab_width = 4 13 | 14 | # New line preferences 15 | end_of_line = crlf 16 | insert_final_newline = false 17 | 18 | #### .NET Coding Conventions #### 19 | 20 | # Organize usings 21 | dotnet_separate_import_directive_groups = false 22 | dotnet_sort_system_directives_first = true 23 | file_header_template = unset 24 | 25 | # this. and Me. preferences 26 | dotnet_style_qualification_for_event = false:suggestion 27 | dotnet_style_qualification_for_field = false 28 | dotnet_style_qualification_for_method = false:suggestion 29 | dotnet_style_qualification_for_property = false:suggestion 30 | 31 | # Language keywords vs BCL types preferences 32 | dotnet_style_predefined_type_for_locals_parameters_members = true:error 33 | dotnet_style_predefined_type_for_member_access = true:error 34 | 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:warning 37 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:warning 38 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion 39 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:warning 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = for_non_interface_members 43 | 44 | # Expression-level preferences 45 | dotnet_style_coalesce_expression = true 46 | dotnet_style_collection_initializer = true:silent 47 | dotnet_style_explicit_tuple_names = true:warning 48 | dotnet_style_namespace_match_folder = true 49 | dotnet_style_null_propagation = true 50 | dotnet_style_object_initializer = true:silent 51 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 52 | dotnet_style_prefer_auto_properties = true:suggestion 53 | dotnet_style_prefer_compound_assignment = true 54 | dotnet_style_prefer_conditional_expression_over_assignment = true 55 | dotnet_style_prefer_conditional_expression_over_return = true 56 | dotnet_style_prefer_foreach_explicit_cast_in_source = when_strongly_typed 57 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:silent 58 | dotnet_style_prefer_inferred_tuple_names = true:silent 59 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true 60 | dotnet_style_prefer_simplified_boolean_expressions = true 61 | dotnet_style_prefer_simplified_interpolation = true 62 | 63 | # Field preferences 64 | dotnet_style_readonly_field = true:warning 65 | 66 | # Parameter preferences 67 | dotnet_code_quality_unused_parameters = non_public:warning 68 | 69 | # Suppression preferences 70 | dotnet_remove_unnecessary_suppression_exclusions = none 71 | 72 | # New line preferences 73 | dotnet_style_allow_multiple_blank_lines_experimental = false 74 | dotnet_style_allow_statement_immediately_after_block_experimental = false 75 | 76 | #### C# Coding Conventions #### 77 | 78 | # var preferences 79 | csharp_style_var_elsewhere = true:suggestion 80 | csharp_style_var_for_built_in_types = true:suggestion 81 | csharp_style_var_when_type_is_apparent = true:suggestion 82 | 83 | # Expression-bodied members 84 | csharp_style_expression_bodied_accessors = true 85 | csharp_style_expression_bodied_constructors = false 86 | csharp_style_expression_bodied_indexers = true 87 | csharp_style_expression_bodied_lambdas = true 88 | csharp_style_expression_bodied_local_functions = true 89 | csharp_style_expression_bodied_methods = true 90 | csharp_style_expression_bodied_operators = true 91 | csharp_style_expression_bodied_properties = true 92 | 93 | # Pattern matching preferences 94 | csharp_style_pattern_matching_over_as_with_null_check = true 95 | csharp_style_pattern_matching_over_is_with_cast_check = true 96 | csharp_style_prefer_extended_property_pattern = true 97 | csharp_style_prefer_not_pattern = true 98 | csharp_style_prefer_pattern_matching = true:suggestion 99 | csharp_style_prefer_switch_expression = true 100 | 101 | # Null-checking preferences 102 | csharp_style_conditional_delegate_call = true 103 | csharp_style_prefer_parameter_null_checking = false:error 104 | 105 | # Modifier preferences 106 | csharp_prefer_static_local_function = true:warning 107 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async 108 | 109 | # Code-block preferences 110 | csharp_prefer_braces = when_multiline:warning 111 | csharp_prefer_simple_using_statement = true:silent 112 | csharp_style_namespace_declarations = file_scoped 113 | csharp_style_prefer_method_group_conversion = true 114 | csharp_style_prefer_top_level_statements = true 115 | 116 | # Expression-level preferences 117 | csharp_prefer_simple_default_expression = true 118 | csharp_style_deconstructed_variable_declaration = true 119 | csharp_style_implicit_object_creation_when_type_is_apparent = true 120 | csharp_style_inlined_variable_declaration = true 121 | csharp_style_prefer_index_operator = true 122 | csharp_style_prefer_local_over_anonymous_function = true 123 | csharp_style_prefer_null_check_over_type_check = true:warning 124 | csharp_style_prefer_range_operator = true 125 | csharp_style_prefer_tuple_swap = true:silent 126 | csharp_style_throw_expression = true 127 | csharp_style_unused_value_assignment_preference = discard_variable:warning 128 | csharp_style_unused_value_expression_statement_preference = discard_variable 129 | 130 | # 'using' directive preferences 131 | csharp_using_directive_placement = outside_namespace:error 132 | 133 | # New line preferences 134 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true 135 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = false 136 | csharp_style_allow_embedded_statements_on_same_line_experimental = false:warning 137 | 138 | #### C# Formatting Rules #### 139 | 140 | # New line preferences 141 | csharp_new_line_before_catch = true 142 | csharp_new_line_before_else = true 143 | csharp_new_line_before_finally = true 144 | csharp_new_line_before_members_in_anonymous_types = true 145 | csharp_new_line_before_members_in_object_initializers = true 146 | csharp_new_line_before_open_brace = all 147 | csharp_new_line_between_query_expression_clauses = true 148 | 149 | # Indentation preferences 150 | csharp_indent_block_contents = true 151 | csharp_indent_braces = false 152 | csharp_indent_case_contents = true 153 | csharp_indent_case_contents_when_block = true 154 | csharp_indent_labels = one_less_than_current 155 | csharp_indent_switch_labels = true 156 | 157 | # Space preferences 158 | csharp_space_after_cast = false 159 | csharp_space_after_colon_in_inheritance_clause = true 160 | csharp_space_after_comma = true 161 | csharp_space_after_dot = false 162 | csharp_space_after_keywords_in_control_flow_statements = true 163 | csharp_space_after_semicolon_in_for_statement = true 164 | csharp_space_around_binary_operators = before_and_after 165 | csharp_space_around_declaration_statements = false 166 | csharp_space_before_colon_in_inheritance_clause = true 167 | csharp_space_before_comma = false 168 | csharp_space_before_dot = false 169 | csharp_space_before_open_square_brackets = false 170 | csharp_space_before_semicolon_in_for_statement = false 171 | csharp_space_between_empty_square_brackets = false 172 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 173 | csharp_space_between_method_call_name_and_opening_parenthesis = false 174 | csharp_space_between_method_call_parameter_list_parentheses = false 175 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 176 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 177 | csharp_space_between_method_declaration_parameter_list_parentheses = false 178 | csharp_space_between_parentheses = false 179 | csharp_space_between_square_brackets = false 180 | 181 | # Wrapping preferences 182 | csharp_preserve_single_line_blocks = true 183 | csharp_preserve_single_line_statements = true 184 | 185 | #### Naming styles #### 186 | 187 | # Naming rules 188 | 189 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 190 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 191 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 192 | 193 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 194 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 195 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 196 | 197 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 198 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 199 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 200 | 201 | # Symbol specifications 202 | 203 | dotnet_naming_symbols.interface.applicable_kinds = interface 204 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 205 | dotnet_naming_symbols.interface.required_modifiers = 206 | 207 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 208 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 209 | dotnet_naming_symbols.types.required_modifiers = 210 | 211 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 212 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 213 | dotnet_naming_symbols.non_field_members.required_modifiers = 214 | 215 | # Naming styles 216 | 217 | dotnet_naming_style.pascal_case.required_prefix = 218 | dotnet_naming_style.pascal_case.required_suffix = 219 | dotnet_naming_style.pascal_case.word_separator = 220 | dotnet_naming_style.pascal_case.capitalization = pascal_case 221 | 222 | dotnet_naming_style.begins_with_i.required_prefix = I 223 | dotnet_naming_style.begins_with_i.required_suffix = 224 | dotnet_naming_style.begins_with_i.word_separator = 225 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 226 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | deploy: 9 | runs-on: windows-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | 13 | - uses: actions/setup-dotnet@v2 14 | 15 | - name: Build 16 | run: dotnet build 17 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | jobs: 9 | deploy: 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v3 13 | 14 | - uses: actions/setup-dotnet@v2 15 | 16 | - name: Build 17 | run: dotnet publish -o "publish" -c Release -r win-x64 18 | 19 | - name: Create installer 20 | run: | 21 | dotnet tool install --global wix --version 4.0.0-preview.1 22 | wix build Product.wxs -o "publish/Install Network Monitor.msi" 23 | 24 | - name: Create GitHub release 25 | uses: ncipollo/release-action@v1 26 | with: 27 | artifacts: "publish/*.exe,publish/*.msi" 28 | allowUpdates: true 29 | artifactErrorsFailBuild: true 30 | prerelease: contains(github.ref, 'beta') 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Windows Store app package directory 170 | AppPackages/ 171 | BundleArtifacts/ 172 | 173 | # Visual Studio cache files 174 | # files ending in .cache can be ignored 175 | *.[Cc]ache 176 | # but keep track of directories ending in .cache 177 | !*.[Cc]ache/ 178 | 179 | # Others 180 | ClientBin/ 181 | [Ss]tyle[Cc]op.* 182 | ~$* 183 | *~ 184 | *.dbmdl 185 | *.dbproj.schemaview 186 | *.pfx 187 | *.publishsettings 188 | node_modules/ 189 | orleans.codegen.cs 190 | 191 | # RIA/Silverlight projects 192 | Generated_Code/ 193 | 194 | # Backup & report files from converting an old project file 195 | # to a newer Visual Studio version. Backup files are not needed, 196 | # because we have git ;-) 197 | _UpgradeReport_Files/ 198 | Backup*/ 199 | UpgradeLog*.XML 200 | UpgradeLog*.htm 201 | 202 | # SQL Server files 203 | *.mdf 204 | *.ldf 205 | 206 | # Business Intelligence projects 207 | *.rdl.data 208 | *.bim.layout 209 | *.bim_*.settings 210 | 211 | # Microsoft Fakes 212 | FakesAssemblies/ 213 | 214 | # GhostDoc plugin setting file 215 | *.GhostDoc.xml 216 | 217 | # Node.js Tools for Visual Studio 218 | .ntvs_analysis.dat 219 | 220 | # Visual Studio 6 build log 221 | *.plg 222 | 223 | # Visual Studio 6 workspace options file 224 | *.opt 225 | 226 | # Visual Studio LightSwitch build output 227 | **/*.HTMLClient/GeneratedArtifacts 228 | **/*.DesktopClient/GeneratedArtifacts 229 | **/*.DesktopClient/ModelManifest.xml 230 | **/*.Server/GeneratedArtifacts 231 | **/*.Server/ModelManifest.xml 232 | _Pvt_Extensions 233 | 234 | # LightSwitch generated files 235 | GeneratedArtifacts/ 236 | ModelManifest.xml 237 | 238 | # Paket dependency manager 239 | .paket/paket.exe 240 | 241 | # FAKE - F# Make 242 | .fake/ 243 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Daniel Chalmers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Network Monitor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33103.201 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Network Monitor", "Network Monitor\Network Monitor.csproj", "{46A5208D-49CB-499A-BC21-7B6993B1F3F4}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {46A5208D-49CB-499A-BC21-7B6993B1F3F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {46A5208D-49CB-499A-BC21-7B6993B1F3F4}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {46A5208D-49CB-499A-BC21-7B6993B1F3F4}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {46A5208D-49CB-499A-BC21-7B6993B1F3F4}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /Network Monitor/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | True 15 | 16 | 17 | True 18 | 19 | 20 | True 21 | 22 | 23 | 96 24 | 25 | 26 | True 27 | 28 | 29 | False 30 | 31 | 32 | False 33 | 34 | 35 | False 36 | 37 | 38 | 39 | 40 | 41 | 42 | 8.8.8.8 43 | 44 | 45 | 00:00:04 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Network Monitor/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | -------------------------------------------------------------------------------- /Network Monitor/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | namespace Network_Monitor; 4 | 5 | /// 6 | /// Interaction logic for App.xaml 7 | /// 8 | public partial class App : Application 9 | { 10 | } -------------------------------------------------------------------------------- /Network Monitor/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  25 | 26 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 55 | 56 | 59 | 60 | 63 | 64 | 67 | 68 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 120 | 121 | 122 | 123 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /Network Monitor/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Windows; 7 | using System.Windows.Input; 8 | using Microsoft.Win32; 9 | using Network_Monitor.Monitors; 10 | using Network_Monitor.Properties; 11 | using WpfWindowPlacement; 12 | 13 | namespace Network_Monitor; 14 | 15 | /// 16 | /// Interaction logic for MainWindow.xaml 17 | /// 18 | public partial class MainWindow : Window 19 | { 20 | public MainWindow() 21 | { 22 | InitializeComponent(); 23 | 24 | if (Settings.Default.MustUpgrade) 25 | { 26 | Settings.Default.Upgrade(); 27 | Settings.Default.MustUpgrade = false; 28 | Settings.Default.Save(); 29 | } 30 | 31 | Settings.Default.PropertyChanged += Settings_PropertyChanged; 32 | 33 | Monitors = new List { 34 | new LatencyMonitor(Settings.Default.PingHost, Settings.Default.Timeout), 35 | new DownloadMonitor(), 36 | new UploadMonitor() 37 | }; 38 | } 39 | 40 | private void Settings_PropertyChanged(object sender, PropertyChangedEventArgs e) 41 | { 42 | switch (e.PropertyName) 43 | { 44 | case nameof(Settings.Default.RunOnStartup): 45 | 46 | using (var key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", true)) 47 | { 48 | if (Settings.Default.RunOnStartup) 49 | key?.SetValue("Network_Monitor", App.ResourceAssembly.Location); 50 | else 51 | key?.DeleteValue("Network_Monitor", false); 52 | } 53 | 54 | break; 55 | } 56 | } 57 | 58 | public IReadOnlyList Monitors { get; } 59 | 60 | private void MainWindow_OnMouseDown(object sender, MouseButtonEventArgs e) 61 | { 62 | if (e.ChangedButton == MouseButton.Left) 63 | DragMove(); 64 | } 65 | 66 | private void Window_PreviewMouseWheel(object sender, MouseWheelEventArgs e) 67 | { 68 | if (Keyboard.Modifiers == ModifierKeys.Control) 69 | { 70 | // Scale size based on scroll amount, with one notch on a default PC mouse being a change of 15%. 71 | var steps = e.Delta / (double)Mouse.MouseWheelDeltaForOneLine; 72 | var change = Settings.Default.Size * steps * 0.15; 73 | Settings.Default.Size = (int)Math.Min(Math.Max(Settings.Default.Size + change, 32), 320); 74 | } 75 | } 76 | 77 | private void CopyOverviewToClipboard() 78 | { 79 | var longestMonitorName = Monitors.Max(m => m.Name.Length); 80 | var overviewText = string.Join(Environment.NewLine, Monitors.Select(m => $"{m.Name.PadRight(longestMonitorName)}: {m.DisplayValue}")); 81 | 82 | Clipboard.SetText(overviewText.ToString()); 83 | } 84 | 85 | private void MenuItemCopy_OnClick(object sender, RoutedEventArgs e) 86 | { 87 | CopyOverviewToClipboard(); 88 | } 89 | 90 | private void MenuItemCheckForUpdates_OnClick(object sender, RoutedEventArgs e) 91 | { 92 | Process.Start(new ProcessStartInfo { FileName = "https://github.com/danielchalmers/Network-Monitor/releases", UseShellExecute = true }); 93 | } 94 | 95 | private void MenuItemExit_OnClick(object sender, RoutedEventArgs e) 96 | { 97 | Close(); 98 | } 99 | 100 | private void Window_SourceInitialized(object sender, EventArgs e) 101 | { 102 | try 103 | { 104 | WindowPlacementFunctions.SetPlacement(this, Settings.Default.Placement); 105 | } 106 | catch 107 | { 108 | // System.Configuration doesn't like the WindowPlacement struct sometimes. 109 | } 110 | } 111 | 112 | private void Window_Closing(object sender, CancelEventArgs e) 113 | { 114 | Settings.Default.Placement = WindowPlacementFunctions.GetPlacement(this); 115 | Settings.Default.Save(); 116 | } 117 | 118 | private void Window_MouseDoubleClick(object sender, MouseButtonEventArgs e) 119 | { 120 | if (e.ChangedButton == MouseButton.Left) 121 | CopyOverviewToClipboard(); 122 | } 123 | } -------------------------------------------------------------------------------- /Network Monitor/MonitorView.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 19 | 20 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Network Monitor/MonitorView.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows; 3 | using System.Windows.Controls; 4 | using Network_Monitor.Monitors; 5 | 6 | namespace Network_Monitor; 7 | 8 | /// 9 | /// Interaction logic for MonitorView.xaml 10 | /// 11 | public partial class MonitorView : UserControl 12 | { 13 | private readonly SystemClockTimer Timer = new(); 14 | 15 | public static readonly DependencyProperty MonitorProperty = DependencyProperty.Register(nameof(Monitor), typeof(Monitor), typeof(MonitorView), new(OnMonitorChanged)); 16 | 17 | public MonitorView() 18 | { 19 | InitializeComponent(); 20 | } 21 | 22 | public Monitor Monitor 23 | { 24 | get => (Monitor)GetValue(MonitorProperty); 25 | set => SetValue(MonitorProperty, value); 26 | } 27 | 28 | public static void OnMonitorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 29 | { 30 | if (e.OldValue is not null) 31 | throw new InvalidOperationException("The monitor can only be set once."); 32 | 33 | var view = (MonitorView)d; 34 | var monitor = (Monitor)e.NewValue; 35 | 36 | view.DisplayTextBlock.Text = monitor.DisplayValue; 37 | 38 | view.Timer.SecondChanged += (_, _) => view.Dispatcher.Invoke(() => view.DisplayTextBlock.Text = monitor.DisplayValue); 39 | view.Timer.Start(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Network Monitor/Monitors/BandwidthMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Net.NetworkInformation; 4 | 5 | namespace Network_Monitor.Monitors; 6 | 7 | /// 8 | /// Base for bandwidth type monitors (i.e. upload and download). 9 | /// 10 | public abstract class BandwidthMonitor : Monitor 11 | { 12 | private readonly char[] ByteSuffixes = new[] { 'B', 'K', 'M', 'G', 'T', 'P', 'E' }; 13 | private readonly char[] BitSuffixes = new[] { 'b', 'k', 'm', 'g', 't', 'p', 'e' }; 14 | private long _lastBytes; 15 | 16 | protected BandwidthMonitor() : base(TimeSpan.FromSeconds(2)) 17 | { 18 | NetworkChange.NetworkAvailabilityChanged += (_, _) => NetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces(); 19 | } 20 | 21 | protected IReadOnlyList NetworkInterfaces { get; private set; } = NetworkInterface.GetAllNetworkInterfaces(); 22 | 23 | protected abstract long GetTotalBytes(); 24 | 25 | protected override string GetDisplayValue() 26 | { 27 | var bytes = GetBytesDiffAndUpdateLast(); 28 | 29 | if (!bytes.HasValue) 30 | return string.Empty; 31 | 32 | return GetReadableByteString(bytes.Value, Properties.Settings.Default.Bits); 33 | } 34 | 35 | private long? GetBytesDiffAndUpdateLast() 36 | { 37 | var bytes = GetTotalBytes(); 38 | try 39 | { 40 | // Last value hasn't been set or an interface was disconnected. 41 | if (_lastBytes <= 0 || bytes <= 0) 42 | return null; 43 | 44 | // Return the difference in bytes since the last call. 45 | return bytes - _lastBytes; 46 | } 47 | finally 48 | { 49 | _lastBytes = bytes; 50 | } 51 | } 52 | 53 | /// 54 | /// Returns a short user-friendly representation of a number of bytes. 55 | /// 56 | private string GetReadableByteString(long bytes, bool convertToBits) 57 | { 58 | if (bytes < 0) 59 | throw new ArgumentOutOfRangeException(nameof(bytes), "Number of bytes must be positive for this."); 60 | 61 | if (convertToBits) 62 | bytes *= 8; 63 | 64 | var suffixIndex = 0; 65 | while (bytes >= 1000) // Keep at 3 or less digits. 66 | { 67 | bytes /= 1024; 68 | suffixIndex++; 69 | } 70 | 71 | return bytes.ToString(bytes < 10 ? "0.0" : "0") + (convertToBits ? BitSuffixes[suffixIndex] : ByteSuffixes[suffixIndex]); 72 | } 73 | } -------------------------------------------------------------------------------- /Network Monitor/Monitors/DownloadMonitor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Windows.Media; 3 | 4 | namespace Network_Monitor.Monitors; 5 | 6 | /// 7 | /// Monitor for download bandwidth usage. 8 | /// 9 | public class DownloadMonitor : BandwidthMonitor 10 | { 11 | public DownloadMonitor() 12 | { 13 | Name = "Download"; 14 | Icon = '↓'; 15 | IconBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#00E676")); // Green A400 https://materialui.co/colors 16 | } 17 | 18 | protected override long GetTotalBytes() => 19 | NetworkInterfaces 20 | .Select(x => x.GetIPStatistics().BytesReceived) 21 | .Sum(); 22 | } -------------------------------------------------------------------------------- /Network Monitor/Monitors/DummyMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Media; 3 | 4 | namespace Network_Monitor.Monitors; 5 | 6 | /// 7 | /// Dummy monitor for preserving auto-generated window width. 8 | /// 9 | public class DummyMonitor : Monitor 10 | { 11 | public DummyMonitor() : base(TimeSpan.Zero) 12 | { 13 | Name = "You shouldn't be seeing this!"; 14 | Icon = 'X'; 15 | IconBrush = Brushes.Red; 16 | DisplayValue = string.Empty.PadRight(4); 17 | } 18 | 19 | protected override string GetDisplayValue() => 20 | throw new InvalidOperationException("Dummy monitor should never be updated."); 21 | } -------------------------------------------------------------------------------- /Network Monitor/Monitors/LatencyMonitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.NetworkInformation; 3 | using System.Windows.Media; 4 | 5 | namespace Network_Monitor.Monitors; 6 | 7 | /// 8 | /// Monitor for ping latency. 9 | /// 10 | public class LatencyMonitor : Monitor 11 | { 12 | private readonly Ping _ping = new(); 13 | private readonly string _host; 14 | private readonly int _timeout; 15 | 16 | public LatencyMonitor(string host, TimeSpan timeout) : base(timeout) 17 | { 18 | Name = "Latency"; 19 | Icon = '⟳'; 20 | IconBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#FF9100")); // Orange A400 https://materialui.co/colors 21 | 22 | _host = host; 23 | _timeout = (int)timeout.TotalMilliseconds; 24 | } 25 | 26 | protected override string GetDisplayValue() 27 | { 28 | var reply = _ping.Send(_host, _timeout); 29 | 30 | return reply.Status == IPStatus.Success ? reply.RoundtripTime.ToString() : "Fail"; 31 | } 32 | } -------------------------------------------------------------------------------- /Network Monitor/Monitors/Monitor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Windows.Media; 4 | 5 | namespace Network_Monitor.Monitors; 6 | 7 | public abstract class Monitor 8 | { 9 | private readonly Timer _timer; 10 | 11 | protected Monitor(TimeSpan interval) 12 | { 13 | if (interval > TimeSpan.Zero) 14 | { 15 | _timer = new Timer(_ => Update()); 16 | _timer.Change(TimeSpan.Zero, interval); 17 | } 18 | } 19 | 20 | /// 21 | /// Name of the monitor. 22 | /// 23 | public string Name { get; protected set; } 24 | 25 | /// 26 | /// Icon to show in the UI. 27 | /// 28 | public char Icon { get; protected set; } 29 | 30 | /// 31 | /// Icon color. 32 | /// 33 | public Brush IconBrush { get; protected set; } 34 | 35 | /// 36 | /// User-friendly text to show in the UI. 37 | /// 38 | public string DisplayValue { get; protected set; } 39 | 40 | /// 41 | /// Gets the latest value for . 42 | /// 43 | protected abstract string GetDisplayValue(); 44 | 45 | /// 46 | /// Updates with the latest value. 47 | /// 48 | private void Update() 49 | { 50 | try 51 | { 52 | DisplayValue = GetDisplayValue(); 53 | } 54 | catch 55 | { 56 | DisplayValue = "Fail"; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /Network Monitor/Monitors/UploadMonitor.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Windows.Media; 3 | 4 | namespace Network_Monitor.Monitors; 5 | 6 | /// 7 | /// Monitor for upload bandwidth usage. 8 | /// 9 | public class UploadMonitor : BandwidthMonitor 10 | { 11 | public UploadMonitor() 12 | { 13 | Name = "Upload"; 14 | Icon = '↑'; 15 | IconBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#2979FF")); // Blue A400 https://materialui.co/colors 16 | } 17 | 18 | protected override long GetTotalBytes() => 19 | NetworkInterfaces 20 | .Select(x => x.GetIPStatistics().BytesSent) 21 | .Sum(); 22 | } -------------------------------------------------------------------------------- /Network Monitor/Network Monitor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | WinExe 5 | net48 6 | true 7 | latest 8 | Network Monitor.ico 9 | © Daniel Chalmers 10 | 3.0.0 11 | 12 | 13 | -------------------------------------------------------------------------------- /Network Monitor/Network Monitor.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/danielchalmers/Network-Monitor/508e5962a282e2c88dfd19c234d1ecdd28b5672f/Network Monitor/Network Monitor.ico -------------------------------------------------------------------------------- /Network Monitor/ObservableObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Runtime.CompilerServices; 4 | 5 | namespace Network_Monitor; 6 | 7 | public class ObservableObject : INotifyPropertyChanged 8 | { 9 | public event PropertyChangedEventHandler PropertyChanged; 10 | 11 | protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) => 12 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 13 | 14 | protected bool Set( 15 | ref T field, 16 | T newValue = default, 17 | bool checkEquality = true, 18 | [CallerMemberName] string propertyName = null) 19 | { 20 | if (checkEquality && EqualityComparer.Default.Equals(field, newValue)) 21 | return false; 22 | 23 | field = newValue; 24 | RaisePropertyChanged(propertyName); 25 | return true; 26 | } 27 | } -------------------------------------------------------------------------------- /Network Monitor/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Network_Monitor.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.UserScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 29 | public bool MustUpgrade { 30 | get { 31 | return ((bool)(this["MustUpgrade"])); 32 | } 33 | set { 34 | this["MustUpgrade"] = value; 35 | } 36 | } 37 | 38 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 39 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 40 | [global::System.Configuration.DefaultSettingValueAttribute("8.8.8.8")] 41 | public string PingHost { 42 | get { 43 | return ((string)(this["PingHost"])); 44 | } 45 | } 46 | 47 | [global::System.Configuration.UserScopedSettingAttribute()] 48 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 49 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 50 | public bool Topmost { 51 | get { 52 | return ((bool)(this["Topmost"])); 53 | } 54 | set { 55 | this["Topmost"] = value; 56 | } 57 | } 58 | 59 | [global::System.Configuration.UserScopedSettingAttribute()] 60 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 61 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 62 | public bool ShowInTaskbar { 63 | get { 64 | return ((bool)(this["ShowInTaskbar"])); 65 | } 66 | set { 67 | this["ShowInTaskbar"] = value; 68 | } 69 | } 70 | 71 | [global::System.Configuration.UserScopedSettingAttribute()] 72 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 73 | [global::System.Configuration.DefaultSettingValueAttribute("96")] 74 | public int Size { 75 | get { 76 | return ((int)(this["Size"])); 77 | } 78 | set { 79 | this["Size"] = value; 80 | } 81 | } 82 | 83 | [global::System.Configuration.UserScopedSettingAttribute()] 84 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 85 | public global::WpfWindowPlacement.WindowPlacement Placement { 86 | get { 87 | return ((global::WpfWindowPlacement.WindowPlacement)(this["Placement"])); 88 | } 89 | set { 90 | this["Placement"] = value; 91 | } 92 | } 93 | 94 | [global::System.Configuration.UserScopedSettingAttribute()] 95 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 96 | [global::System.Configuration.DefaultSettingValueAttribute("True")] 97 | public bool Bits { 98 | get { 99 | return ((bool)(this["Bits"])); 100 | } 101 | set { 102 | this["Bits"] = value; 103 | } 104 | } 105 | 106 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 107 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 108 | [global::System.Configuration.DefaultSettingValueAttribute("00:00:04")] 109 | public global::System.TimeSpan Timeout { 110 | get { 111 | return ((global::System.TimeSpan)(this["Timeout"])); 112 | } 113 | } 114 | 115 | [global::System.Configuration.UserScopedSettingAttribute()] 116 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 117 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 118 | public bool Horizontal { 119 | get { 120 | return ((bool)(this["Horizontal"])); 121 | } 122 | set { 123 | this["Horizontal"] = value; 124 | } 125 | } 126 | 127 | [global::System.Configuration.UserScopedSettingAttribute()] 128 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 129 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 130 | public bool Dark { 131 | get { 132 | return ((bool)(this["Dark"])); 133 | } 134 | set { 135 | this["Dark"] = value; 136 | } 137 | } 138 | 139 | [global::System.Configuration.UserScopedSettingAttribute()] 140 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 141 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 142 | public bool RunOnStartup { 143 | get { 144 | return ((bool)(this["RunOnStartup"])); 145 | } 146 | set { 147 | this["RunOnStartup"] = value; 148 | } 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /Network Monitor/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | True 7 | 8 | 9 | 8.8.8.8 10 | 11 | 12 | True 13 | 14 | 15 | True 16 | 17 | 18 | 96 19 | 20 | 21 | 22 | 23 | 24 | True 25 | 26 | 27 | 00:00:04 28 | 29 | 30 | False 31 | 32 | 33 | False 34 | 35 | 36 | False 37 | 38 | 39 | -------------------------------------------------------------------------------- /Network Monitor/SystemClockTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace Network_Monitor; 5 | 6 | /// 7 | /// A timer that is synced with the system clock. 8 | /// 9 | /// 10 | /// 11 | /// 12 | public sealed class SystemClockTimer : IDisposable 13 | { 14 | private readonly Timer _timer; 15 | 16 | public SystemClockTimer() 17 | { 18 | _timer = new Timer(_ => OnTick()); 19 | } 20 | 21 | /// 22 | /// Occurs after the second of the system clock changes. 23 | /// 24 | public event EventHandler SecondChanged; 25 | 26 | /// 27 | /// Number of milliseconds until the next second on the system clock. 28 | /// 29 | private int MillisecondsUntilNextSecond => 1000 - DateTimeOffset.Now.Millisecond; 30 | 31 | public void Dispose() => _timer.Dispose(); 32 | 33 | public void Start() => ScheduleTickForNextSecond(); 34 | 35 | public void Stop() => _timer.Change(Timeout.Infinite, Timeout.Infinite); 36 | 37 | private void OnTick() 38 | { 39 | ScheduleTickForNextSecond(); 40 | 41 | SecondChanged?.Invoke(this, EventArgs.Empty); 42 | } 43 | 44 | /// 45 | /// Starts the timer and schedules the tick for the next second on the system clock. 46 | /// 47 | private void ScheduleTickForNextSecond() => 48 | _timer.Change(MillisecondsUntilNextSecond, Timeout.Infinite); 49 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace WpfWindowPlacement; 5 | 6 | internal static class NativeMethods 7 | { 8 | [DllImport("user32.dll")] 9 | internal static extern bool SetWindowPlacement(IntPtr hWnd, [In] ref WindowPlacement lpwndpl); 10 | 11 | [DllImport("user32.dll")] 12 | internal static extern bool GetWindowPlacement(IntPtr hWnd, out WindowPlacement lpwndpl); 13 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/Point.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace WpfWindowPlacement; 5 | 6 | /// 7 | /// Defines the x- and y- coordinates of a point. 8 | /// 9 | [Serializable] 10 | [StructLayout(LayoutKind.Sequential)] 11 | public struct Point 12 | { 13 | /// 14 | /// The x-coordinate of the point. 15 | /// 16 | public int X; 17 | 18 | /// 19 | /// The y-coordinate of the point. 20 | /// 21 | public int Y; 22 | 23 | public Point(int x, int y) 24 | { 25 | X = x; 26 | Y = y; 27 | } 28 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/Rectangle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace WpfWindowPlacement; 5 | 6 | /// 7 | /// Defines the coordinates of the upper-left and lower-right corners of a rectangle. 8 | /// 9 | [Serializable] 10 | [StructLayout(LayoutKind.Sequential)] 11 | public struct Rectangle 12 | { 13 | /// 14 | /// The x-coordinate of the upper-left corner of the rectangle. 15 | /// 16 | public int Left; 17 | 18 | /// 19 | /// The y-coordinate of the upper-left corner of the rectangle. 20 | /// 21 | public int Top; 22 | 23 | /// 24 | /// The x-coordinate of the lower-right corner of the rectangle. 25 | /// 26 | public int Right; 27 | 28 | /// 29 | /// The y-coordinate of the lower-right corner of the rectangle. 30 | /// 31 | public int Bottom; 32 | 33 | public Rectangle(int left, int top, int right, int bottom) 34 | { 35 | Left = left; 36 | Top = top; 37 | Right = right; 38 | Bottom = bottom; 39 | } 40 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/WindowPlacement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace WpfWindowPlacement; 5 | 6 | /// 7 | /// Contains information about the placement of a window on the screen. 8 | /// 9 | [Serializable] 10 | [StructLayout(LayoutKind.Sequential)] 11 | public struct WindowPlacement 12 | { 13 | /// 14 | /// The length of the structure, in bytes. 15 | /// 16 | public int Length; 17 | 18 | /// 19 | /// The flags that control the position of the minimized window and the method by which the window is restored. 20 | /// 21 | public WindowPlacementFlags Flags; 22 | 23 | /// 24 | /// The current show state of the window. 25 | /// 26 | public WindowPlacementShowCommand ShowCommand; 27 | 28 | /// 29 | /// The coordinates of the window's upper-left corner when the window is minimized. 30 | /// 31 | public Point MinimizedPosition; 32 | 33 | /// 34 | /// The coordinates of the window's upper-left corner when the window is maximized. 35 | /// 36 | public Point MaximizedPosition; 37 | 38 | /// 39 | /// The window's bounds when the window is in the restored position. 40 | /// 41 | public Rectangle NormalBounds; 42 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/WindowPlacementFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WpfWindowPlacement; 4 | 5 | /// 6 | /// The flags that control the position of the minimized window and the method by which the window is restored. 7 | /// 8 | [Flags] 9 | public enum WindowPlacementFlags : uint 10 | { 11 | /// 12 | /// If the calling thread and the thread that owns the window are attached to different input queues, the system posts the request to the thread that owns the window. 13 | /// This prevents the calling thread from blocking its execution while other threads process the request. 14 | /// 15 | AsyncWindowPlacement = 0x0004, 16 | 17 | /// 18 | /// The restored window will be maximized, regardless of whether it is maximized or minimized. 19 | /// This setting is only valid next time the window is restored. It does not change the default restoration behavior. 20 | /// 21 | RestoreToMaximized = 0x0002, 22 | 23 | /// 24 | /// The coordinates of the minimized window may be specified. 25 | /// This flag must be specified in the member. 26 | /// 27 | SetMinimizedPosition = 0x0001, 28 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/WindowPlacementFunctions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using System.Windows; 4 | using System.Windows.Interop; 5 | 6 | namespace WpfWindowPlacement; 7 | 8 | /// 9 | /// related functions. 10 | /// See for use in XAML. 11 | /// 12 | public static class WindowPlacementFunctions 13 | { 14 | /// 15 | /// Retrieves the show state and the restored, minimized, and maximized positions of the specified window. 16 | /// 17 | /// The handle to the window. 18 | public static WindowPlacement GetPlacement(IntPtr windowHandle) 19 | { 20 | var placement = new WindowPlacement 21 | { 22 | // The length member must be set correctly or the P/Invoke function returns false. 23 | Length = Marshal.SizeOf(typeof(WindowPlacement)) 24 | }; 25 | 26 | NativeMethods.GetWindowPlacement(windowHandle, out placement); 27 | 28 | return placement; 29 | } 30 | 31 | /// 32 | /// Retrieves the show state and the restored, minimized, and maximized positions of the specified window. 33 | /// 34 | /// The window. 35 | public static WindowPlacement GetPlacement(this Window window) => 36 | GetPlacement(new WindowInteropHelper(window).Handle); 37 | 38 | /// 39 | /// Sets the show state and the restored, minimized, and maximized positions of the specified window. 40 | /// 41 | /// The handle to the window. 42 | /// A structure that specifies the new show state and window positions. 43 | public static void SetPlacement(IntPtr windowHandle, WindowPlacement placement) 44 | { 45 | if (placement.Equals(default(WindowPlacement))) 46 | return; 47 | 48 | // Restore window to normal state if minimized. 49 | if (placement.ShowCommand == WindowPlacementShowCommand.ShowMinimized) 50 | placement.ShowCommand = WindowPlacementShowCommand.ShowNormal; 51 | 52 | // Length must be set correctly or the P/Invoke function will return false. 53 | placement.Length = Marshal.SizeOf(typeof(WindowPlacement)); 54 | 55 | // P/Invoke win32 method to set the window's placement. 56 | NativeMethods.SetWindowPlacement(windowHandle, ref placement); 57 | } 58 | 59 | /// 60 | /// Sets the show state and the restored, minimized, and maximized positions of the specified window. 61 | /// 62 | /// The window. 63 | /// A structure that specifies the new show state and window positions. 64 | public static void SetPlacement(this Window window, WindowPlacement placement) => 65 | SetPlacement(new WindowInteropHelper(window).Handle, placement); 66 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/WindowPlacementProperties.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Windows; 4 | using System.Windows.Interop; 5 | 6 | namespace WpfWindowPlacement; 7 | 8 | /// 9 | /// Attached properties for in XAML. 10 | /// See for use in code-behind. 11 | /// 12 | public static class WindowPlacementProperties 13 | { 14 | public static readonly DependencyProperty PlacementProperty = 15 | DependencyProperty.RegisterAttached( 16 | "Placement", 17 | typeof(WindowPlacement?), 18 | typeof(WindowPlacementProperties), 19 | new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnPlacementPropertyChanged)); 20 | 21 | public static WindowPlacement GetPlacement(Window sender) => (WindowPlacement)sender.GetValue(PlacementProperty); 22 | public static void SetPlacement(Window sender, WindowPlacement value) => sender.SetValue(PlacementProperty, value); 23 | 24 | private static void OnPlacementPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 25 | { 26 | if (DesignerProperties.GetIsInDesignMode(sender)) 27 | return; 28 | 29 | var window = (Window)sender; 30 | var placement = (WindowPlacement)e.NewValue; 31 | 32 | // Does the window have a handle? 33 | if (new WindowInteropHelper(window).Handle == IntPtr.Zero) 34 | { 35 | // Wait until the source has been initialized and the handle is available. 36 | window.SourceInitialized -= Window_SourceInitialized; 37 | window.SourceInitialized += Window_SourceInitialized; 38 | } 39 | else 40 | { 41 | // The handle is available so we can set the placement for it. 42 | WindowPlacementFunctions.SetPlacement(window, placement); 43 | } 44 | 45 | // Unsubscribe first in case we already were subscribed so that we only have one subscription. 46 | window.Closing -= UpdatePlacementProperty; 47 | window.Closing += UpdatePlacementProperty; 48 | } 49 | 50 | private static void Window_SourceInitialized(object sender, EventArgs e) 51 | { 52 | var window = (Window)sender; 53 | 54 | window.SetPlacement(GetPlacement(window)); 55 | } 56 | 57 | private static void UpdatePlacementProperty(object sender, EventArgs e) 58 | { 59 | var window = (Window)sender; 60 | var placement = WindowPlacementFunctions.GetPlacement(window); 61 | 62 | SetPlacement(window, placement); 63 | } 64 | } -------------------------------------------------------------------------------- /Network Monitor/WpfWindowPlacement/WindowPlacementShowCommand.cs: -------------------------------------------------------------------------------- 1 | namespace WpfWindowPlacement; 2 | 3 | /// 4 | /// The current show state of the window. 5 | /// 6 | public enum WindowPlacementShowCommand : uint 7 | { 8 | /// 9 | /// Hides the window and activates another window. 10 | /// 11 | Hide = 0, 12 | 13 | /// 14 | /// Maximizes the specified window. 15 | /// 16 | Maximize = 3, 17 | 18 | /// 19 | /// Minimize the specified window and activate the next top-level window in the z-order. 20 | /// 21 | Minimize = 6, 22 | 23 | /// 24 | /// Activates and displays the window. 25 | /// If the window is minimized or maximized, the system restores it to its original size and position. 26 | /// An application should specify this flag when restoring a minimized window. 27 | /// 28 | Restore = 9, 29 | 30 | /// 31 | /// Activates the window and displays it in its current size and position. 32 | /// 33 | Show = 5, 34 | 35 | /// 36 | /// Activates the window and displays it as a maximized window. 37 | /// 38 | ShowMaximized = 3, 39 | 40 | /// 41 | /// Activates the window and displays it as a minimized window. 42 | /// 43 | ShowMinimized = 2, 44 | 45 | /// 46 | /// Displays the window as a minimized window. 47 | /// This value is relative to , except the window is not activated. 48 | /// 49 | ShowMinimizedNoActivate = 7, 50 | 51 | /// 52 | /// Displays the window in its current size and position. 53 | /// This value is similar to , except the window is not activated. 54 | /// 55 | ShowNA = 8, 56 | 57 | /// 58 | /// Displays a window in its most recent size and position. 59 | /// This value is only valid for , except the window is not activated. 60 | /// 61 | ShowNoActivate = 4, 62 | 63 | /// 64 | /// Activates and displays a window. 65 | /// If the window is minimized or maximized, the system restores it to its original size and position. 66 | /// An application should specify this flag when displaying the window for the first time. 67 | /// 68 | ShowNormal = 1, 69 | } -------------------------------------------------------------------------------- /Product.wxs: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Network Monitor 2 | 3 | [![Release](https://img.shields.io/github/release/danielchalmers/Network-Monitor?include_prereleases)](https://github.com/danielchalmers/Network-Monitor/releases/latest) 4 | [![License](https://img.shields.io/github/license/danielchalmers/Network-Monitor)](LICENSE) 5 | 6 | See live network latency & bandwidth usage. 7 | 8 | ## Vertical (Default) 9 | 10 | ![Vertical](https://user-images.githubusercontent.com/7112040/33785224-16384542-dc32-11e7-8574-676f0fe52726.gif) 11 | 12 | ## Horizontal 13 | 14 | ![Horizontal](https://user-images.githubusercontent.com/7112040/33785456-202dfeb0-dc33-11e7-87e5-af4a09d77058.gif) 15 | 16 | ## Right-click options 17 | 18 | ![Options](https://user-images.githubusercontent.com/7112040/204114602-8d508d10-6a93-43d5-bb8a-af0c4befefd6.png) 19 | -------------------------------------------------------------------------------- /Settings.XamlStyler: -------------------------------------------------------------------------------- 1 | { 2 | "AttributesTolerance": 2, 3 | "KeepFirstAttributeOnSameLine": true, 4 | "MaxAttributeCharactersPerLine": 40, 5 | "MaxAttributesPerLine": 1, 6 | "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransform, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter", 7 | "SeparateByGroups": false, 8 | "AttributeIndentation": 0, 9 | "AttributeIndentationStyle": 1, 10 | "RemoveDesignTimeReferences": false, 11 | "EnableAttributeReordering": false, 12 | "AttributeOrderingRuleGroups": [ 13 | "x:Class", 14 | "xmlns, xmlns:x", 15 | "xmlns:*", 16 | "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", 17 | "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom", 18 | "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight", 19 | "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", 20 | "*:*, *", 21 | "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", 22 | "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", 23 | "Storyboard.*, From, To, Duration" 24 | ], 25 | "FirstLineAttributes": "", 26 | "OrderAttributesByName": true, 27 | "PutEndingBracketOnNewLine": false, 28 | "RemoveEndingTagOfEmptyElement": true, 29 | "SpaceBeforeClosingSlash": true, 30 | "RootElementLineBreakRule": 0, 31 | "ReorderVSM": 2, 32 | "ReorderGridChildren": false, 33 | "ReorderCanvasChildren": false, 34 | "ReorderSetters": 0, 35 | "FormatMarkupExtension": true, 36 | "NoNewLineMarkupExtensions": "x:Bind, Binding", 37 | "ThicknessSeparator": 2, 38 | "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin", 39 | "CommentPadding": 2, 40 | } --------------------------------------------------------------------------------