Profiles Select Window

pull/7891/head
DHR60 2025-09-06 17:02:09 +08:00
parent 6391667c15
commit 5db990a2f8
7 changed files with 702 additions and 27 deletions

View File

@ -0,0 +1,298 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Text;
using System.Threading.Tasks;
using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using ReactiveUI.Fody.Helpers;
using Splat;
namespace ServiceLib.ViewModels;
public class ProfilesSelectViewModel : MyReactiveObject
{
#region private prop
private List<ProfileItem> _lstProfile;
private string _serverFilter = string.Empty;
private Dictionary<string, bool> _dicHeaderSort = new();
private string _subIndexId = string.Empty;
#endregion private prop
#region ObservableCollection
public IObservableCollection<ProfileItemModel> ProfileItems { get; } = new ObservableCollectionExtended<ProfileItemModel>();
public IObservableCollection<SubItem> SubItems { get; } = new ObservableCollectionExtended<SubItem>();
[Reactive]
public ProfileItemModel SelectedProfile { get; set; }
public IList<ProfileItemModel> SelectedProfiles { get; set; }
[Reactive]
public SubItem SelectedSub { get; set; }
[Reactive]
public string ServerFilter { get; set; }
#endregion ObservableCollection
#region Init
public ProfilesSelectViewModel(Func<EViewAction, object?, Task<bool>>? updateView)
{
_config = AppManager.Instance.Config;
_updateView = updateView;
_subIndexId = _config.SubIndexId ?? string.Empty;
#region WhenAnyValue && ReactiveCommand
this.WhenAnyValue(
x => x.SelectedSub,
y => y != null && !y.Remarks.IsNullOrEmpty() && _subIndexId != y.Id)
.Subscribe(async c => await SubSelectedChangedAsync(c));
this.WhenAnyValue(
x => x.ServerFilter,
y => y != null && _serverFilter != y)
.Subscribe(async c => await ServerFilterChanged(c));
#endregion WhenAnyValue && ReactiveCommand
#region AppEvents
AppEvents.ProfilesRefreshRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(async _ => await RefreshServersBiz());
AppEvents.DispatcherStatisticsRequested
.AsObservable()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(UpdateStatistics);
#endregion AppEvents
_ = Init();
}
private async Task Init()
{
SelectedProfile = new();
SelectedSub = new();
await RefreshSubscriptions();
await RefreshServers();
}
#endregion Init
#region Actions
public void UpdateStatistics(ServerSpeedItem update)
{
if (!_config.GuiItem.EnableStatistics
|| (update.ProxyUp + update.ProxyDown) <= 0
|| DateTime.Now.Second % 3 != 0)
{
return;
}
try
{
var item = ProfileItems.FirstOrDefault(it => it.IndexId == update.IndexId);
if (item != null)
{
item.TodayDown = Utils.HumanFy(update.TodayDown);
item.TodayUp = Utils.HumanFy(update.TodayUp);
item.TotalDown = Utils.HumanFy(update.TotalDown);
item.TotalUp = Utils.HumanFy(update.TotalUp);
//if (SelectedProfile?.IndexId == item.IndexId)
//{
// var temp = JsonUtils.DeepCopy(item);
// _profileItems.Replace(item, temp);
// SelectedProfile = temp;
//}
//else
//{
// _profileItems.Replace(item, JsonUtils.DeepCopy(item));
//}
}
}
catch
{
}
}
public bool CanOk()
{
return SelectedProfile != null && !SelectedProfile.IndexId.IsNullOrEmpty();
}
public bool SelectFinish()
{
if (!CanOk())
{
return false;
}
_updateView?.Invoke(EViewAction.CloseWindow, null);
return true;
}
#endregion Actions
#region Servers && Groups
private async Task SubSelectedChangedAsync(bool c)
{
if (!c)
{
return;
}
_subIndexId = SelectedSub?.Id;
await RefreshServers();
await _updateView?.Invoke(EViewAction.ProfilesFocus, null);
}
private async Task ServerFilterChanged(bool c)
{
if (!c)
{
return;
}
_serverFilter = ServerFilter;
if (_serverFilter.IsNullOrEmpty())
{
await RefreshServers();
}
}
public async Task RefreshServers()
{
await RefreshServersBiz();
}
private async Task RefreshServersBiz()
{
var lstModel = await GetProfileItemsEx(_subIndexId, _serverFilter);
_lstProfile = JsonUtils.Deserialize<List<ProfileItem>>(JsonUtils.Serialize(lstModel)) ?? [];
ProfileItems.Clear();
ProfileItems.AddRange(lstModel);
if (lstModel.Count > 0)
{
var selected = lstModel.FirstOrDefault(t => t.IndexId == _config.IndexId);
if (selected != null)
{
SelectedProfile = selected;
}
else
{
SelectedProfile = lstModel.First();
}
}
await _updateView?.Invoke(EViewAction.DispatcherRefreshServersBiz, null);
}
public async Task RefreshSubscriptions()
{
SubItems.Clear();
SubItems.Add(new SubItem { Remarks = ResUI.AllGroupServers });
foreach (var item in await AppManager.Instance.SubItems())
{
SubItems.Add(item);
}
if (_subIndexId != null && SubItems.FirstOrDefault(t => t.Id == _subIndexId) != null)
{
SelectedSub = SubItems.FirstOrDefault(t => t.Id == _subIndexId);
}
else
{
SelectedSub = SubItems.First();
}
}
private async Task<List<ProfileItemModel>?> GetProfileItemsEx(string subid, string filter)
{
var lstModel = await AppManager.Instance.ProfileItems(_subIndexId, filter);
//await ConfigHandler.SetDefaultServer(_config, lstModel);
var lstServerStat = (_config.GuiItem.EnableStatistics ? StatisticsManager.Instance.ServerStat : null) ?? [];
var lstProfileExs = await ProfileExManager.Instance.GetProfileExs();
lstModel = (from t in lstModel
join t2 in lstServerStat on t.IndexId equals t2.IndexId into t2b
from t22 in t2b.DefaultIfEmpty()
join t3 in lstProfileExs on t.IndexId equals t3.IndexId into t3b
from t33 in t3b.DefaultIfEmpty()
select new ProfileItemModel
{
IndexId = t.IndexId,
ConfigType = t.ConfigType,
Remarks = t.Remarks,
Address = t.Address,
Port = t.Port,
Security = t.Security,
Network = t.Network,
StreamSecurity = t.StreamSecurity,
Subid = t.Subid,
SubRemarks = t.SubRemarks,
IsActive = t.IndexId == _config.IndexId,
Sort = t33?.Sort ?? 0,
Delay = t33?.Delay ?? 0,
Speed = t33?.Speed ?? 0,
DelayVal = t33?.Delay != 0 ? $"{t33?.Delay}" : string.Empty,
SpeedVal = t33?.Speed > 0 ? $"{t33?.Speed}" : t33?.Message ?? string.Empty,
TodayDown = t22 == null ? "" : Utils.HumanFy(t22.TodayDown),
TodayUp = t22 == null ? "" : Utils.HumanFy(t22.TodayUp),
TotalDown = t22 == null ? "" : Utils.HumanFy(t22.TotalDown),
TotalUp = t22 == null ? "" : Utils.HumanFy(t22.TotalUp)
}).OrderBy(t => t.Sort).ToList();
return lstModel;
}
public async Task<ProfileItem?> GetProfileItem()
{
if (string.IsNullOrEmpty(SelectedProfile?.IndexId))
{
return null;
}
var indexId = SelectedProfile.IndexId;
var item = await AppManager.Instance.GetProfileItem(indexId);
if (item is null)
{
NoticeManager.Instance.Enqueue(ResUI.PleaseSelectServer);
return null;
}
return item;
}
public async Task SortServer(string colName)
{
//if (colName.IsNullOrEmpty())
//{
// return;
//}
//_dicHeaderSort.TryAdd(colName, true);
//_dicHeaderSort.TryGetValue(colName, out bool asc);
//if (await ConfigHandler.SortServers(_config, _config.SubIndexId, colName, asc) != 0)
//{
// return;
//}
//_dicHeaderSort[colName] = !asc;
//await RefreshServers();
}
#endregion Servers && Groups
}

View File

@ -38,15 +38,9 @@ public class ProfilesViewModel : MyReactiveObject
[Reactive]
public SubItem SelectedMoveToGroup { get; set; }
[Reactive]
public ComboItem SelectedServer { get; set; }
[Reactive]
public string ServerFilter { get; set; }
[Reactive]
public bool BlServers { get; set; }
#endregion ObservableCollection
#region Menu
@ -115,11 +109,6 @@ public class ProfilesViewModel : MyReactiveObject
y => y != null && !y.Remarks.IsNullOrEmpty())
.Subscribe(async c => await MoveToGroup(c));
this.WhenAnyValue(
x => x.SelectedServer,
y => y != null && !y.Text.IsNullOrEmpty())
.Subscribe(async c => await ServerSelectedChanged(c));
this.WhenAnyValue(
x => x.ServerFilter,
y => y != null && _serverFilter != y)
@ -266,7 +255,6 @@ public class ProfilesViewModel : MyReactiveObject
SelectedProfile = new();
SelectedSub = new();
SelectedMoveToGroup = new();
SelectedServer = new();
await RefreshSubscriptions();
await RefreshServers();
@ -613,19 +601,6 @@ public class ProfilesViewModel : MyReactiveObject
}
}
private async Task ServerSelectedChanged(bool c)
{
if (!c)
{
return;
}
if (SelectedServer == null || SelectedServer.ID.IsNullOrEmpty())
{
return;
}
await SetDefaultServer(SelectedServer.ID);
}
public async Task ShareServerAsync()
{
var item = await AppManager.Instance.GetProfileItem(SelectedProfile.IndexId);

View File

@ -0,0 +1,210 @@
<base:WindowBase
x:Class="v2rayN.Views.ProfilesSelectWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:v2rayN.Base"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
Title="ProfilesSelectWindow"
Width="800"
Height="450"
x:TypeArguments="vms:ProfilesSelectViewModel"
Style="{StaticResource WindowGlobal}"
mc:Ignorable="d">
<Window.Resources>
<ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<conv:DelayColorConverter x:Key="DelayColorConverter" />
</ResourceDictionary>
</Window.Resources>
<DockPanel Margin="{StaticResource Margin8}">
<StackPanel
Margin="{StaticResource Margin4}"
HorizontalAlignment="Center"
DockPanel.Dock="Bottom"
Orientation="Horizontal">
<Button
x:Name="btnSave"
Width="100"
Content="{x:Static resx:ResUI.TbConfirm}"
IsDefault="True"
Style="{StaticResource DefButton}" />
<Button
x:Name="btnCancel"
Width="100"
Margin="{StaticResource MarginLeftRight8}"
Content="{x:Static resx:ResUI.TbCancel}"
IsCancel="true"
Style="{StaticResource DefButton}" />
</StackPanel>
<Grid>
<DockPanel>
<WrapPanel Margin="{StaticResource Margin4}" DockPanel.Dock="Top">
<ListBox
x:Name="lstGroup"
MaxHeight="200"
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}"
FontSize="{DynamicResource StdFontSize}"
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Remarks}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button
x:Name="btnAutofitColumnWidth"
Width="30"
Height="30"
Margin="{StaticResource MarginLeftRight8}"
AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
</Button>
<TextBox
x:Name="txtServerFilter"
Width="200"
Margin="{StaticResource MarginLeftRight4}"
VerticalContentAlignment="Center"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:TextFieldAssist.HasClearButton="True"
AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}"
Style="{StaticResource DefTextBox}" />
</WrapPanel>
<DataGrid
x:Name="lstProfiles"
materialDesign:DataGridAssist.CellPadding="2,2"
AutoGenerateColumns="False"
BorderThickness="1"
CanUserAddRows="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
EnableRowVirtualization="True"
Focusable="True"
GridLinesVisibility="All"
HeadersVisibility="All"
IsReadOnly="True"
RowHeaderWidth="40"
Style="{StaticResource DefDataGrid}">
<DataGrid.InputBindings>
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Enter" />
</DataGrid.InputBindings>
<DataGrid.Resources>
<Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<base:MyDGTextColumn
Width="80"
Binding="{Binding ConfigType}"
ExName="ConfigType"
Header="{x:Static resx:ResUI.LvServiceType}" />
<base:MyDGTextColumn
Width="150"
Binding="{Binding Remarks}"
ExName="Remarks"
Header="{x:Static resx:ResUI.LvRemarks}" />
<base:MyDGTextColumn
Width="120"
Binding="{Binding Address}"
ExName="Address"
Header="{x:Static resx:ResUI.LvAddress}" />
<base:MyDGTextColumn
Width="60"
Binding="{Binding Port}"
ExName="Port"
Header="{x:Static resx:ResUI.LvPort}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding Network}"
ExName="Network"
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding StreamSecurity}"
ExName="StreamSecurity"
Header="{x:Static resx:ResUI.LvTLS}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding SubRemarks}"
ExName="SubRemarks"
Header="{x:Static resx:ResUI.LvSubscription}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding DelayVal}"
ExName="DelayVal"
Header="{x:Static resx:ResUI.LvTestDelay}"
SortMemberPath="Delay">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Foreground" Value="{Binding Delay, Converter={StaticResource DelayColorConverter}}" />
</Style>
</DataGridTextColumn.ElementStyle>
</base:MyDGTextColumn>
<base:MyDGTextColumn
Width="100"
Binding="{Binding SpeedVal}"
ExName="SpeedVal"
Header="{x:Static resx:ResUI.LvTestSpeed}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</DataGridTextColumn.ElementStyle>
</base:MyDGTextColumn>
<base:MyDGTextColumn
x:Name="colTodayUp"
Width="100"
Binding="{Binding TodayUp}"
ExName="TodayUp"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
<base:MyDGTextColumn
x:Name="colTodayDown"
Width="100"
Binding="{Binding TodayDown}"
ExName="TodayDown"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
<base:MyDGTextColumn
x:Name="colTotalUp"
Width="100"
Binding="{Binding TotalUp}"
ExName="TotalUp"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
<base:MyDGTextColumn
x:Name="colTotalDown"
Width="100"
Binding="{Binding TotalDown}"
ExName="TotalDown"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Grid>
</DockPanel>
</base:WindowBase>

