mirror of
https://github.com/2dust/v2rayN.git
synced 2025-12-23 15:22:43 +00:00
Compare commits
24 commits
d99daac318
...
ac7ace312e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac7ace312e | ||
|
|
8438f99b3b | ||
|
|
ccee805045 | ||
|
|
c53362f000 | ||
|
|
952a347b9c | ||
|
|
71d9d7227b | ||
|
|
17e3a16dec | ||
|
|
6e3b2afcc7 | ||
|
|
d8cf86e695 | ||
|
|
ee3575fa95 | ||
|
|
cc95734f11 | ||
|
|
c786e30f89 | ||
|
|
0bd4a3d48a | ||
|
|
879ac65caf | ||
|
|
347b63def8 | ||
|
|
72d377ad2e | ||
|
|
85842dfb8c | ||
|
|
70fe733ea3 | ||
|
|
ec627bdb82 | ||
|
|
4606e78570 | ||
|
|
f00e968b8f | ||
|
|
a87a015c03 | ||
|
|
c559914ff7 | ||
|
|
436d95576e |
16 changed files with 147 additions and 33 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
<Project>
|
<Project>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Version>7.14.9</Version>
|
<Version>7.14.10</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.3.6" />
|
||||||
<PackageVersion Include="Avalonia.Desktop" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.Desktop" Version="11.3.6" />
|
||||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.Diagnostics" Version="11.3.6" />
|
||||||
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.5" />
|
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.3.6" />
|
||||||
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
<PackageVersion Include="CliWrap" Version="3.9.0" />
|
||||||
<PackageVersion Include="Downloader" Version="4.0.3" />
|
<PackageVersion Include="Downloader" Version="4.0.3" />
|
||||||
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,31 @@ public class JsonUtils
|
||||||
{
|
{
|
||||||
private static readonly string _tag = "JsonUtils";
|
private static readonly string _tag = "JsonUtils";
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _defaultDeserializeOptions = new()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
ReadCommentHandling = JsonCommentHandling.Skip
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _defaultSerializeOptions = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _nullValueSerializeOptions = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
|
||||||
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly JsonDocumentOptions _defaultDocumentOptions = new()
|
||||||
|
{
|
||||||
|
CommentHandling = JsonCommentHandling.Skip
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DeepCopy
|
/// DeepCopy
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -34,11 +59,7 @@ public class JsonUtils
|
||||||
{
|
{
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
var options = new JsonSerializerOptions
|
return JsonSerializer.Deserialize<T>(strJson, _defaultDeserializeOptions);
|
||||||
{
|
|
||||||
PropertyNameCaseInsensitive = true
|
|
||||||
};
|
|
||||||
return JsonSerializer.Deserialize<T>(strJson, options);
|
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
@ -59,7 +80,7 @@ public class JsonUtils
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return JsonNode.Parse(strJson);
|
return JsonNode.Parse(strJson, nodeOptions: null, _defaultDocumentOptions);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|
@ -84,12 +105,7 @@ public class JsonUtils
|
||||||
{
|
{
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
var options = new JsonSerializerOptions
|
var options = nullValue ? _nullValueSerializeOptions : _defaultSerializeOptions;
|
||||||
{
|
|
||||||
WriteIndented = indented,
|
|
||||||
DefaultIgnoreCondition = nullValue ? JsonIgnoreCondition.Never : JsonIgnoreCondition.WhenWritingNull,
|
|
||||||
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
|
|
||||||
};
|
|
||||||
result = JsonSerializer.Serialize(obj, options);
|
result = JsonSerializer.Serialize(obj, options);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ public class ClashFmt : BaseFmt
|
||||||
{
|
{
|
||||||
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
public static ProfileItem? ResolveFull(string strData, string? subRemarks)
|
||||||
{
|
{
|
||||||
if (Contains(strData, "port", "socks-port", "proxies"))
|
if (Contains(strData, "external-controller", "-port", "proxies"))
|
||||||
{
|
{
|
||||||
var fileName = WriteAllText(strData, "yaml");
|
var fileName = WriteAllText(strData, "yaml");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -451,7 +451,7 @@ public partial class CoreConfigSingboxService(Config config)
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
await GenOutboundsList(proxyProfiles, singboxConfig, multipleLoad);
|
await GenOutboundsListWithChain(proxyProfiles, singboxConfig, multipleLoad);
|
||||||
|
|
||||||
await GenDns(null, singboxConfig);
|
await GenDns(null, singboxConfig);
|
||||||
await ConvertGeo2Ruleset(singboxConfig);
|
await ConvertGeo2Ruleset(singboxConfig);
|
||||||
|
|
|
||||||
|
|
@ -179,13 +179,21 @@ public partial class CoreConfigSingboxService
|
||||||
if (node.ConfigType == EConfigType.WireGuard)
|
if (node.ConfigType == EConfigType.WireGuard)
|
||||||
{
|
{
|
||||||
var endpoint = JsonUtils.Deserialize<Endpoints4Sbox>(txtOutbound);
|
var endpoint = JsonUtils.Deserialize<Endpoints4Sbox>(txtOutbound);
|
||||||
await GenEndpoint(node, endpoint);
|
var ret = await GenEndpoint(node, endpoint);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return endpoint;
|
return endpoint;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
|
||||||
await GenOutbound(node, outbound);
|
var ret = await GenOutbound(node, outbound);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return outbound;
|
return outbound;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -410,7 +418,7 @@ public partial class CoreConfigSingboxService
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, SingboxConfig singboxConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag)
|
private async Task<int> GenOutboundsListWithChain(List<ProfileItem> nodes, SingboxConfig singboxConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -458,7 +466,7 @@ public partial class CoreConfigSingboxService
|
||||||
var ret = node.ConfigType switch
|
var ret = node.ConfigType switch
|
||||||
{
|
{
|
||||||
EConfigType.PolicyGroup =>
|
EConfigType.PolicyGroup =>
|
||||||
await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
|
await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
|
||||||
EConfigType.ProxyChain =>
|
EConfigType.ProxyChain =>
|
||||||
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
|
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
|
|
@ -612,6 +620,66 @@ public partial class CoreConfigSingboxService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, SingboxConfig singboxConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag)
|
||||||
|
{
|
||||||
|
var resultOutbounds = new List<Outbound4Sbox>();
|
||||||
|
var resultEndpoints = new List<Endpoints4Sbox>(); // For endpoints
|
||||||
|
var proxyTags = new List<string>(); // For selector and urltest outbounds
|
||||||
|
for (var i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
var node = nodes[i];
|
||||||
|
var server = await GenServer(node);
|
||||||
|
if (server is null)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
server.tag = baseTagName + (i + 1).ToString();
|
||||||
|
if (server is Endpoints4Sbox endpoint)
|
||||||
|
{
|
||||||
|
resultEndpoints.Add(endpoint);
|
||||||
|
}
|
||||||
|
else if (server is Outbound4Sbox outbound)
|
||||||
|
{
|
||||||
|
resultOutbounds.Add(outbound);
|
||||||
|
}
|
||||||
|
proxyTags.Add(server.tag);
|
||||||
|
}
|
||||||
|
// Add urltest outbound (auto selection based on latency)
|
||||||
|
if (proxyTags.Count > 0)
|
||||||
|
{
|
||||||
|
var outUrltest = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "urltest",
|
||||||
|
tag = $"{baseTagName}-auto",
|
||||||
|
outbounds = proxyTags,
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
if (multipleLoad == EMultipleLoad.Fallback)
|
||||||
|
{
|
||||||
|
outUrltest.tolerance = 5000;
|
||||||
|
}
|
||||||
|
// Add selector outbound (manual selection)
|
||||||
|
var outSelector = new Outbound4Sbox
|
||||||
|
{
|
||||||
|
type = "selector",
|
||||||
|
tag = baseTagName,
|
||||||
|
outbounds = JsonUtils.DeepCopy(proxyTags),
|
||||||
|
interrupt_exist_connections = false,
|
||||||
|
};
|
||||||
|
outSelector.outbounds.Insert(0, outUrltest.tag);
|
||||||
|
// Insert these at the beginning
|
||||||
|
resultOutbounds.Insert(0, outUrltest);
|
||||||
|
resultOutbounds.Insert(0, outSelector);
|
||||||
|
}
|
||||||
|
singboxConfig.outbounds ??= new();
|
||||||
|
resultOutbounds.AddRange(singboxConfig.outbounds);
|
||||||
|
singboxConfig.outbounds = resultOutbounds;
|
||||||
|
singboxConfig.endpoints ??= new();
|
||||||
|
resultEndpoints.AddRange(singboxConfig.endpoints);
|
||||||
|
singboxConfig.endpoints = resultEndpoints;
|
||||||
|
return await Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenChainOutboundsList(List<ProfileItem> nodes, SingboxConfig singboxConfig, string baseTagName = Global.ProxyTag)
|
private async Task<int> GenChainOutboundsList(List<ProfileItem> nodes, SingboxConfig singboxConfig, string baseTagName = Global.ProxyTag)
|
||||||
{
|
{
|
||||||
var resultOutbounds = new List<Outbound4Sbox>();
|
var resultOutbounds = new List<Outbound4Sbox>();
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,7 @@ public partial class CoreConfigSingboxService
|
||||||
var ret = node.ConfigType switch
|
var ret = node.ConfigType switch
|
||||||
{
|
{
|
||||||
EConfigType.PolicyGroup =>
|
EConfigType.PolicyGroup =>
|
||||||
await GenOutboundsList(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
|
await GenOutboundsListWithChain(childProfiles, singboxConfig, profileGroupItem.MultipleLoad, childBaseTagName),
|
||||||
EConfigType.ProxyChain =>
|
EConfigType.ProxyChain =>
|
||||||
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
|
await GenChainOutboundsList(childProfiles, singboxConfig, childBaseTagName),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ public partial class CoreConfigV2rayService(Config config)
|
||||||
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
ret.Msg = ResUI.FailedGenDefaultConfiguration;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
await GenOutboundsList(proxyProfiles, v2rayConfig);
|
await GenOutboundsListWithChain(proxyProfiles, v2rayConfig);
|
||||||
|
|
||||||
//add balancers
|
//add balancers
|
||||||
await GenObservatory(v2rayConfig, multipleLoad);
|
await GenObservatory(v2rayConfig, multipleLoad);
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,13 @@ namespace ServiceLib.Services.CoreConfig;
|
||||||
|
|
||||||
public partial class CoreConfigV2rayService
|
public partial class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
private async Task<int> GenObservatory(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad)
|
private async Task<int> GenObservatory(V2rayConfig v2rayConfig, EMultipleLoad multipleLoad, string baseTagName = Global.ProxyTag)
|
||||||
{
|
{
|
||||||
if (multipleLoad == EMultipleLoad.LeastPing)
|
if (multipleLoad == EMultipleLoad.LeastPing)
|
||||||
{
|
{
|
||||||
var observatory = new Observatory4Ray
|
var observatory = new Observatory4Ray
|
||||||
{
|
{
|
||||||
subjectSelector = [Global.ProxyTag],
|
subjectSelector = [baseTagName],
|
||||||
probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
probeUrl = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
||||||
probeInterval = "3m",
|
probeInterval = "3m",
|
||||||
enableConcurrency = true,
|
enableConcurrency = true,
|
||||||
|
|
@ -19,7 +19,7 @@ public partial class CoreConfigV2rayService
|
||||||
{
|
{
|
||||||
var burstObservatory = new BurstObservatory4Ray
|
var burstObservatory = new BurstObservatory4Ray
|
||||||
{
|
{
|
||||||
subjectSelector = [Global.ProxyTag],
|
subjectSelector = [baseTagName],
|
||||||
pingConfig = new()
|
pingConfig = new()
|
||||||
{
|
{
|
||||||
destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
destination = AppManager.Instance.Config.SpeedTestItem.SpeedPingTestUrl,
|
||||||
|
|
|
||||||
|
|
@ -552,7 +552,7 @@ public partial class CoreConfigV2rayService
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag)
|
private async Task<int> GenOutboundsListWithChain(List<ProfileItem> nodes, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -597,7 +597,7 @@ public partial class CoreConfigV2rayService
|
||||||
var ret = node.ConfigType switch
|
var ret = node.ConfigType switch
|
||||||
{
|
{
|
||||||
EConfigType.PolicyGroup =>
|
EConfigType.PolicyGroup =>
|
||||||
await GenOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
await GenOutboundsListWithChain(childProfiles, v2rayConfig, childBaseTagName),
|
||||||
EConfigType.ProxyChain =>
|
EConfigType.ProxyChain =>
|
||||||
await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
|
|
@ -721,6 +721,32 @@ public partial class CoreConfigV2rayService
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<int> GenOutboundsList(List<ProfileItem> nodes, V2rayConfig v2rayConfig, string baseTagName = Global.ProxyTag)
|
||||||
|
{
|
||||||
|
var resultOutbounds = new List<Outbounds4Ray>();
|
||||||
|
for (var i = 0; i < nodes.Count; i++)
|
||||||
|
{
|
||||||
|
var node = nodes[i];
|
||||||
|
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
|
||||||
|
if (txtOutbound.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
|
||||||
|
var result = await GenOutbound(node, outbound);
|
||||||
|
if (result != 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
outbound.tag = baseTagName + (i + 1).ToString();
|
||||||
|
resultOutbounds.Add(outbound);
|
||||||
|
}
|
||||||
|
v2rayConfig.outbounds ??= new();
|
||||||
|
resultOutbounds.AddRange(v2rayConfig.outbounds);
|
||||||
|
v2rayConfig.outbounds = resultOutbounds;
|
||||||
|
return await Task.FromResult(0);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<int> GenChainOutboundsList(List<ProfileItem> nodes, V2rayConfig v2RayConfig, string baseTagName = Global.ProxyTag)
|
private async Task<int> GenChainOutboundsList(List<ProfileItem> nodes, V2rayConfig v2RayConfig, string baseTagName = Global.ProxyTag)
|
||||||
{
|
{
|
||||||
var resultOutbounds = new List<Outbounds4Ray>();
|
var resultOutbounds = new List<Outbounds4Ray>();
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ public partial class CoreConfigV2rayService
|
||||||
var ret = node.ConfigType switch
|
var ret = node.ConfigType switch
|
||||||
{
|
{
|
||||||
EConfigType.PolicyGroup =>
|
EConfigType.PolicyGroup =>
|
||||||
await GenOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
await GenOutboundsListWithChain(childProfiles, v2rayConfig, childBaseTagName),
|
||||||
EConfigType.ProxyChain =>
|
EConfigType.ProxyChain =>
|
||||||
await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
await GenChainOutboundsList(childProfiles, v2rayConfig, childBaseTagName),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
|
|
|
||||||
|
|
@ -400,7 +400,7 @@
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
Width="400"
|
Width="400"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
Watermark="1000:2000,3000:4000" />
|
Watermark="1000-2000,3000,4000" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,7 @@
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstRules"
|
x:Name="lstRules"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
|
Background="Transparent"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CanUserResizeColumns="True"
|
CanUserResizeColumns="True"
|
||||||
GridLinesVisibility="All"
|
GridLinesVisibility="All"
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,7 @@
|
||||||
<DataGrid
|
<DataGrid
|
||||||
x:Name="lstRoutings"
|
x:Name="lstRoutings"
|
||||||
AutoGenerateColumns="False"
|
AutoGenerateColumns="False"
|
||||||
|
Background="Transparent"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CanUserResizeColumns="True"
|
CanUserResizeColumns="True"
|
||||||
GridLinesVisibility="All"
|
GridLinesVisibility="All"
|
||||||
|
|
|
||||||
|
|
@ -538,7 +538,7 @@
|
||||||
Width="400"
|
Width="400"
|
||||||
Margin="{StaticResource Margin4}"
|
Margin="{StaticResource Margin4}"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
materialDesign:HintAssist.Hint="1000:2000,3000:4000"
|
materialDesign:HintAssist.Hint="1000-2000,3000,4000"
|
||||||
Style="{StaticResource DefTextBox}" />
|
Style="{StaticResource DefTextBox}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Row="3"
|
Grid.Row="3"
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,8 @@ public partial class RoutingRuleSettingWindow
|
||||||
|
|
||||||
private void RoutingRuleSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
private void RoutingRuleSettingWindow_PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (!lstRules.IsKeyboardFocusWithin)
|
||||||
|
return;
|
||||||
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||||
{
|
{
|
||||||
if (e.Key == Key.A)
|
if (e.Key == Key.A)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue