mirror of
https://github.com/2dust/v2rayN.git
synced 2026-10-18 19:25:01 +03:00
Add HappyEyeballs (#9772)
* Add HappyEyeballs * Clean up the code * Fix
This commit is contained in:
@@ -119,6 +119,7 @@ public static class ConfigHandler
|
|||||||
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
config.SimpleDNSItem.BootstrapDNS ??= Global.DomainPureIPDNSAddress.FirstOrDefault();
|
||||||
config.SimpleDNSItem.ServeStale ??= false;
|
config.SimpleDNSItem.ServeStale ??= false;
|
||||||
config.SimpleDNSItem.ParallelQuery ??= false;
|
config.SimpleDNSItem.ParallelQuery ??= false;
|
||||||
|
config.SimpleDNSItem.EnableHappyEyeballs ??= false;
|
||||||
|
|
||||||
config.SpeedTestItem ??= new();
|
config.SpeedTestItem ??= new();
|
||||||
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
if (config.SpeedTestItem.SpeedTestTimeout < 10)
|
||||||
@@ -170,6 +171,14 @@ public static class ConfigHandler
|
|||||||
Packets = "tlshello",
|
Packets = "tlshello",
|
||||||
};
|
};
|
||||||
config.Fragment4RayItem.MaxSplit ??= "0";
|
config.Fragment4RayItem.MaxSplit ??= "0";
|
||||||
|
|
||||||
|
config.HappyEyeballs4RayItem ??= new()
|
||||||
|
{
|
||||||
|
TryDelayMs = 250,
|
||||||
|
PrioritizeIPv6 = false,
|
||||||
|
Interleave = 1,
|
||||||
|
MaxConcurrentTry = 4,
|
||||||
|
};
|
||||||
if ((config.Fragment4RayItem.Lengths ?? []).Count == 0)
|
if ((config.Fragment4RayItem.Lengths ?? []).Count == 0)
|
||||||
{
|
{
|
||||||
config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"];
|
config.Fragment4RayItem.Lengths = [config.Fragment4RayItem.Length ?? "50-100"];
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ public class Config
|
|||||||
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
public List<KeyEventItem> GlobalHotkeys { get; set; }
|
||||||
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
public List<CoreTypeItem> CoreTypeItem { get; set; }
|
||||||
public SimpleDNSItem SimpleDNSItem { get; set; }
|
public SimpleDNSItem SimpleDNSItem { get; set; }
|
||||||
|
public HappyEyeballs4RayItem HappyEyeballs4RayItem { get; set; }
|
||||||
|
|
||||||
#endregion other entities
|
#endregion other entities
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -285,4 +285,14 @@ public class SimpleDNSItem
|
|||||||
public bool? ParallelQuery { get; set; }
|
public bool? ParallelQuery { get; set; }
|
||||||
public string? Hosts { get; set; }
|
public string? Hosts { get; set; }
|
||||||
public string? DirectExpectedIPs { get; set; }
|
public string? DirectExpectedIPs { get; set; }
|
||||||
|
public bool? EnableHappyEyeballs { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class HappyEyeballs4RayItem
|
||||||
|
{
|
||||||
|
public int? TryDelayMs { get; set; }
|
||||||
|
public bool? PrioritizeIPv6 { get; set; }
|
||||||
|
public int? Interleave { get; set; }
|
||||||
|
public int? MaxConcurrentTry { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -553,11 +553,13 @@ public class Sockopt4Ray
|
|||||||
|
|
||||||
[JsonPropertyName("interface")]
|
[JsonPropertyName("interface")]
|
||||||
public string? Interface { get; set; }
|
public string? Interface { get; set; }
|
||||||
|
public HappyEyeballs4Ray? happyEyeballs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FragmentItem4Ray
|
public class HappyEyeballs4Ray
|
||||||
{
|
{
|
||||||
public string? packets { get; set; }
|
public int? tryDelayMs { get; set; }
|
||||||
public string? length { get; set; }
|
public bool? prioritizeIPv6 { get; set; }
|
||||||
public string? interval { get; set; }
|
public int? interleave { get; set; }
|
||||||
|
public int? maxConcurrentTry { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+18
@@ -3060,6 +3060,24 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Enable Happy Eyeballs 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbEnableHappyEyeballs {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbEnableHappyEyeballs", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path. 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TbEnableHappyEyeballsTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TbEnableHappyEyeballsTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 DNS via Bridge 的本地化字符串。
|
/// 查找类似 DNS via Bridge 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1836,4 +1836,10 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
<value>Not recommended; may cause routing loops.</value>
|
<value>Not recommended; may cause routing loops.</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>Enable Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>Requires the UseIP Strategy. When enabled, it attempts IPv4 and IPv6 connections simultaneously and automatically selects the faster available path.</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -1833,4 +1833,10 @@
|
|||||||
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
<data name="TbProxyDialResolveStrategyTip" xml:space="preserve">
|
||||||
<value>不建议开启,特殊情况可能回环。</value>
|
<value>不建议开启,特殊情况可能回环。</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="TbEnableHappyEyeballs" xml:space="preserve">
|
||||||
|
<value>启用 Happy Eyeballs</value>
|
||||||
|
</data>
|
||||||
|
<data name="TbEnableHappyEyeballsTip" xml:space="preserve">
|
||||||
|
<value>需配合 UseIP 策略使用。启用后将同时尝试 IPv4 和 IPv6 连接,并自动选择更快可用的路径。</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
@@ -43,9 +43,7 @@ public partial class CoreConfigV2rayService
|
|||||||
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
var outbound = _coreConfig.outbounds.FirstOrDefault(t => t is { protocol: "freedom", tag: Global.DirectTag });
|
||||||
if (outbound != null)
|
if (outbound != null)
|
||||||
{
|
{
|
||||||
outbound.streamSettings ??= new();
|
FillSockoptDomainStrategy(outbound, strategy4Freedom);
|
||||||
outbound.streamSettings.sockopt ??= new();
|
|
||||||
outbound.streamSettings.sockopt.domainStrategy = strategy4Freedom;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,9 +72,7 @@ public partial class CoreConfigV2rayService
|
|||||||
.ToList()
|
.ToList()
|
||||||
.ForEach(outbound =>
|
.ForEach(outbound =>
|
||||||
{
|
{
|
||||||
outbound.streamSettings ??= new();
|
FillSockoptDomainStrategy(outbound, strategy4DialProxy);
|
||||||
outbound.streamSettings.sockopt ??= new();
|
|
||||||
outbound.streamSettings.sockopt.domainStrategy = strategy4DialProxy;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -485,4 +481,28 @@ public partial class CoreConfigV2rayService
|
|||||||
};
|
};
|
||||||
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
servers.AsArray().Add(JsonUtils.SerializeToNode(dnsServer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FillSockoptDomainStrategy(Outbounds4Ray outbound, string? domainStrategy, bool skipHappyEyeballs = false)
|
||||||
|
{
|
||||||
|
if (domainStrategy.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
outbound.streamSettings ??= new();
|
||||||
|
outbound.streamSettings.sockopt ??= new();
|
||||||
|
var sockopt = outbound.streamSettings.sockopt;
|
||||||
|
sockopt.domainStrategy = domainStrategy;
|
||||||
|
|
||||||
|
if (skipHappyEyeballs || _config.SimpleDNSItem.EnableHappyEyeballs != true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var happyEyeballsItem = _config.HappyEyeballs4RayItem;
|
||||||
|
sockopt.happyEyeballs ??= new();
|
||||||
|
var happyEyeballs = sockopt.happyEyeballs;
|
||||||
|
happyEyeballs.tryDelayMs = happyEyeballsItem.TryDelayMs;
|
||||||
|
happyEyeballs.prioritizeIPv6 = happyEyeballsItem.PrioritizeIPv6;
|
||||||
|
happyEyeballs.interleave = happyEyeballsItem.Interleave;
|
||||||
|
happyEyeballs.maxConcurrentTry = happyEyeballsItem.MaxConcurrentTry;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,20 +4,21 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
{
|
{
|
||||||
public event EventHandler? RequestClose;
|
public event EventHandler? RequestClose;
|
||||||
|
|
||||||
[Reactive] public bool? UseSystemHosts { get; set; }
|
[Reactive] public bool UseSystemHosts { get; set; }
|
||||||
[Reactive] public bool? AddCommonHosts { get; set; }
|
[Reactive] public bool AddCommonHosts { get; set; }
|
||||||
[Reactive] public bool? FakeIP { get; set; }
|
[Reactive] public bool FakeIP { get; set; }
|
||||||
[Reactive] public bool? BlockBindingQuery { get; set; }
|
[Reactive] public bool BlockBindingQuery { get; set; }
|
||||||
[Reactive] public string? DirectDNS { get; set; }
|
[Reactive] public string DirectDNS { get; set; }
|
||||||
[Reactive] public string? RemoteDNS { get; set; }
|
[Reactive] public string RemoteDNS { get; set; }
|
||||||
[Reactive] public string? BootstrapDNS { get; set; }
|
[Reactive] public string BootstrapDNS { get; set; }
|
||||||
[Reactive] public string? Strategy4Freedom { get; set; }
|
[Reactive] public string Strategy4Freedom { get; set; }
|
||||||
[Reactive] public string? Strategy4Proxy { get; set; }
|
[Reactive] public string Strategy4Proxy { get; set; }
|
||||||
[Reactive] public string? Strategy4ProxyDial { get; set; }
|
[Reactive] public string Strategy4ProxyDial { get; set; }
|
||||||
[Reactive] public string? Hosts { get; set; }
|
[Reactive] public string Hosts { get; set; }
|
||||||
[Reactive] public string? DirectExpectedIPs { get; set; }
|
[Reactive] public string DirectExpectedIPs { get; set; }
|
||||||
[Reactive] public bool? ParallelQuery { get; set; }
|
[Reactive] public bool ParallelQuery { get; set; }
|
||||||
[Reactive] public bool? ServeStale { get; set; }
|
[Reactive] public bool ServeStale { get; set; }
|
||||||
|
[Reactive] public bool EnableHappyEyeballs { get; set; }
|
||||||
|
|
||||||
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
[Reactive] public bool UseSystemHostsCompatible { get; set; }
|
||||||
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
|
[Reactive] public string DomainStrategy4FreedomCompatible { get; set; } = string.Empty;
|
||||||
@@ -68,21 +69,21 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
{
|
{
|
||||||
_config = AppManager.Instance.Config;
|
_config = AppManager.Instance.Config;
|
||||||
var item = _config.SimpleDNSItem;
|
var item = _config.SimpleDNSItem;
|
||||||
UseSystemHosts = item.UseSystemHosts;
|
UseSystemHosts = item.UseSystemHosts ?? false;
|
||||||
AddCommonHosts = item.AddCommonHosts;
|
AddCommonHosts = item.AddCommonHosts ?? false;
|
||||||
FakeIP = item.FakeIP;
|
FakeIP = item.FakeIP ?? false;
|
||||||
BlockBindingQuery = item.BlockBindingQuery;
|
BlockBindingQuery = item.BlockBindingQuery ?? false;
|
||||||
DirectDNS = item.DirectDNS;
|
DirectDNS = item.DirectDNS ?? string.Empty;
|
||||||
RemoteDNS = item.RemoteDNS;
|
RemoteDNS = item.RemoteDNS ?? string.Empty;
|
||||||
BootstrapDNS = item.BootstrapDNS;
|
BootstrapDNS = item.BootstrapDNS ?? string.Empty;
|
||||||
Strategy4Freedom = item.Strategy4Freedom;
|
Strategy4Freedom = item.Strategy4Freedom ?? string.Empty;
|
||||||
Strategy4Proxy = item.Strategy4Proxy;
|
Strategy4Proxy = item.Strategy4Proxy ?? string.Empty;
|
||||||
Strategy4ProxyDial = item.Strategy4ProxyDial;
|
Strategy4ProxyDial = item.Strategy4ProxyDial ?? string.Empty;
|
||||||
Hosts = item.Hosts;
|
Hosts = item.Hosts ?? string.Empty;
|
||||||
DirectExpectedIPs = item.DirectExpectedIPs;
|
DirectExpectedIPs = item.DirectExpectedIPs ?? string.Empty;
|
||||||
ParallelQuery = item.ParallelQuery;
|
ParallelQuery = item.ParallelQuery ?? false;
|
||||||
ServeStale = item.ServeStale;
|
ServeStale = item.ServeStale ?? false;
|
||||||
|
EnableHappyEyeballs = item.EnableHappyEyeballs ?? false;
|
||||||
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
|
var item1 = await AppManager.Instance.GetDNSItem(ECoreType.Xray);
|
||||||
RayCustomDNSEnableCompatible = item1.Enabled;
|
RayCustomDNSEnableCompatible = item1.Enabled;
|
||||||
UseSystemHostsCompatible = item1.UseSystemHosts;
|
UseSystemHostsCompatible = item1.UseSystemHosts;
|
||||||
@@ -115,7 +116,7 @@ public class DNSSettingViewModel : MyReactiveObject, ICloseable
|
|||||||
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
_config.SimpleDNSItem.DirectExpectedIPs = DirectExpectedIPs;
|
||||||
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
|
_config.SimpleDNSItem.ParallelQuery = ParallelQuery;
|
||||||
_config.SimpleDNSItem.ServeStale = ServeStale;
|
_config.SimpleDNSItem.ServeStale = ServeStale;
|
||||||
|
_config.SimpleDNSItem.EnableHappyEyeballs = EnableHappyEyeballs;
|
||||||
if (NormalDNSCompatible.IsNotEmpty())
|
if (NormalDNSCompatible.IsNotEmpty())
|
||||||
{
|
{
|
||||||
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
var obj = JsonUtils.ParseJson(NormalDNSCompatible);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
x:Name="gridBasicDNSSettings"
|
x:Name="gridBasicDNSSettings"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
ColumnDefinitions="Auto,Auto,*"
|
ColumnDefinitions="Auto,Auto,*"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="txtBasicDNSSettingsInvalid"
|
x:Name="txtBasicDNSSettingsInvalid"
|
||||||
@@ -211,6 +211,27 @@
|
|||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togEnableHappyEyeballs"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -340,8 +361,8 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
Classes="TextArea"
|
Classes="TextArea"
|
||||||
TextWrapping="Wrap"
|
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}"
|
||||||
PlaceholderText="{x:Static resx:ResUI.TbDNSHostsConfig}" />
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public partial class DNSSettingWindow : WindowBase<DNSSettingViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.IsChecked).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -241,6 +242,28 @@
|
|||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Margin="{StaticResource Margin8}"
|
Margin="{StaticResource Margin8}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballs}" />
|
||||||
|
<ToggleButton
|
||||||
|
x:Name="togEnableHappyEyeballs"
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="10"
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="{StaticResource Margin8}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Style="{StaticResource ToolbarTextBlock}"
|
||||||
|
Text="{x:Static resx:ResUI.TbEnableHappyEyeballsTip}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public partial class DNSSettingWindow
|
|||||||
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.DirectExpectedIPs, v => v.cmbDirectExpectedIPs.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ParallelQuery, v => v.togParallelQuery.IsChecked).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.ServeStale, v => v.togServeStale.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.EnableHappyEyeballs, v => v.togEnableHappyEyeballs.IsChecked).DisposeWith(disposables);
|
||||||
|
|
||||||
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user