The outbound tag of the route rule can enter a config remarks

https://github.com/2dust/v2rayN/issues/7537
pull/7579/head
2dust 2025-07-13 20:25:53 +08:00
parent 916055d8bd
commit e21c0b4d62
13 changed files with 160 additions and 59 deletions

View File

@ -2724,6 +2724,15 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Can fill in the configuration remarks, please make sure it exist and are unique 的本地化字符串。
/// </summary>
public static string TbRuleOutboundTagTip {
get {
return ResourceManager.GetString("TbRuleOutboundTagTip", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Encryption method (security) 的本地化字符串。 /// 查找类似 Encryption method (security) 的本地化字符串。
/// </summary> /// </summary>

View File

@ -1392,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>URL آزمایش اطلاعات اتصال فعلی</value> <value>URL آزمایش اطلاعات اتصال فعلی</value>
</data> </data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
</root> </root>

View File

@ -1392,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value> <value>Current connection info test URL</value>
</data> </data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
</root> </root>

View File

@ -1392,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>Current connection info test URL</value> <value>Current connection info test URL</value>
</data> </data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
</root> </root>

View File

@ -1392,4 +1392,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>URL для тестирования текущего соединения</value> <value>URL для тестирования текущего соединения</value>
</data> </data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>Can fill in the configuration remarks, please make sure it exist and are unique</value>
</data>
</root> </root>

View File

@ -1389,4 +1389,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>当前连接信息测试地址</value> <value>当前连接信息测试地址</value>
</data> </data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>可以填写配置文件别名,请确保存在并唯一</value>
</data>
</root> </root>

View File

@ -1389,4 +1389,7 @@
<data name="TbSettingsIPAPIUrl" xml:space="preserve"> <data name="TbSettingsIPAPIUrl" xml:space="preserve">
<value>目前連接資訊測試地址</value> <value>目前連接資訊測試地址</value>
</data> </data>
<data name="TbRuleOutboundTagTip" xml:space="preserve">
<value>可以填寫設定檔別名,請確保存在並唯一</value>
</data>
</root> </root>

View File

@ -1166,7 +1166,7 @@ public class CoreConfigSingboxService
{ {
if (item.Enabled) if (item.Enabled)
{ {
await GenRoutingUserRule(item, singboxConfig.route.rules); await GenRoutingUserRule(item, singboxConfig);
} }
} }
} }
@ -1206,7 +1206,7 @@ public class CoreConfigSingboxService
lstDirectExe = new List<string>(directExeSet); lstDirectExe = new List<string>(directExeSet);
} }
private async Task<int> GenRoutingUserRule(RulesItem item, List<Rule4Sbox> rules) private async Task<int> GenRoutingUserRule(RulesItem item, SingboxConfig singboxConfig)
{ {
try try
{ {
@ -1214,6 +1214,8 @@ public class CoreConfigSingboxService
{ {
return 0; return 0;
} }
item.OutboundTag = await GenRoutingUserRuleOutbound(item.OutboundTag, singboxConfig);
var rules = singboxConfig.route.rules;
var rule = new Rule4Sbox() var rule = new Rule4Sbox()
{ {
@ -1365,6 +1367,29 @@ public class CoreConfigSingboxService
return true; return true;
} }
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, SingboxConfig singboxConfig)
{
if (outboundTag is Global.ProxyTag or Global.ProxyTag or Global.BlockTag)
{
return outboundTag;
}
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
if (node == null
|| node.ConfigType == EConfigType.Custom)
{
return Global.ProxyTag;
}
var txtOutbound = EmbedUtils.GetEmbedText(Global.SingboxSampleOutbound);
var outbound = JsonUtils.Deserialize<Outbound4Sbox>(txtOutbound);
await GenOutbound(node, outbound);
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
singboxConfig.outbounds.Add(outbound);
return outbound.tag;
}
private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig) private async Task<int> GenDns(ProfileItem? node, SingboxConfig singboxConfig)
{ {
try try

View File

@ -54,12 +54,12 @@ public class CoreConfigV2rayService
await GenInbounds(v2rayConfig); await GenInbounds(v2rayConfig);
await GenRouting(v2rayConfig);
await GenOutbound(node, v2rayConfig.outbounds.First()); await GenOutbound(node, v2rayConfig.outbounds.First());
await GenMoreOutbounds(node, v2rayConfig); await GenMoreOutbounds(node, v2rayConfig);
await GenRouting(v2rayConfig);
await GenDns(node, v2rayConfig); await GenDns(node, v2rayConfig);
await GenStatistic(v2rayConfig); await GenStatistic(v2rayConfig);
@ -556,6 +556,8 @@ public class CoreConfigV2rayService
{ {
return 0; return 0;
} }
rule.outboundTag = await GenRoutingUserRuleOutbound(rule.outboundTag, v2rayConfig);
if (rule.port.IsNullOrEmpty()) if (rule.port.IsNullOrEmpty())
{ {
rule.port = null; rule.port = null;
@ -627,6 +629,31 @@ public class CoreConfigV2rayService
return await Task.FromResult(0); return await Task.FromResult(0);
} }
private async Task<string?> GenRoutingUserRuleOutbound(string outboundTag, V2rayConfig v2rayConfig)
{
if (outboundTag is Global.ProxyTag or Global.ProxyTag or Global.BlockTag)
{
return outboundTag;
}
var node = await AppHandler.Instance.GetProfileItemViaRemarks(outboundTag);
if (node == null
|| node.ConfigType == EConfigType.Custom
|| node.ConfigType == EConfigType.Hysteria2
|| node.ConfigType == EConfigType.TUIC)
{
return Global.ProxyTag;
}
var txtOutbound = EmbedUtils.GetEmbedText(Global.V2raySampleOutbound);
var outbound = JsonUtils.Deserialize<Outbounds4Ray>(txtOutbound);
await GenOutbound(node, outbound);
outbound.tag = Global.ProxyTag + node.IndexId.ToString();
v2rayConfig.outbounds.Add(outbound);
return outbound.tag;
}
private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound) private async Task<int> GenOutbound(ProfileItem node, Outbounds4Ray outbound)
{ {
try try
@ -659,7 +686,7 @@ public class CoreConfigV2rayService
{ {
usersItem = vnextItem.users.First(); usersItem = vnextItem.users.First();
} }
usersItem.id = node.Id; usersItem.id = node.Id;
usersItem.alterId = node.AlterId; usersItem.alterId = node.AlterId;
usersItem.email = Global.UserEMail; usersItem.email = Global.UserEMail;
@ -1318,7 +1345,7 @@ public class CoreConfigV2rayService
//Previous proxy //Previous proxy
var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile); var prevNode = await AppHandler.Instance.GetProfileItemViaRemarks(subItem.PrevProfile);
string? prevOutboundTag = null; string? prevOutboundTag = null;
if (prevNode is not null if (prevNode is not null
&& prevNode.ConfigType != EConfigType.Custom && prevNode.ConfigType != EConfigType.Custom
&& prevNode.ConfigType != EConfigType.Hysteria2 && prevNode.ConfigType != EConfigType.Hysteria2

View File

@ -2,6 +2,7 @@
x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow" x:Class="v2rayN.Desktop.Views.RoutingRuleDetailsWindow"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrls="clr-namespace:v2rayN.Desktop.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib" xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
@ -22,86 +23,95 @@
<TextBlock <TextBlock
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.LvRemarks}" /> Text="{x:Static resx:ResUI.LvRemarks}" />
<TextBox <TextBox
x:Name="txtRemarks" x:Name="txtRemarks"
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Width="200" Width="300"
HorizontalAlignment="Left" Margin="{StaticResource Margin4}"
Margin="{StaticResource Margin4}" /> HorizontalAlignment="Left" />
<ToggleSwitch <ToggleSwitch
x:Name="togEnabled" x:Name="togEnabled"
Grid.Row="0" Grid.Row="0"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" /> VerticalAlignment="Center" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="outboundTag" /> Text="outboundTag" />
<ComboBox <ctrls:AutoCompleteBox
x:Name="cmbOutboundTag" Name="cmbOutboundTag"
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Width="200" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
MaxDropDownHeight="1000" /> Text="{Binding SelectedSource.OutboundTag, Mode=TwoWay}" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
Grid.Column="2" Grid.Column="2"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" /> HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="port" /> Text="port" />
<TextBox <TextBox
x:Name="txtPort" x:Name="txtPort"
Grid.Row="2" Grid.Row="2"
Grid.Column="1" Grid.Column="1"
Width="200" Width="300"
HorizontalAlignment="Left" Margin="{StaticResource Margin4}"
Margin="{StaticResource Margin4}" /> HorizontalAlignment="Left" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="{StaticResource Margin4}"> Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="protocol" />
<ListBox
x:Name="clbProtocol"
Grid.Row="3"
Grid.Column="1"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
SelectionMode="Multiple,Toggle"
Theme="{DynamicResource CardCheckGroupListBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center">
<HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click"> <HyperlinkButton Classes="WithIcon" Click="linkRuleobjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" /> <TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
</HyperlinkButton> </HyperlinkButton>
</TextBlock> </TextBlock>
<TextBlock
Grid.Row="3"
Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}"
Text="protocol" />
<ListBox
x:Name="clbProtocol"
Grid.Row="3"
Grid.Column="1"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}"
SelectionMode="Multiple,Toggle"
Theme="{DynamicResource CardCheckGroupListBox}" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="inboundTag" /> Text="inboundTag" />
<ListBox <ListBox
x:Name="clbInboundTag" x:Name="clbInboundTag"
@ -113,35 +123,36 @@
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
Grid.Column="2" Grid.Column="2"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" /> Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="0" Grid.Column="0"
VerticalAlignment="Center"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="network" /> Text="network" />
<ComboBox <ComboBox
x:Name="cmbNetwork" x:Name="cmbNetwork"
Grid.Row="5" Grid.Row="5"
Grid.Column="1" Grid.Column="1"
Width="200" Width="300"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
MaxDropDownHeight="1000" /> MaxDropDownHeight="1000" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
Grid.Column="2" Grid.Column="2"
HorizontalAlignment="Left"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbRoutingTips}" /> Text="{x:Static resx:ResUI.TbRoutingTips}" />
</Grid> </Grid>
<StackPanel <StackPanel
HorizontalAlignment="Right"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Right"
DockPanel.Dock="Bottom" DockPanel.Dock="Bottom"
Orientation="Horizontal"> Orientation="Horizontal">
<StackPanel <StackPanel

View File

@ -23,9 +23,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged; clbInboundTag.SelectionChanged += ClbInboundTag_SelectionChanged;
ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler); ViewModel = new RoutingRuleDetailsViewModel(rulesItem, UpdateViewHandler);
cmbOutboundTag.Items.Add(Global.ProxyTag); cmbOutboundTag.ItemsSource = new List<string> { Global.ProxyTag, Global.DirectTag, Global.BlockTag };
cmbOutboundTag.Items.Add(Global.DirectTag);
cmbOutboundTag.Items.Add(Global.BlockTag);
Global.RuleProtocols.ForEach(it => Global.RuleProtocols.ForEach(it =>
{ {
clbProtocol.Items.Add(it); clbProtocol.Items.Add(it);
@ -54,7 +52,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.OutboundTag, v => v.cmbOutboundTag.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Port, v => v.txtPort.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Network, v => v.cmbNetwork.SelectedValue).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Enabled, v => v.togEnabled.IsChecked).DisposeWith(disposables);
@ -80,7 +78,7 @@ public partial class RoutingRuleDetailsWindow : WindowBase<RoutingRuleDetailsVie
private void Window_Loaded(object? sender, RoutedEventArgs e) private void Window_Loaded(object? sender, RoutedEventArgs e)
{ {
cmbOutboundTag.Focus(); txtRemarks.Focus();
} }
private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e) private void ClbProtocol_SelectionChanged(object? sender, SelectionChangedEventArgs e)

View File

@ -53,7 +53,8 @@
Grid.Row="0" Grid.Row="0"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
VerticalAlignment="Center" />
<TextBlock <TextBlock
Grid.Row="1" Grid.Row="1"
@ -68,6 +69,7 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
IsEditable="True"
MaxDropDownHeight="1000" MaxDropDownHeight="1000"
Style="{StaticResource DefComboBox}" /> Style="{StaticResource DefComboBox}" />
<TextBlock <TextBlock
@ -75,8 +77,9 @@
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRuleMatchingTips}" /> Text="{x:Static resx:ResUI.TbRuleOutboundTagTip}" />
<TextBlock <TextBlock
Grid.Row="2" Grid.Row="2"
@ -97,13 +100,10 @@
Grid.Row="2" Grid.Row="2"
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"> Style="{StaticResource ToolbarTextBlock}"
<Hyperlink Click="linkRuleobjectDoc_Click"> Text="{x:Static resx:ResUI.TbRuleMatchingTips}" />
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<TextBlock <TextBlock
Grid.Row="3" Grid.Row="3"
@ -120,6 +120,17 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
FontSize="{DynamicResource StdFontSize}" FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" /> Style="{StaticResource MaterialDesignFilterChipPrimaryListBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}">
<Hyperlink Click="linkRuleobjectDoc_Click">
<TextBlock Text="{x:Static resx:ResUI.TbRuleobjectDoc}" />
<materialDesign:PackIcon Kind="Link" />
</Hyperlink>
</TextBlock>
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@ -140,6 +151,7 @@
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" /> Text="{x:Static resx:ResUI.TbRoutingInboundTagTips}" />
@ -164,6 +176,7 @@
Grid.Column="2" Grid.Column="2"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}" Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbRoutingTips}" /> Text="{x:Static resx:ResUI.TbRoutingTips}" />
</Grid> </Grid>

View File

@ -74,7 +74,7 @@ public partial class RoutingRuleDetailsWindow
private void Window_Loaded(object sender, RoutedEventArgs e) private void Window_Loaded(object sender, RoutedEventArgs e)
{ {
cmbOutboundTag.Focus(); txtRemarks.Focus();
} }
private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) private void ClbProtocol_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)