View File

@ -0,0 +1,150 @@
using System.Reactive.Disposables;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Threading;
using ReactiveUI;
using ServiceLib.Manager;
using Splat;
using v2rayN.Base;
namespace v2rayN.Views;
public partial class ProfilesSelectWindow
{
private static Config _config;
public Task<ProfileItem?> ProfileItem => GetFirstProfileItemAsync();
public ProfilesSelectWindow()
{
InitializeComponent();
lstGroup.MaxHeight = Math.Floor(SystemParameters.WorkArea.Height * 0.20 / 40) * 40;
_config = AppManager.Instance.Config;
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
lstProfiles.SelectionChanged += LstProfiles_SelectionChanged;
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
ViewModel = new ProfilesSelectViewModel(UpdateViewHandler);
this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedProfile, v => v.lstProfiles.SelectedItem).DisposeWith(disposables);
this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.lstGroup.ItemsSource).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables);
});
}
#region Event
private async Task<bool> UpdateViewHandler(EViewAction action, object? obj)
{
switch (action)
{
case EViewAction.CloseWindow:
this.DialogResult = true;
break;
}
return await Task.FromResult(true);
}
private void LstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (ViewModel != null)
{
ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast<ProfileItemModel>().ToList();
}
}
private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
{
e.Row.Header = $" {e.Row.GetIndex() + 1}";
}
private void LstProfiles_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
ViewModel?.SelectFinish();
}
private void LstProfiles_ColumnHeader_Click(object sender, RoutedEventArgs e)
{
var colHeader = sender as DataGridColumnHeader;
if (colHeader == null || colHeader.TabIndex < 0 || colHeader.Column == null)
{
return;
}
var colName = ((MyDGTextColumn)colHeader.Column).ExName;
ViewModel?.SortServer(colName);
}
private void menuSelectAll_Click(object sender, RoutedEventArgs e)
{
lstProfiles.SelectAll();
}
private void LstProfiles_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
switch (e.Key)
{
case Key.A:
menuSelectAll_Click(null, null);
break;
}
}
else
{
if (e.Key is Key.Enter or Key.Return)
{
ViewModel?.SelectFinish();
}
}
}
private void BtnAutofitColumnWidth_Click(object sender, RoutedEventArgs e)
{
AutofitColumnWidth();
}
private void AutofitColumnWidth()
{
try
{
foreach (var it in lstProfiles.Columns)
{
it.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}
}
catch (Exception ex)
{
Logging.SaveLog("ProfilesView", ex);
}
}
private void TxtServerFilter_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key is Key.Enter or Key.Return)
{
ViewModel?.RefreshServers();
}
}
public async Task<ProfileItem?> GetFirstProfileItemAsync()
{
var item = await ViewModel?.GetProfileItem();
return item;
}
#endregion Event
}

