├── .editorconfig
├── .gitattributes
├── .gitignore
├── Directory.Build.props
├── IPConfig.sln
├── IPConfig
├── .dns
│ ├── ipv4_public_dns.en.csv
│ └── ipv4_public_dns.zh-CN.csv
├── .mask
│ ├── ipv4_mask.en.csv
│ └── ipv4_mask.zh-CN.csv
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── Behaviors
│ ├── ContextMenuLeftClickBehavior.cs
│ ├── CopyContentsSplitButtonBehavior.cs
│ ├── IgnoreMouseWheelBehavior.cs
│ ├── InputBindingBehavior.cs
│ ├── SelectedItemsBehavior.cs
│ ├── SplitButtonToggleDropDownBehavior.cs
│ └── TripleClickToSelectAllBehavior.cs
├── Controls
│ ├── AlignDashCornerRect.cs
│ ├── BindingProxy.cs
│ ├── DeferredContent.cs
│ └── ReadOnlyComboBox.cs
├── Converters
│ ├── BytesToFileSizeConverter.cs
│ ├── CopyContentFormatConverter.cs
│ ├── GetIPCIDRConverter.cs
│ ├── MultiValueEqualsConverter.cs
│ ├── NicIPConfigToolTipConverter.cs
│ ├── OperationalStatusToolTipConverter.cs
│ ├── PingDnsGroupIsEnabledConverter.cs
│ ├── PingDnsLabelContentConverter.cs
│ ├── PingDnsLabelStyleConverter.cs
│ ├── PingReplyToolTipConverter.cs
│ ├── SelectedNicIPConfigNameConverter.cs
│ ├── SkinTypeToImageConverter.cs
│ ├── SkinTypeToolTipConverter.cs
│ ├── StringRemoveNewLineConverter.cs
│ ├── StringToIntConverter.cs
│ └── ValidationErrorsToolTipConverter.cs
├── Extensions
│ ├── EnumerableExtensions.cs
│ ├── IPConfigModelExtensions.cs
│ ├── StringExtensions.cs
│ └── WindowsThemeExtensions.cs
├── Helpers
│ ├── BytesFormatter.cs
│ ├── ClipboardHelper.cs
│ ├── FileOrderHelper.cs
│ ├── GroupItemHelper.cs
│ ├── LiteDbHelper.cs
│ ├── NameOfHelper.cs
│ ├── NetworkManagement.cs
│ ├── ResourceHelper.cs
│ ├── ThemeManager.cs
│ ├── ThemeWatcher.cs
│ └── UriHelper.cs
├── IPConfig.csproj
├── Languages
│ ├── Lang.Designer.cs
│ ├── Lang.Designer.tt
│ ├── Lang.en.resx
│ ├── Lang.resx
│ ├── LangExtension.cs
│ └── LangSource.cs
├── Models
│ ├── EditableIPConfigModel.cs
│ ├── Error.cs
│ ├── GitHub
│ │ ├── GitHubApi.cs
│ │ ├── GitHubApiException.cs
│ │ └── GitHubReleaseInfo.cs
│ ├── IDeepCloneTo.cs
│ ├── IDeepCloneable.cs
│ ├── IPAdvancedConfigBase.cs
│ ├── IPConfigBase.cs
│ ├── IPConfigModel.cs
│ ├── IPv4AdvancedConfig.cs
│ ├── IPv4Config.cs
│ ├── IPv4Dns.cs
│ ├── IPv4Mask.cs
│ ├── IPv6AdvancedConfig.cs
│ ├── LastUsedIPv4Config.cs
│ ├── Messages
│ │ ├── AddUntitledIPConfigMessage.cs
│ │ ├── CancelEditMessage.cs
│ │ ├── ChangeSelectionMessage.cs
│ │ ├── CollectionChangeActionMessage.cs
│ │ ├── EmptyMessage.cs
│ │ ├── GoBackMessage.cs
│ │ ├── ISender.cs
│ │ ├── KeyPressMessage.cs
│ │ ├── RefreshMessage.cs
│ │ ├── SaveMessage.cs
│ │ └── ToggleStateMessage.cs
│ ├── Nic.cs
│ ├── SimpleNicType.cs
│ └── Validations
│ │ ├── ForwardingErrorsAttribute.cs
│ │ ├── IPValidationAttribute.cs
│ │ ├── RequiredIfAttribute.cs
│ │ └── ValidationLangAttributeBase.cs
├── Properties
│ ├── Settings.Designer.cs
│ ├── Settings.cs
│ └── Settings.settings
├── Resources
│ ├── Screenshots
│ │ └── mainwindow.png
│ ├── artist_palette_3d.png
│ ├── crescent_moon_3d.png
│ ├── inetcpl.cpl(4487).png
│ ├── ipconfig.ico
│ ├── network-tree.ai
│ ├── network-tree.png
│ ├── purple_circle_3d.png
│ ├── shell32.dll(22).png
│ └── sun_3d.png
├── Themes
│ ├── FixedHandyControlSearchBarPlusTemplate.xaml
│ ├── FixedHandyControlTextBoxPlusTemplate.xaml
│ ├── MyDarkTheme.xaml
│ ├── MyLightTheme.xaml
│ ├── MyResources.xaml
│ ├── MyStyles.xaml
│ └── MyVioletTheme.xaml
├── ViewModels
│ ├── IPConfigDetailViewModel.cs
│ ├── IPConfigListViewModel.cs
│ ├── MainViewModel.cs
│ ├── NicConfigDetailViewModel.cs
│ ├── NicViewModel.cs
│ ├── StatusBarViewModel.cs
│ ├── ThemeSwitchButtonViewModel.cs
│ └── VersionInfoViewModel.cs
├── Views
│ ├── IPConfigDetailView.xaml
│ ├── IPConfigDetailView.xaml.cs
│ ├── IPConfigListSelectionCounterView.xaml
│ ├── IPConfigListSelectionCounterView.xaml.cs
│ ├── IPConfigListView.xaml
│ ├── IPConfigListView.xaml.cs
│ ├── IPv4ConfigView.xaml
│ ├── IPv4ConfigView.xaml.cs
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── NicConfigDetailView.xaml
│ ├── NicConfigDetailView.xaml.cs
│ ├── NicInfoCardView.xaml
│ ├── NicInfoCardView.xaml.cs
│ ├── NicSelectorView.xaml
│ ├── NicSelectorView.xaml.cs
│ ├── NicSpeedMonitorView.xaml
│ ├── NicSpeedMonitorView.xaml.cs
│ ├── StatusBarView.xaml
│ ├── StatusBarView.xaml.cs
│ ├── ThemeSwitchButtonView.xaml
│ ├── ThemeSwitchButtonView.xaml.cs
│ ├── VersionInfoView.xaml
│ └── VersionInfoView.xaml.cs
└── app.manifest
├── LICENSE
├── Languages.Designer.t4
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)=$(MSBuildProjectName)
5 |
6 |
7 |
--------------------------------------------------------------------------------
/IPConfig.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33530.505
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IPConfig", "IPConfig\IPConfig.csproj", "{BB63F771-3406-4600-B774-AF6DE6499347}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D44A49D4-79B7-466B-A512-CA4C2125E89D}"
9 | ProjectSection(SolutionItems) = preProject
10 | .editorconfig = .editorconfig
11 | Directory.Build.props = Directory.Build.props
12 | Languages.Designer.t4 = Languages.Designer.t4
13 | EndProjectSection
14 | EndProject
15 | Global
16 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
17 | Debug|Any CPU = Debug|Any CPU
18 | Release|Any CPU = Release|Any CPU
19 | EndGlobalSection
20 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
21 | {BB63F771-3406-4600-B774-AF6DE6499347}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {BB63F771-3406-4600-B774-AF6DE6499347}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {BB63F771-3406-4600-B774-AF6DE6499347}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {BB63F771-3406-4600-B774-AF6DE6499347}.Release|Any CPU.Build.0 = Release|Any CPU
25 | EndGlobalSection
26 | GlobalSection(SolutionProperties) = preSolution
27 | HideSolutionNode = FALSE
28 | EndGlobalSection
29 | GlobalSection(ExtensibilityGlobals) = postSolution
30 | RESX_SortFileContentOnSave = True
31 | RESX_MoveToResources = {"Items":[{"Extensions":".cs,.vb","Patterns":"$File.$Key|{$File.$Key}|$Namespace.$File.$Key|LangKey.$Key|$Namespace.LangKey.$Key|nameof($File.$Key), ResourceType = typeof($File)|ErrorMessageResourceType = typeof($File), ErrorMessageResourceName = nameof($File.$Key)"},{"Extensions":".cshtml,.vbhtml","Patterns":"@$Namespace.$File.$Key|@$File.$Key|@StringResourceKey.$Key|@$Namespace.StringResourceKey.$Key"},{"Extensions":".cpp,.c,.hxx,.h","Patterns":"$File::$Key"},{"Extensions":".aspx,.ascx","Patterns":"<%$ Resources:$File,$Key %>|<%= $File.$Key %>|<%= $Namespace.$File.$Key %>"},{"Extensions":".xaml","Patterns":"\"{lang:Lang {x:Static lang:LangKey.$Key}}\""},{"Extensions":".ts","Patterns":"resources.$Key"},{"Extensions":".html","Patterns":"{{ resources.$Key }}"}]}
32 | SolutionGuid = {570D33A3-1D7B-44F2-9A79-313E68E608D8}
33 | RESX_NeutralResourcesLanguage = zh-CN
34 | RESX_SaveFilesImmediatelyUponChange = True
35 | EndGlobalSection
36 | EndGlobal
37 |
--------------------------------------------------------------------------------
/IPConfig/.dns/ipv4_public_dns.en.csv:
--------------------------------------------------------------------------------
1 | Provider,Filter,Dns1,Dns2,Group,Description
2 | 114DNS,NULL,114.114.114.114,114.114.115.115,Public DNS(China),"Pure and hijack-free, no need to endure the pain of being forced to watch adverts or vulgar websites"
3 | 114DNS,Enhanced Security,114.114.114.119,114.114.115.119,Public DNS(China),"Block phishing virus and Trojan horse websites to enhance the security of online banking, securities, shopping, gaming and privacy information"
4 | 114DNS,Minor,114.114.114.110,114.114.115.110,Public DNS(China),Schools or parents have the option of blocking pornographic websites to protect children and adolescents from pornographic content on the internet
5 | DNS Pai,Telecom,101.226.4.6,218.30.118.6,Public DNS(China),"Fast, smart, stable and pure"
6 | DNS Pai,Unicom,123.125.81.6,140.207.198.6,Public DNS(China),"Fast, smart, stable and pure"
7 | DNS Pai,Mobile,101.226.4.6,218.30.118.6,Public DNS(China),"Fast, smart, stable and pure"
8 | DNS Pai,Tietong,101.226.4.6,218.30.118.6,Public DNS(China),"Fast, smart, stable and pure"
9 | OneDNS,Pure,117.50.10.10,52.80.52.52,Public DNS(China),"Not to intercept any filtering of the visiting site, directly return its real response results"
10 | OneDNS,Blocking,117.50.11.11,52.80.66.66,Public DNS(China),"Protect against all kinds of malware, filter ads and nuisances"
11 | OneDNS,Family,117.50.60.30,52.80.60.30,Public DNS(China),"On the basis of the blocking version, pornographic and violent site filtering and gambling site filtering are added to better purify the home network environment"
12 | SDNS,NULL,1.2.4.8,202.98.0.68,Public DNS(China),China Internet Network Information Centre (CNNIC)
13 | AliDNS,NULL,223.5.5.5,223.6.6.6,Public DNS(China),"Fast, stable and secure"
14 | Baidu DNS,NULL,180.76.76.76,NULL,Public DNS(China),"Secure, hijack-free and more accurate"
15 | Tencent DNSPod,NULL,119.29.29.29,182.254.116.116,Public DNS(China),Free and reliable public resolution
16 | AdGuard,Default,94.140.14.14,94.140.15.15,Public DNS,AdGuard DNS will block ads and trackers
17 | AdGuard,Non-Filtering,94.140.14.140,94.140.14.141,Public DNS,"AdGuard DNS will not block ads, trackers, or any other DNS requests"
18 | AdGuard,Family Protection,94.140.14.15,94.140.15.16,Public DNS,"AdGuard DNS will block ads, trackers, adult content, and enable Safe Search and Safe Mode, where possible"
19 | CleanBrowsing,Family Filter,185.228.168.168,185.228.169.168,Public DNS,"Blocks access to all adult, pornographic and explicit sites. It also blocks proxy and VPN domains that are used to bypass the filters. Mixed content sites (like Reddit) are also blocked. Google, Bing and Youtube are set to the Safe Mode. Malicious and Phishing domains are blocked"
20 | CleanBrowsing,Adult Filter,185.228.168.10,185.228.169.11,Public DNS,"Blocks access to all adult, pornographic and explicit sites. It does not block proxy or VPNs, nor mixed-content sites. Sites like Reddit are allowed. Google and Bing are set to the Safe Mode. Malicious and Phishing domains are blocked"
21 | CleanBrowsing,Security Filter,185.228.168.9,185.228.169.9,Public DNS,"Blocks access to phishing, spam, malware and malicious domains. Our database of malicious domains is updated hourly and considered to be one of the best in the industry. Note that it does not block adult content"
22 | Cloudflare,NULL,1.1.1.1,1.0.0.1,Public DNS,Fast. Free. Private
23 | Cloudflare,Security Filter,1.1.1.2,1.0.0.2,Public DNS,Malware Blocking Only
24 | Cloudflare,Family Filter,1.1.1.3,1.0.0.3,Public DNS,Malware and Adult Content Blocking Together
25 | Google,NULL,8.8.8.8,8.8.4.4,Public DNS,"Speed up your browsing experience, Improve your security, Get the results you expect with absolutely no redirection"
26 | Level 3,NULL,209.244.0.3,209.244.0.4,Public DNS,"The free DNS servers listed above as Level 3 will automatically route to the nearest DNS server operated by Level 3 Communications, the company that provides most of the ISPs in the US their access to the internet backbone"
27 | Level 3,Verizon DNS,4.2.2.1,4.2.2.2,Public DNS,These servers are often given as Verizon DNS servers but that is not technically the case
28 | Level 3,Verizon DNS,4.2.2.3,4.2.2.4,Public DNS,These servers are often given as Verizon DNS servers but that is not technically the case
29 | Level 3,Verizon DNS,4.2.2.5,4.2.2.6,Public DNS,These servers are often given as Verizon DNS servers but that is not technically the case
30 | OpenDNS,Basic Security,208.67.222.222,208.67.220.220,Public DNS,"Our classic, free service with customizable filtering and basic protection"
31 | OpenDNS,Family Shield,208.67.222.123,208.67.220.123,Public DNS,Preconfigured to block adult content - set it & forget it
32 | OpenDNS,Sandbox,208.67.222.2,208.67.220.2,Public DNS,OpenDNS Sandbox is an RFC-compliant DNS service that does not provide any level of filtering
33 | OpenNIC,NULL,185.121.177.177,169.239.202.202,Public DNS,"DNS Neutrality, No Cost, Stop DNS Hijacking"
34 | Quad9,NULL,9.9.9.9,149.112.112.112,Public DNS,"Recommended: Malware Blocking, DNSSEC Validation (this is the most typical configuration)"
35 | Quad9,ECS,9.9.9.11,149.112.112.11,Public DNS,"Secured w/ECS: Malware blocking, DNSSEC Validation, ECS enabled"
36 | Quad9,Unsecured,9.9.9.10,149.112.112.10,Public DNS,"Unsecured: No Malware blocking, no DNSSEC validation (for experts only!)"
37 | V2EX,NULL,199.91.73.222,178.79.131.110,Public DNS,Powered by V2EX webmaster
38 | Yandex,Basic,77.88.8.1,77.88.8.8,Public DNS,No traffic filtering
39 | Yandex,Safe,77.88.8.2,77.88.8.88,Public DNS,Protection from infected and fraudulent sites is provided
40 | Yandex,Family,77.88.8.3,77.88.8.7,Public DNS,Protection from dangerous sites and blocks sites with adult content
41 |
--------------------------------------------------------------------------------
/IPConfig/.dns/ipv4_public_dns.zh-CN.csv:
--------------------------------------------------------------------------------
1 | Provider,Filter,Dns1,Dns2,Group,Description
2 | 114DNS,NULL,114.114.114.114,114.114.115.115,公共 DNS(中国),纯净无劫持,无需再忍受被强扭去看广告或粗俗网站之痛苦
3 | 114DNS,增强安全,114.114.114.119,114.114.115.119,公共 DNS(中国),拦截钓鱼病毒木马网站,增强网银、证券、购物、游戏、隐私信息安全
4 | 114DNS,少年儿童,114.114.114.110,114.114.115.110,公共 DNS(中国),学校或家长可选拦截色情网站,保护少年儿童免受网络色情内容的毒害
5 | DNS 派,电信,101.226.4.6,218.30.118.6,公共 DNS(中国),快速、智能、稳定、纯净
6 | DNS 派,联通,123.125.81.6,140.207.198.6,公共 DNS(中国),快速、智能、稳定、纯净
7 | DNS 派,移动,101.226.4.6,218.30.118.6,公共 DNS(中国),快速、智能、稳定、纯净
8 | DNS 派,铁通,101.226.4.6,218.30.118.6,公共 DNS(中国),快速、智能、稳定、纯净
9 | OneDNS,纯净版,117.50.10.10,52.80.52.52,公共 DNS(中国),不对访问网站进行任何过滤拦截,直接返回其真实的响应结果
10 | OneDNS,拦截版,117.50.11.11,52.80.66.66,公共 DNS(中国),防护各类恶意软件,过滤广告骚扰
11 | OneDNS,家庭版,117.50.60.30,52.80.60.30,公共 DNS(中国),在拦截版的基础上,增加了色情暴力站点过滤、赌博站点过滤功能,更好的净化家庭网络环境
12 | SDNS,NULL,1.2.4.8,202.98.0.68,公共 DNS(中国),中国互联网络信息中心
13 | 阿里云,NULL,223.5.5.5,223.6.6.6,公共 DNS(中国),快速、稳定、安全
14 | 百度 DNS,NULL,180.76.76.76,NULL,公共 DNS(中国),安全、无劫持、更精准
15 | 腾讯 DNSPod,NULL,119.29.29.29,182.254.116.116,公共 DNS(中国),免费且可靠的公共解析
16 | AdGuard,默认,94.140.14.14,94.140.15.15,公共 DNS,AdGuard DNS 拦截广告和跟踪器
17 | AdGuard,无过滤,94.140.14.140,94.140.14.141,公共 DNS,AdGuard DNS 不拦截广告、跟踪器或其他任何 DNS 请求
18 | AdGuard,家庭保护,94.140.14.15,94.140.15.16,公共 DNS,AdGuard DNS 拦截广告、跟踪器、成人内容,并在可能的情况下启用安全搜索和安全模式
19 | CleanBrowsing,家庭过滤,185.228.168.168,185.228.169.168,公共 DNS,阻止访问所有成人、色情和露骨网站。它还阻止用于绕过过滤器的代理和 VPN 域。混合内容网站(如 Reddit)也被阻止。Google,Bing 和 Youtube 设置为安全模式。恶意域和网络钓鱼域被阻止
20 | CleanBrowsing,成人过滤,185.228.168.10,185.228.169.11,公共 DNS,阻止访问所有成人、色情和露骨网站。它不会阻止代理或 VPN,也不会阻止混合内容网站。像 Reddit 这样的网站是允许的。Google 和 Bing 设置为安全模式。恶意域和网络钓鱼域被阻止
21 | CleanBrowsing,安全过滤,185.228.168.9,185.228.169.9,公共 DNS,阻止对网络钓鱼、垃圾邮件、恶意软件和恶意域的访问。我们的恶意域名数据库每小时更新一次,被认为是业内最好的数据库之一。请注意,它不会阻止成人内容
22 | Cloudflare,NULL,1.1.1.1,1.0.0.1,公共 DNS,快速且私密地浏览互联网的方式
23 | Cloudflare,安全过滤,1.1.1.2,1.0.0.2,公共 DNS,仅恶意软件阻止
24 | Cloudflare,家庭过滤,1.1.1.3,1.0.0.3,公共 DNS,同时阻止恶意和成人内容
25 | Google,NULL,8.8.8.8,8.8.4.4,公共 DNS,提升您的浏览体验、提高安全性、获得您完全没有重定向的预期结果
26 | Level 3,NULL,209.244.0.3,209.244.0.4,公共 DNS,自动路由到最近的由 Level 3 通信公司运营的 DNS 服务器,该公司为美国大多数 ISP 提供互联网骨干网的接入
27 | Level 3,Verizon DNS,4.2.2.1,4.2.2.2,公共 DNS,通常作为 Verizon DNS 服务器,但技术上并非如此,也许可以让微软网络服务加速
28 | Level 3,Verizon DNS,4.2.2.3,4.2.2.4,公共 DNS,通常作为 Verizon DNS 服务器,但技术上并非如此,也许可以让微软网络服务加速
29 | Level 3,Verizon DNS,4.2.2.5,4.2.2.6,公共 DNS,通常作为 Verizon DNS 服务器,但技术上并非如此,也许可以让微软网络服务加速
30 | OpenDNS,家庭,208.67.222.222,208.67.220.220,公共 DNS,经典免费服务,具有可定制的过滤和基本保护
31 | OpenDNS,家庭盾牌,208.67.222.123,208.67.220.123,公共 DNS,预配置为阻止成人内容
32 | OpenDNS,沙盒,208.67.222.2,208.67.220.2,公共 DNS,OpenDNS Sandbox 是一种符合 RFC 标准的 DNS 服务,不提供任何级别的过滤
33 | OpenNIC,NULL,185.121.177.177,169.239.202.202,公共 DNS,DNS 中立性、无成本、停止 DNS 劫持
34 | Quad9,NULL,9.9.9.9,149.112.112.112,公共 DNS,建议:恶意软件阻止、DNSSEC 验证(这是最典型的配置)
35 | Quad9,ECS,9.9.9.11,149.112.112.11,公共 DNS,带 ECS 的安全:恶意软件阻止、DNSSEC 验证、启用 ECS
36 | Quad9,专家,9.9.9.10,149.112.112.10,公共 DNS,不安全:没有恶意软件阻止,没有DNSSEC验证(仅适用于专家!)
37 | V2EX,NULL,199.91.73.222,178.79.131.110,公共 DNS,由 V2EX 站长提供
38 | Yandex,基本,77.88.8.1,77.88.8.8,公共 DNS,请求处理速度快,连接速度快
39 | Yandex,安全,77.88.8.2,77.88.8.88,公共 DNS,防止受感染或欺诈网站
40 | Yandex,家庭,77.88.8.3,77.88.8.7,公共 DNS,防止受感染或欺诈性网站以及阻止成人网站
41 |
--------------------------------------------------------------------------------
/IPConfig/.mask/ipv4_mask.en.csv:
--------------------------------------------------------------------------------
1 | Mask,CIDR,Group
2 | 255.0.0.0,8,Default
3 | 255.255.0.0,16,Default
4 | 255.255.255.0,24,Default
5 | 0.0.0.0,0,/0 ~ /8
6 | 128.0.0.0,1,/0 ~ /8
7 | 192.0.0.0,2,/0 ~ /8
8 | 224.0.0.0,3,/0 ~ /8
9 | 240.0.0.0,4,/0 ~ /8
10 | 248.0.0.0,5,/0 ~ /8
11 | 252.0.0.0,6,/0 ~ /8
12 | 254.0.0.0,7,/0 ~ /8
13 | 255.0.0.0,8,/0 ~ /8
14 | 255.128.0.0,9,/9 ~ /16
15 | 255.192.0.0,10,/9 ~ /16
16 | 255.224.0.0,11,/9 ~ /16
17 | 255.240.0.0,12,/9 ~ /16
18 | 255.248.0.0,13,/9 ~ /16
19 | 255.252.0.0,14,/9 ~ /16
20 | 255.254.0.0,15,/9 ~ /16
21 | 255.255.0.0,16,/9 ~ /16
22 | 255.255.128.0,17,/17 ~ /24
23 | 255.255.192.0,18,/17 ~ /24
24 | 255.255.224.0,19,/17 ~ /24
25 | 255.255.240.0,20,/17 ~ /24
26 | 255.255.248.0,21,/17 ~ /24
27 | 255.255.252.0,22,/17 ~ /24
28 | 255.255.254.0,23,/17 ~ /24
29 | 255.255.255.0,24,/17 ~ /24
30 | 255.255.255.128,25,/25 ~ /32
31 | 255.255.255.192,26,/25 ~ /32
32 | 255.255.255.224,27,/25 ~ /32
33 | 255.255.255.240,28,/25 ~ /32
34 | 255.255.255.248,29,/25 ~ /32
35 | 255.255.255.252,30,/25 ~ /32
36 | 255.255.255.254,31,/25 ~ /32
37 | 255.255.255.255,32,/25 ~ /32
38 |
--------------------------------------------------------------------------------
/IPConfig/.mask/ipv4_mask.zh-CN.csv:
--------------------------------------------------------------------------------
1 | Mask,CIDR,Group
2 | 255.0.0.0,8,默认
3 | 255.255.0.0,16,默认
4 | 255.255.255.0,24,默认
5 | 0.0.0.0,0,/0 ~ /8
6 | 128.0.0.0,1,/0 ~ /8
7 | 192.0.0.0,2,/0 ~ /8
8 | 224.0.0.0,3,/0 ~ /8
9 | 240.0.0.0,4,/0 ~ /8
10 | 248.0.0.0,5,/0 ~ /8
11 | 252.0.0.0,6,/0 ~ /8
12 | 254.0.0.0,7,/0 ~ /8
13 | 255.0.0.0,8,/0 ~ /8
14 | 255.128.0.0,9,/9 ~ /16
15 | 255.192.0.0,10,/9 ~ /16
16 | 255.224.0.0,11,/9 ~ /16
17 | 255.240.0.0,12,/9 ~ /16
18 | 255.248.0.0,13,/9 ~ /16
19 | 255.252.0.0,14,/9 ~ /16
20 | 255.254.0.0,15,/9 ~ /16
21 | 255.255.0.0,16,/9 ~ /16
22 | 255.255.128.0,17,/17 ~ /24
23 | 255.255.192.0,18,/17 ~ /24
24 | 255.255.224.0,19,/17 ~ /24
25 | 255.255.240.0,20,/17 ~ /24
26 | 255.255.248.0,21,/17 ~ /24
27 | 255.255.252.0,22,/17 ~ /24
28 | 255.255.254.0,23,/17 ~ /24
29 | 255.255.255.0,24,/17 ~ /24
30 | 255.255.255.128,25,/25 ~ /32
31 | 255.255.255.192,26,/25 ~ /32
32 | 255.255.255.224,27,/25 ~ /32
33 | 255.255.255.240,28,/25 ~ /32
34 | 255.255.255.248,29,/25 ~ /32
35 | 255.255.255.252,30,/25 ~ /32
36 | 255.255.255.254,31,/25 ~ /32
37 | 255.255.255.255,32,/25 ~ /32
38 |
--------------------------------------------------------------------------------
/IPConfig/App.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/IPConfig/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/ContextMenuLeftClickBehavior.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Controls.Primitives;
4 | using System.Windows.Data;
5 |
6 | namespace IPConfig.Behaviors;
7 |
8 | ///
9 | /// Show ContextMenu on Left Click using only XAML
10 | ///
11 | public static class ContextMenuLeftClickBehavior
12 | {
13 | public static readonly DependencyProperty IsLeftClickEnabledProperty =
14 | DependencyProperty.RegisterAttached(
15 | "IsLeftClickEnabled",
16 | typeof(bool),
17 | typeof(ContextMenuLeftClickBehavior),
18 | new UIPropertyMetadata(false, OnIsLeftClickEnabledChanged));
19 |
20 | public static bool GetIsLeftClickEnabled(DependencyObject obj)
21 | {
22 | return (bool)obj.GetValue(IsLeftClickEnabledProperty);
23 | }
24 |
25 | public static void SetIsLeftClickEnabled(DependencyObject obj, bool value)
26 | {
27 | obj.SetValue(IsLeftClickEnabledProperty, value);
28 | }
29 |
30 | private static void OnIsLeftClickEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
31 | {
32 | if (d is UIElement uiElement)
33 | {
34 | bool isEnabled = e.NewValue is bool b && b;
35 |
36 | if (isEnabled)
37 | {
38 | if (uiElement is ButtonBase btn)
39 | {
40 | btn.Click += OnMouseLeftButtonUp;
41 | }
42 | else
43 | {
44 | uiElement.MouseLeftButtonUp += OnMouseLeftButtonUp;
45 | }
46 | }
47 | else
48 | {
49 | if (uiElement is ButtonBase btn)
50 | {
51 | btn.Click -= OnMouseLeftButtonUp;
52 | }
53 | else
54 | {
55 | uiElement.MouseLeftButtonUp -= OnMouseLeftButtonUp;
56 | }
57 | }
58 | }
59 | }
60 |
61 | private static void OnMouseLeftButtonUp(object sender, RoutedEventArgs e)
62 | {
63 | if (sender is FrameworkElement fe)
64 | {
65 | // 如果我们在上下文菜单中使用绑定, 则当我们在左键单击时显示菜单时, 它的 “数据上下文” 将不会被设置。
66 | // (当用户右键单击控件时, 似乎在 WPF 中设置了 “数据上下文”, 尽管我不确定)
67 | // 所以我们必须在这里手动设置 ContextMenu 的数据上下文。
68 | if (fe.ContextMenu.DataContext is null)
69 | {
70 | fe.ContextMenu.SetBinding(FrameworkElement.DataContextProperty, new Binding { Source = fe.DataContext });
71 | }
72 |
73 | ContextMenuService.SetPlacementTarget(fe.ContextMenu, fe);
74 |
75 | ContextMenuService.SetPlacement(fe.ContextMenu, ContextMenuService.GetPlacement(fe));
76 | ContextMenuService.SetPlacementRectangle(fe.ContextMenu, ContextMenuService.GetPlacementRectangle(fe));
77 | ContextMenuService.SetHorizontalOffset(fe.ContextMenu, ContextMenuService.GetHorizontalOffset(fe));
78 | ContextMenuService.SetVerticalOffset(fe.ContextMenu, ContextMenuService.GetVerticalOffset(fe));
79 |
80 | fe.ContextMenu.IsOpen = true;
81 |
82 | // 设置切换形式打开上下文菜单。
83 | // 建议在 XAML 设置 ContextMenuService.IsEnabled="False" 以禁用右键打开功能,避免产生打开状态的切换冲突。
84 | fe.ContextMenu.Closed += (s, e) => fe.IsEnabled = true;
85 | fe.IsEnabled = false;
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/CopyContentsSplitButtonBehavior.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 | using System.Windows.Input;
5 | using System.Windows.Media;
6 | using System.Windows.Media.Animation;
7 |
8 | using HandyControl.Controls;
9 |
10 | using IPConfig.Languages;
11 |
12 | namespace IPConfig.Behaviors;
13 |
14 | public class CopyContentsSplitButtonBehavior : SplitButtonToggleDropDownBehavior
15 | {
16 | private bool _canPlayTextAnimation;
17 |
18 | protected override void OnAssociatedObjectClick(object sender, RoutedEventArgs e)
19 | {
20 | if (_canPlayTextAnimation)
21 | {
22 | AnimateText();
23 |
24 | _canPlayTextAnimation = false;
25 | }
26 | }
27 |
28 | protected override void OnAssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e, HitTestResult hitTestResult)
29 | {
30 | if (hitTestResult?.VisualHit is Border { Child: null } or TextBlock)
31 | {
32 | _canPlayTextAnimation = true;
33 | }
34 | }
35 |
36 | private void AnimateText()
37 | {
38 | NameScope.SetNameScope(AssociatedObject, new NameScope());
39 | string name = $"SplitButton_{Guid.NewGuid().ToString().Replace('-', '_')}";
40 | AssociatedObject.RegisterName(name, AssociatedObject);
41 |
42 | var keyFrames = new StringAnimationUsingKeyFrames {
43 | Duration = new(TimeSpan.FromSeconds(1))
44 | };
45 |
46 | var frame = new DiscreteStringKeyFrame(Lang.Copied, KeyTime.FromTimeSpan(TimeSpan.Zero));
47 | keyFrames.KeyFrames.Add(frame);
48 |
49 | var story = new Storyboard { FillBehavior = FillBehavior.Stop };
50 | Storyboard.SetTargetName(keyFrames, name);
51 | Storyboard.SetTargetProperty(keyFrames, new PropertyPath(SplitButton.ContentProperty));
52 | story.Children.Add(keyFrames);
53 | story.Begin(AssociatedObject);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/IgnoreMouseWheelBehavior.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Input;
3 |
4 | using Microsoft.Xaml.Behaviors;
5 |
6 | namespace IPConfig.Behaviors;
7 |
8 | ///
9 | /// 忽略 的鼠标滚轮行为,兼容附加属性模式。
10 | ///
11 | /// Bubbling scroll events from a ListView to its parent
12 | ///
13 | ///
14 | public sealed class IgnoreMouseWheelBehavior : Behavior
15 | {
16 | // Using a DependencyProperty as the backing store for Enabled. This enables animation, styling, binding, etc...
17 | public static readonly DependencyProperty EnabledProperty =
18 | DependencyProperty.RegisterAttached(
19 | "Enabled",
20 | typeof(bool),
21 | typeof(IgnoreMouseWheelBehavior),
22 | new PropertyMetadata(false, OnEnabledChanged));
23 |
24 | public static bool GetEnabled(DependencyObject obj)
25 | {
26 | return (bool)obj.GetValue(EnabledProperty);
27 | }
28 |
29 | public static void SetEnabled(DependencyObject obj, bool value)
30 | {
31 | obj.SetValue(EnabledProperty, value);
32 | }
33 |
34 | protected override void OnAttached()
35 | {
36 | base.OnAttached();
37 |
38 | AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
39 | }
40 |
41 | protected override void OnDetaching()
42 | {
43 | AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
44 |
45 | base.OnDetaching();
46 | }
47 |
48 | private static void OnEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
49 | {
50 | if (d is UIElement uie)
51 | {
52 | if ((bool)e.NewValue)
53 | {
54 | uie.PreviewMouseWheel += OnPreviewMouseWheel;
55 | }
56 | else
57 | {
58 | uie.PreviewMouseWheel -= OnPreviewMouseWheel;
59 | }
60 | }
61 | }
62 |
63 | private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
64 | {
65 | e.Handled = true;
66 |
67 | var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) {
68 | RoutedEvent = UIElement.MouseWheelEvent
69 | };
70 |
71 | ((UIElement)sender).RaiseEvent(e2);
72 | }
73 |
74 | private void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
75 | {
76 | e.Handled = true;
77 |
78 | var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) {
79 | RoutedEvent = UIElement.MouseWheelEvent
80 | };
81 |
82 | AssociatedObject.RaiseEvent(e2);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/InputBindingBehavior.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Windows;
6 | using System.Windows.Input;
7 |
8 | using IPConfig.Controls;
9 |
10 | namespace IPConfig.Behaviors;
11 |
12 | ///
13 | /// InputBindings work only when focused
14 | ///
15 | /// 此行为将在运行时引发 XAML 绑定错误,但不影响工作。使用 可以消除错误。
16 | ///
17 | /// System.Windows.Data Error: Cannot find governing FrameworkElement or FrameworkContentElement for target element.
18 | ///
19 | public class InputBindingBehavior
20 | {
21 | public static readonly DependencyProperty PropagateInputBindingsToWindowProperty =
22 | DependencyProperty.RegisterAttached(
23 | "PropagateInputBindingsToWindow",
24 | typeof(bool),
25 | typeof(InputBindingBehavior),
26 | new PropertyMetadata(false, OnPropagateInputBindingsToWindowChanged));
27 |
28 | private static readonly Dictionary, List>> _trackedFrameWorkElementsToBindings = [];
29 |
30 | public static bool GetPropagateInputBindingsToWindow(FrameworkElement obj)
31 | {
32 | return (bool)obj.GetValue(PropagateInputBindingsToWindowProperty);
33 | }
34 |
35 | public static void SetPropagateInputBindingsToWindow(FrameworkElement obj, bool value)
36 | {
37 | obj.SetValue(PropagateInputBindingsToWindowProperty, value);
38 | }
39 |
40 | private static void CleanupBindingsDictionary(Window window, Dictionary, List>> bindingsDictionary)
41 | {
42 | foreach (int hashCode in bindingsDictionary.Keys.ToList())
43 | {
44 | if (bindingsDictionary.TryGetValue(hashCode, out var trackedData) &&
45 | !trackedData.Item1.TryGetTarget(out _))
46 | {
47 | Debug.WriteLine($"InputBindingBehavior: FrameWorkElement {hashCode} did never unload but was GCed, cleaning up leftover KeyBindings.");
48 |
49 | foreach (var binding in trackedData.Item2)
50 | {
51 | window.InputBindings.Remove(binding);
52 | }
53 |
54 | trackedData.Item2.Clear();
55 | bindingsDictionary.Remove(hashCode);
56 | }
57 | }
58 | }
59 |
60 | private static void OnFrameworkElementLoaded(object sender, RoutedEventArgs e)
61 | {
62 | var frameworkElement = (FrameworkElement)sender;
63 |
64 | var window = Window.GetWindow(frameworkElement);
65 |
66 | if (window is not null)
67 | {
68 | // Transfer InputBindings into our control.
69 | if (!_trackedFrameWorkElementsToBindings.TryGetValue(frameworkElement.GetHashCode(), out var trackingData))
70 | {
71 | trackingData = Tuple.Create(
72 | new WeakReference(frameworkElement),
73 | frameworkElement.InputBindings.Cast().ToList());
74 |
75 | _trackedFrameWorkElementsToBindings.Add(
76 | frameworkElement.GetHashCode(), trackingData);
77 | }
78 |
79 | // Apply Bindings to Window.
80 | foreach (var inputBinding in trackingData.Item2)
81 | {
82 | window.InputBindings.Add(inputBinding);
83 | }
84 |
85 | frameworkElement.InputBindings.Clear();
86 | }
87 | }
88 |
89 | private static void OnFrameworkElementUnLoaded(object sender, RoutedEventArgs e)
90 | {
91 | var frameworkElement = (FrameworkElement)sender;
92 | var window = Window.GetWindow(frameworkElement);
93 | int hashCode = frameworkElement.GetHashCode();
94 |
95 | // Remove Bindings from Window.
96 | if (window is not null)
97 | {
98 | if (_trackedFrameWorkElementsToBindings.TryGetValue(hashCode, out var trackedData))
99 | {
100 | foreach (var binding in trackedData.Item2)
101 | {
102 | frameworkElement.InputBindings.Add(binding);
103 | window.InputBindings.Remove(binding);
104 | }
105 |
106 | trackedData.Item2.Clear();
107 | _trackedFrameWorkElementsToBindings.Remove(hashCode);
108 |
109 | // Catch removed and orphaned entries.
110 | CleanupBindingsDictionary(window, _trackedFrameWorkElementsToBindings);
111 | }
112 | }
113 | }
114 |
115 | private static void OnPropagateInputBindingsToWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
116 | {
117 | ((FrameworkElement)d).Loaded += OnFrameworkElementLoaded;
118 | ((FrameworkElement)d).Unloaded += OnFrameworkElementUnLoaded;
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/SelectedItemsBehavior.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Specialized;
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Controls.Primitives;
6 |
7 | namespace IPConfig.Behaviors;
8 |
9 | ///
10 | /// 不要对绑定的 SelectedItems 属性重新赋值,此行为将对列表内部数据进行增删操作。
11 | ///
12 | /// SelectedItems-Behavior-for-ListBox-and-MultiSelect
13 | ///
14 | ///
15 | public sealed class SelectedItemsBehavior
16 | {
17 | public static readonly DependencyProperty SelectedItemsProperty =
18 | DependencyProperty.RegisterAttached(
19 | "SelectedItems",
20 | typeof(INotifyCollectionChanged),
21 | typeof(SelectedItemsBehavior),
22 | new PropertyMetadata(default(IList), OnSelectedItemsChanged));
23 |
24 | private static readonly DependencyProperty _isBusyProperty =
25 | DependencyProperty.RegisterAttached(
26 | "IsBusy",
27 | typeof(bool),
28 | typeof(SelectedItemsBehavior),
29 | new PropertyMetadata(default(bool)));
30 |
31 | public static IList GetSelectedItems(DependencyObject element)
32 | {
33 | return (IList)element.GetValue(SelectedItemsProperty);
34 | }
35 |
36 | public static void SetSelectedItems(DependencyObject d, INotifyCollectionChanged value)
37 | {
38 | d.SetValue(SelectedItemsProperty, value);
39 | }
40 |
41 | private static bool GetIsBusy(DependencyObject element)
42 | {
43 | return (bool)element.GetValue(_isBusyProperty);
44 | }
45 |
46 | private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
47 | {
48 | IList? selectedItems = null;
49 |
50 | void CollectionChangedEventHandler(object? sender, NotifyCollectionChangedEventArgs args)
51 | {
52 | if (args.OldItems is not null)
53 | {
54 | foreach (object? item in args.OldItems)
55 | {
56 | if (selectedItems.Contains(item))
57 | {
58 | selectedItems.Remove(item);
59 | }
60 | }
61 | }
62 |
63 | if (args.NewItems is not null)
64 | {
65 | foreach (object? item in args.NewItems)
66 | {
67 | if (!selectedItems.Contains(item))
68 | {
69 | selectedItems.Add(item);
70 | }
71 | }
72 | }
73 | }
74 |
75 | if (d is ListView listView)
76 | {
77 | selectedItems = listView.SelectedItems;
78 | listView.SelectionChanged += OnSelectionChanged;
79 | }
80 | else if (d is ListBox listBox)
81 | {
82 | selectedItems = listBox.SelectedItems;
83 | listBox.SelectionChanged += OnSelectionChanged;
84 | }
85 | else if (d is MultiSelector multiSelector)
86 | {
87 | selectedItems = multiSelector.SelectedItems;
88 | multiSelector.SelectionChanged += OnSelectionChanged;
89 | }
90 |
91 | if (selectedItems is null)
92 | {
93 | return;
94 | }
95 |
96 | if (e.OldValue is INotifyCollectionChanged oldValue)
97 | {
98 | oldValue.CollectionChanged -= CollectionChangedEventHandler;
99 | }
100 |
101 | if (e.NewValue is INotifyCollectionChanged newValue)
102 | {
103 | newValue.CollectionChanged += CollectionChangedEventHandler;
104 | }
105 | }
106 |
107 | private static void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
108 | {
109 | if (sender is DependencyObject d)
110 | {
111 | if (!GetIsBusy(d))
112 | {
113 | SetIsBusy(d, true);
114 | var list = GetSelectedItems(d);
115 |
116 | foreach (object? item in e.RemovedItems)
117 | {
118 | if (list.Contains(item))
119 | {
120 | list.Remove(item);
121 | }
122 | }
123 |
124 | foreach (object? item in e.AddedItems)
125 | {
126 | if (!list.Contains(item))
127 | {
128 | list.Add(item);
129 | }
130 | }
131 |
132 | SetIsBusy(d, false);
133 | }
134 | }
135 | }
136 |
137 | private static void SetIsBusy(DependencyObject element, bool value)
138 | {
139 | element.SetValue(_isBusyProperty, value);
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/SplitButtonToggleDropDownBehavior.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 | using System.Windows.Media;
5 | using System.Windows.Shapes;
6 |
7 | using HandyControl.Controls;
8 |
9 | using Microsoft.Xaml.Behaviors;
10 |
11 | namespace IPConfig.Behaviors;
12 |
13 | ///
14 | /// 使 SplitButton 的下拉显示表现为切换打开行为。
15 | ///
16 | public class SplitButtonToggleDropDownBehavior : Behavior
17 | {
18 | protected virtual void OnAssociatedObjectClick(object sender, RoutedEventArgs e)
19 | { }
20 |
21 | protected virtual void OnAssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e, HitTestResult hitTestResult)
22 | { }
23 |
24 | protected override void OnAttached()
25 | {
26 | base.OnAttached();
27 |
28 | AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObject_PreviewMouseLeftButtonDown;
29 | AssociatedObject.Click += AssociatedObject_Click;
30 | }
31 |
32 | protected override void OnDetaching()
33 | {
34 | AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObject_PreviewMouseLeftButtonDown;
35 | AssociatedObject.Click -= AssociatedObject_Click;
36 |
37 | base.OnDetaching();
38 | }
39 |
40 | private void AssociatedObject_Click(object sender, RoutedEventArgs e)
41 | {
42 | OnAssociatedObjectClick(sender, e);
43 | }
44 |
45 | private void AssociatedObject_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
46 | {
47 | var hitTestResult = VisualTreeHelper.HitTest(AssociatedObject, e.GetPosition(AssociatedObject));
48 | OnAssociatedObjectPreviewMouseLeftButtonDown(sender, e, hitTestResult);
49 |
50 | // 如果 VisualHit 为 Path,则鼠标在点击 SplitButton 的 DropDown 位置,
51 | // 如果为 TextBlock,则鼠标在点击 SplitButton 的非 DropDown 位置。
52 | // 如果为 Border,并且其 Child 不为 null,则鼠标在点击 DropDown 位置,否则,鼠标在点击 非 DropDown 位置。
53 | // 如果为 null,则鼠标在点击其他位置。
54 | // 如果不判断 VisualHit,则在点击下拉项前,此事件将被调用,下拉项被关闭,导致下拉项无法被点击到。
55 | if (AssociatedObject.IsDropDownOpen && hitTestResult?.VisualHit is Border or Path or TextBlock)
56 | {
57 | AssociatedObject.IsDropDownOpen = false;
58 | e.Handled = true;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/IPConfig/Behaviors/TripleClickToSelectAllBehavior.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Input;
4 |
5 | namespace IPConfig.Behaviors;
6 |
7 | ///
8 | /// Why does WPF textbox not support triple-click to select all text
9 | ///
10 | public class TripleClickToSelectAllBehavior
11 | {
12 | public static readonly DependencyProperty EnabledProperty =
13 | DependencyProperty.RegisterAttached(
14 | "Enabled",
15 | typeof(bool),
16 | typeof(TripleClickToSelectAllBehavior),
17 | new PropertyMetadata(false, OnPropertyChanged));
18 |
19 | public static bool GetEnabled(DependencyObject element)
20 | {
21 | return (bool)element.GetValue(EnabledProperty);
22 | }
23 |
24 | public static void SetEnabled(DependencyObject element, bool value)
25 | {
26 | element.SetValue(EnabledProperty, value);
27 | }
28 |
29 | private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
30 | {
31 | if (d is TextBox tb)
32 | {
33 | bool enabled = (bool)e.NewValue;
34 |
35 | if (enabled)
36 | {
37 | tb.PreviewMouseLeftButtonDown += OnTextBoxMouseDown;
38 | }
39 | else
40 | {
41 | tb.PreviewMouseLeftButtonDown -= OnTextBoxMouseDown;
42 | }
43 | }
44 | }
45 |
46 | private static void OnTextBoxMouseDown(object sender, MouseButtonEventArgs e)
47 | {
48 | if (sender is TextBox textBox && e.ClickCount == 3)
49 | {
50 | textBox.SelectAll();
51 | textBox.ScrollToHome();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/IPConfig/Controls/AlignDashCornerRect.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Windows;
4 | using System.Windows.Media;
5 |
6 | namespace IPConfig.Controls;
7 |
8 | ///
9 | /// WPF reactangle border with corner from connecting line of two dashes
10 | ///
11 | public class AlignDashCornerRect : FrameworkElement
12 | {
13 | public static readonly DependencyProperty FillProperty =
14 | DependencyProperty.Register(
15 | "Fill",
16 | typeof(Brush),
17 | typeof(AlignDashCornerRect),
18 | new PropertyMetadata(default(Brush), OnVisualPropertyChanged));
19 |
20 | public static readonly DependencyProperty StrokeDashCapProperty =
21 | DependencyProperty.Register(
22 | "StrokeDashCap",
23 | typeof(PenLineCap),
24 | typeof(AlignDashCornerRect),
25 | new PropertyMetadata(PenLineCap.Flat, OnVisualPropertyChanged));
26 |
27 | public static readonly DependencyProperty StrokeDashLineProperty =
28 | DependencyProperty.Register(
29 | "StrokeDashLine",
30 | typeof(double),
31 | typeof(AlignDashCornerRect),
32 | new PropertyMetadata(default(double), OnVisualPropertyChanged));
33 |
34 | public static readonly DependencyProperty StrokeDashSpaceProperty =
35 | DependencyProperty.Register(
36 | "StrokeDashSpace",
37 | typeof(double),
38 | typeof(AlignDashCornerRect),
39 | new PropertyMetadata(default(double), OnVisualPropertyChanged));
40 |
41 | public static readonly DependencyProperty StrokeEndLineCapProperty =
42 | DependencyProperty.Register(
43 | "StrokeEndLineCap",
44 | typeof(PenLineCap),
45 | typeof(AlignDashCornerRect),
46 | new PropertyMetadata(PenLineCap.Flat, OnVisualPropertyChanged));
47 |
48 | public static readonly DependencyProperty StrokeLineJoinProperty =
49 | DependencyProperty.Register(
50 | "StrokeLineJoin",
51 | typeof(PenLineJoin),
52 | typeof(AlignDashCornerRect),
53 | new PropertyMetadata(PenLineJoin.Miter, OnVisualPropertyChanged));
54 |
55 | public static readonly DependencyProperty StrokeMiterLimitProperty =
56 | DependencyProperty.Register(
57 | "StrokeMiterLimit",
58 | typeof(double),
59 | typeof(AlignDashCornerRect),
60 | new PropertyMetadata(10.0d, OnVisualPropertyChanged));
61 |
62 | public static readonly DependencyProperty StrokeProperty =
63 | DependencyProperty.Register(
64 | "Stroke",
65 | typeof(Brush),
66 | typeof(AlignDashCornerRect),
67 | new PropertyMetadata(default(Brush), OnVisualPropertyChanged));
68 |
69 | public static readonly DependencyProperty StrokeStartLineCapProperty =
70 | DependencyProperty.Register(
71 | "StrokeStartLineCap",
72 | typeof(PenLineCap),
73 | typeof(AlignDashCornerRect),
74 | new PropertyMetadata(PenLineCap.Flat, OnVisualPropertyChanged));
75 |
76 | public static readonly DependencyProperty StrokeThicknessProperty =
77 | DependencyProperty.Register(
78 | "StrokeThickness",
79 | typeof(double),
80 | typeof(AlignDashCornerRect),
81 | new PropertyMetadata(default(double), OnVisualPropertyChanged));
82 |
83 | public Brush Fill
84 | {
85 | get => (Brush)GetValue(FillProperty);
86 | set => SetValue(FillProperty, value);
87 | }
88 |
89 | public Brush Stroke
90 | {
91 | get => (Brush)GetValue(StrokeProperty);
92 | set => SetValue(StrokeProperty, value);
93 | }
94 |
95 | public PenLineCap StrokeDashCap
96 | {
97 | get => (PenLineCap)GetValue(StrokeDashCapProperty);
98 | set => SetValue(StrokeDashCapProperty, value);
99 | }
100 |
101 | public double StrokeDashLine
102 | {
103 | get => (double)GetValue(StrokeDashLineProperty);
104 | set => SetValue(StrokeDashLineProperty, value);
105 | }
106 |
107 | public double StrokeDashSpace
108 | {
109 | get => (double)GetValue(StrokeDashSpaceProperty);
110 | set => SetValue(StrokeDashSpaceProperty, value);
111 | }
112 |
113 | public PenLineCap StrokeEndLineCap
114 | {
115 | get => (PenLineCap)GetValue(StrokeEndLineCapProperty);
116 | set => SetValue(StrokeEndLineCapProperty, value);
117 | }
118 |
119 | public PenLineJoin StrokeLineJoin
120 | {
121 | get => (PenLineJoin)GetValue(StrokeLineJoinProperty);
122 | set => SetValue(StrokeLineJoinProperty, value);
123 | }
124 |
125 | public double StrokeMiterLimit
126 | {
127 | get => (double)GetValue(StrokeMiterLimitProperty);
128 | set => SetValue(StrokeMiterLimitProperty, value);
129 | }
130 |
131 | public PenLineCap StrokeStartLineCap
132 | {
133 | get => (PenLineCap)GetValue(StrokeStartLineCapProperty);
134 | set => SetValue(StrokeStartLineCapProperty, value);
135 | }
136 |
137 | public double StrokeThickness
138 | {
139 | get => (double)GetValue(StrokeThicknessProperty);
140 | set => SetValue(StrokeThicknessProperty, value);
141 | }
142 |
143 | public AlignDashCornerRect()
144 | {
145 | SnapsToDevicePixels = true;
146 | UseLayoutRounding = true;
147 | }
148 |
149 | protected override void OnRender(DrawingContext drawingContext)
150 | {
151 | double w = ActualWidth;
152 | double h = ActualHeight;
153 | double x = StrokeThickness / 2.0;
154 |
155 | var horizontalPen = GetPen(ActualWidth - (2.0 * x));
156 | var verticalPen = GetPen(ActualHeight - (2.0 * x));
157 |
158 | drawingContext.DrawRectangle(Fill, null, new Rect(new Point(0, 0), new Size(w, h)));
159 |
160 | drawingContext.DrawLine(horizontalPen, new Point(x, x), new Point(w - x, x));
161 | drawingContext.DrawLine(horizontalPen, new Point(x, h - x), new Point(w - x, h - x));
162 |
163 | drawingContext.DrawLine(verticalPen, new Point(x, x), new Point(x, h - x));
164 | drawingContext.DrawLine(verticalPen, new Point(w - x, x), new Point(w - x, h - x));
165 | }
166 |
167 | private static void OnVisualPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
168 | {
169 | ((AlignDashCornerRect)d).InvalidateVisual();
170 | }
171 |
172 | private IEnumerable GetDashArray(double length)
173 | {
174 | double useableLength = length - StrokeDashLine;
175 | int lines = (int)Math.Round(useableLength / (StrokeDashLine + StrokeDashSpace));
176 | useableLength -= lines * StrokeDashLine;
177 | double actualSpacing = useableLength / lines;
178 |
179 | yield return StrokeDashLine / StrokeThickness;
180 | yield return actualSpacing / StrokeThickness;
181 | }
182 |
183 | private Pen GetPen(double length)
184 | {
185 | var dashArray = GetDashArray(length);
186 |
187 | return new Pen(Stroke, StrokeThickness) {
188 | DashStyle = new DashStyle(dashArray, 0),
189 | DashCap = StrokeDashCap,
190 | StartLineCap = StrokeStartLineCap,
191 | EndLineCap = StrokeEndLineCap,
192 | LineJoin = StrokeLineJoin,
193 | MiterLimit = StrokeMiterLimit
194 | };
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/IPConfig/Controls/BindingProxy.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace IPConfig.Controls;
4 |
5 | ///
6 | /// https://thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
7 | ///
8 | public class BindingProxy : Freezable
9 | {
10 | #region Overrides of Freezable
11 |
12 | protected override Freezable CreateInstanceCore()
13 | {
14 | return new BindingProxy();
15 | }
16 |
17 | #endregion Overrides of Freezable
18 |
19 | // Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
20 | public static readonly DependencyProperty DataProperty =
21 | DependencyProperty.Register(
22 | "Data",
23 | typeof(object),
24 | typeof(BindingProxy),
25 | new UIPropertyMetadata(null));
26 |
27 | public object Data
28 | {
29 | get => GetValue(DataProperty);
30 | set => SetValue(DataProperty, value);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/IPConfig/Controls/DeferredContent.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 |
5 | namespace IPConfig.Controls;
6 |
7 | ///
8 | /// Deferred loading of XAML
9 | ///
10 | public class DeferredContent : ContentPresenter
11 | {
12 | public static readonly DependencyProperty DeferredContentTemplateProperty =
13 | DependencyProperty.Register(
14 | "DeferredContentTemplate",
15 | typeof(DataTemplate),
16 | typeof(DeferredContent),
17 | null);
18 |
19 | public DataTemplate DeferredContentTemplate
20 | {
21 | get => (DataTemplate)GetValue(DeferredContentTemplateProperty);
22 | set => SetValue(DeferredContentTemplateProperty, value);
23 | }
24 |
25 | public event EventHandler? DeferredContentLoaded;
26 |
27 | public DeferredContent()
28 | {
29 | Loaded += HandleLoaded;
30 | }
31 |
32 | public void ShowDeferredContent()
33 | {
34 | if (DeferredContentTemplate is not null)
35 | {
36 | Content = DeferredContentTemplate.LoadContent();
37 | RaiseDeferredContentLoaded();
38 | }
39 | }
40 |
41 | private void HandleLoaded(object sender, RoutedEventArgs e)
42 | {
43 | Loaded -= HandleLoaded;
44 | Dispatcher.BeginInvoke(ShowDeferredContent);
45 | }
46 |
47 | private void RaiseDeferredContentLoaded()
48 | {
49 | DeferredContentLoaded?.Invoke(this, new RoutedEventArgs());
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/IPConfig/Controls/ReadOnlyComboBox.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | using HcComboBox = HandyControl.Controls.ComboBox;
4 |
5 | namespace IPConfig.Controls;
6 |
7 | ///
8 | /// XAML ReadOnly ComboBox
9 | ///
10 | public class ReadOnlyComboBox : HcComboBox
11 | {
12 | private int _oldSelectedIndex = -1;
13 |
14 | //static ReadOnlyComboBox()
15 | //{
16 | // IsDropDownOpenProperty.OverrideMetadata(typeof(ReadOnlyComboBox), new FrameworkPropertyMetadata(
17 | // propertyChangedCallback: delegate { },
18 | // coerceValueCallback: (d, value) => {
19 | // if (((ReadOnlyComboBox)d).IsReadOnly)
20 | // {
21 | // // Prohibit opening the drop down when read only.
22 | // return false;
23 | // }
24 |
25 | // return value;
26 | // }));
27 |
28 | // IsReadOnlyProperty.OverrideMetadata(typeof(ReadOnlyComboBox), new FrameworkPropertyMetadata(
29 | // propertyChangedCallback: (d, e) => {
30 | // // When setting "read only" to false, close the drop down.
31 | // if (e.NewValue is true)
32 | // {
33 | // ((ReadOnlyComboBox)d).IsDropDownOpen = false;
34 | // }
35 | // }));
36 | //}
37 |
38 | public override bool VerifyData()
39 | {
40 | // 设置初始状态不提示错误。
41 | if (ErrorStr is null)
42 | {
43 | return false;
44 | }
45 |
46 | // 修复 HandyControl 无法去除验证错误信息的问题。
47 | // 另一种解决方法是在样式中重写 ErrorTemplate,并用一个与背景色相同的 Border 覆盖 ErrorStr。
48 | bool hasError = base.VerifyData();
49 |
50 | if (!hasError)
51 | {
52 | // 此 ErrorStr 是 HandyControl 的属性,不影响 Validation.Errors 获取错误信息。
53 | ErrorStr = "";
54 | }
55 |
56 | return hasError;
57 | }
58 |
59 | protected override void OnSelectionChanged(SelectionChangedEventArgs e)
60 | {
61 | if (IsReadOnly)
62 | {
63 | SelectedIndex = _oldSelectedIndex;
64 |
65 | // Disallow changing the selection when read only.
66 | e.Handled = true;
67 |
68 | return;
69 | }
70 |
71 | _oldSelectedIndex = SelectedIndex;
72 |
73 | base.OnSelectionChanged(e);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/IPConfig/Converters/BytesToFileSizeConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | using IPConfig.Helpers;
6 | using IPConfig.Languages;
7 |
8 | namespace IPConfig.Converters;
9 |
10 | public class BytesToFileSizeConverter : IValueConverter
11 | {
12 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
13 | {
14 | string size = BytesFormatter.ToFileSize(System.Convert.ToInt64(value));
15 | var key = (LangKey)parameter;
16 | string transport = LangSource.Instance[key];
17 |
18 | return $"{transport}: ~ {size}";
19 | }
20 |
21 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
22 | {
23 | throw new NotImplementedException();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/IPConfig/Converters/CopyContentFormatConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | using IPConfig.Languages;
6 |
7 | namespace IPConfig.Converters;
8 |
9 | public class CopyContentFormatConverter : IValueConverter
10 | {
11 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | return String.Format(LangSource.Instance[LangKey.CopyContent_Format_], value);
14 | }
15 |
16 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
17 | {
18 | throw new NotImplementedException();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/IPConfig/Converters/GetIPCIDRConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Windows.Data;
6 |
7 | namespace IPConfig.Converters;
8 |
9 | public class GetIPCIDRConverter : IValueConverter
10 | {
11 | public object? Convert(object value, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | string? str = value as string;
14 |
15 | if (IPAddress.TryParse(str, out var mask))
16 | {
17 | return mask.GetAddressBytes().Sum(x => System.Convert.ToString(x, 2).Count(x => x == '1'));
18 | }
19 |
20 | return null;
21 | }
22 |
23 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
24 | {
25 | throw new NotImplementedException();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/IPConfig/Converters/MultiValueEqualsConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Globalization;
4 | using System.Linq;
5 | using System.Windows.Data;
6 |
7 | namespace IPConfig.Converters;
8 |
9 | public class MultiValueEqualsConverter : IMultiValueConverter
10 | {
11 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
12 | {
13 | return values.Skip(1).All(x => EqualityComparer