View File

@ -29,7 +29,7 @@ public partial class ProfilesView
btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
txtServerFilter.PreviewKeyDown += TxtServerFilter_PreviewKeyDown;
lstProfiles.PreviewKeyDown += LstProfiles_PreviewKeyDown;
lstProfiles.SelectionChanged += lstProfiles_SelectionChanged;
lstProfiles.SelectionChanged += LstProfiles_SelectionChanged;
lstProfiles.LoadingRow += LstProfiles_LoadingRow;
menuSelectAll.Click += menuSelectAll_Click;
@ -191,7 +191,7 @@ public partial class ProfilesView
}
}
private void lstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
private void LstProfiles_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (ViewModel != null)
{

View File

@ -259,6 +259,14 @@
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.LvPrevProfileTip}"
AcceptsReturn="True"
Style="{StaticResource MyOutlinedTextBox}" />
<Button
Grid.Row="9"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Click="BtnSelectPrevProfile_Click"
Content="btnSelectPrevProfile"
Style="{StaticResource DefButton}" />
<TextBlock
Grid.Row="10"
@ -276,6 +284,14 @@
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.LvPrevProfileTip}"
AcceptsReturn="True"
Style="{StaticResource MyOutlinedTextBox}" />
<Button
Grid.Row="10"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Click="BtnSelectNextProfile_Click"
Content="btnNextPrevProfile"
Style="{StaticResource DefButton}" />
<TextBlock
Grid.Row="11"

View File

@ -54,4 +54,30 @@ public partial class SubEditWindow
{
txtRemarks.Focus();
}
private async void BtnSelectPrevProfile_Click(object sender, RoutedEventArgs e)
{
var selectWindow = new ProfilesSelectWindow();
if (selectWindow.ShowDialog() == true)
{
var profile = await selectWindow.ProfileItem;
if (profile != null)
{
txtPrevProfile.Text = profile.Remarks;
}
}
}
private async void BtnSelectNextProfile_Click(object sender, RoutedEventArgs e)
{
var selectWindow = new ProfilesSelectWindow();
if (selectWindow.ShowDialog() == true)
{
var profile = await selectWindow.ProfileItem;
if (profile != null)
{
txtNextProfile.Text = profile.Remarks;
}
}
}
}