- tweak: Many tweaks!
This commit is contained in:
26
.vscode/launch.json
vendored
Normal file
26
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
// Use IntelliSense to find out which attributes exist for C# debugging
|
||||||
|
// Use hover for the description of the existing attributes
|
||||||
|
// For further information visit https://github.com/dotnet/vscode-csharp/blob/main/debugger-launchjson.md
|
||||||
|
"name": ".NET Core Launch (console)",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "launch",
|
||||||
|
"preLaunchTask": "build",
|
||||||
|
// If you have changed target frameworks, make sure to update the program path.
|
||||||
|
"program": "${workspaceFolder}/Nebula.Launcher/bin/Debug/net9.0/Nebula.Launcher.dll",
|
||||||
|
"args": [],
|
||||||
|
"cwd": "${workspaceFolder}/Nebula.Launcher",
|
||||||
|
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
|
||||||
|
"console": "internalConsole",
|
||||||
|
"stopAtEntry": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": ".NET Core Attach",
|
||||||
|
"type": "coreclr",
|
||||||
|
"request": "attach"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
41
.vscode/tasks.json
vendored
Normal file
41
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "build",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"${workspaceFolder}/Nebula.Launcher/Nebula.Launcher.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "publish",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"publish",
|
||||||
|
"${workspaceFolder}/Nebula.Launcher/Nebula.Launcher.csproj",
|
||||||
|
"/property:GenerateFullPaths=true",
|
||||||
|
"/consoleloggerparameters:NoSummary;ForceNoAlign"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "watch",
|
||||||
|
"command": "dotnet",
|
||||||
|
"type": "process",
|
||||||
|
"args": [
|
||||||
|
"watch",
|
||||||
|
"run",
|
||||||
|
"--project",
|
||||||
|
"${workspaceFolder}/Nebula.Launcher/Nebula.Launcher.csproj"
|
||||||
|
],
|
||||||
|
"problemMatcher": "$msCompile"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -42,4 +42,5 @@ public partial class LocalisationService
|
|||||||
{
|
{
|
||||||
Initialise();
|
Initialise();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
Nebula.Launcher/ViewModels/ContentView/ContentViewBase.cs
Normal file
14
Nebula.Launcher/ViewModels/ContentView/ContentViewBase.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Nebula.Launcher.ViewModels.Pages;
|
||||||
|
|
||||||
|
namespace Nebula.Launcher.ViewModels.ContentView;
|
||||||
|
public abstract class ContentViewBase : ViewModelBase, IDisposable
|
||||||
|
{
|
||||||
|
public virtual void InitialiseWithData(ContentPath path, Stream stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public virtual void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,9 +53,6 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private CurrentAuthInfo? _currAuthTemp;
|
|
||||||
|
|
||||||
public string AuthItemSelect
|
public string AuthItemSelect
|
||||||
{
|
{
|
||||||
set => CurrentAuthServer = value;
|
set => CurrentAuthServer = value;
|
||||||
@@ -65,6 +62,8 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
|||||||
protected override void InitialiseInDesignMode()
|
protected override void InitialiseInDesignMode()
|
||||||
{
|
{
|
||||||
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
|
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
|
||||||
|
AddAccount(new AuthLoginPassword("Binka", "12341", ""));
|
||||||
|
|
||||||
AuthUrls.Add("https://cinka.ru");
|
AuthUrls.Add("https://cinka.ru");
|
||||||
AuthUrls.Add("https://cinka.ru");
|
AuthUrls.Add("https://cinka.ru");
|
||||||
}
|
}
|
||||||
@@ -177,6 +176,7 @@ public partial class AccountInfoViewModel : ViewModelBase, IViewModelPage
|
|||||||
AuthUrls.Clear();
|
AuthUrls.Clear();
|
||||||
var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!;
|
var authUrls = ConfigurationService.GetConfigValue(LauncherConVar.AuthServers)!;
|
||||||
foreach (var url in authUrls) AuthUrls.Add(url);
|
foreach (var url in authUrls) AuthUrls.Add(url);
|
||||||
|
if(authUrls.Length > 0) CurrentAuthServer = authUrls[0];
|
||||||
|
|
||||||
var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent);
|
var currProfile = ConfigurationService.GetConfigValue(LauncherConVar.AuthCurrent);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using Avalonia.Media.Imaging;
|
|||||||
using Avalonia.Platform;
|
using Avalonia.Platform;
|
||||||
using CommunityToolkit.Mvvm.ComponentModel;
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
using Nebula.Launcher.Services;
|
using Nebula.Launcher.Services;
|
||||||
|
using Nebula.Launcher.ViewModels.ContentView;
|
||||||
using Nebula.Launcher.ViewModels.Popup;
|
using Nebula.Launcher.ViewModels.Popup;
|
||||||
using Nebula.Launcher.Views.Pages;
|
using Nebula.Launcher.Views.Pages;
|
||||||
using Nebula.Shared.Models;
|
using Nebula.Shared.Models;
|
||||||
@@ -33,6 +34,10 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModel
|
|||||||
|
|
||||||
private ContentEntry? _selectedEntry;
|
private ContentEntry? _selectedEntry;
|
||||||
[ObservableProperty] private string _serverText = "";
|
[ObservableProperty] private string _serverText = "";
|
||||||
|
[ObservableProperty] private ContentViewBase? _contentView;
|
||||||
|
public bool IsCustomContenView => ContentView != null;
|
||||||
|
|
||||||
|
|
||||||
[GenerateProperty] private ContentService ContentService { get; } = default!;
|
[GenerateProperty] private ContentService ContentService { get; } = default!;
|
||||||
[GenerateProperty] private CancellationService CancellationService { get; } = default!;
|
[GenerateProperty] private CancellationService CancellationService { get; } = default!;
|
||||||
[GenerateProperty] private FileService FileService { get; } = default!;
|
[GenerateProperty] private FileService FileService { get; } = default!;
|
||||||
@@ -43,16 +48,26 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModel
|
|||||||
|
|
||||||
public ObservableCollection<ContentEntry> Entries { get; } = new();
|
public ObservableCollection<ContentEntry> Entries { get; } = new();
|
||||||
|
|
||||||
|
private Dictionary<string, Type> _contentContainers = new();
|
||||||
|
|
||||||
public ContentEntry? SelectedEntry
|
public ContentEntry? SelectedEntry
|
||||||
{
|
{
|
||||||
get => _selectedEntry;
|
get => _selectedEntry;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
SearchText = value?.GetPath().ToString() ?? "";
|
||||||
|
ContentView = null;
|
||||||
|
|
||||||
if (value is { Item: not null })
|
if (value is { Item: not null })
|
||||||
{
|
{
|
||||||
if (FileService.ContentFileApi.TryOpen(value.Item.Value.Hash, out var stream))
|
if (FileService.ContentFileApi.TryOpen(value.Item.Value.Hash, out var stream))
|
||||||
{
|
{
|
||||||
var ext = Path.GetExtension(value.Item.Value.Path);
|
var ext = Path.GetExtension(value.Item.Value.Path);
|
||||||
|
if(TryGetContentViewer(ext, out var contentViewBase)){
|
||||||
|
contentViewBase.InitialiseWithData(value.GetPath(), stream);
|
||||||
|
ContentView = contentViewBase;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var myTempFile = Path.Combine(Path.GetTempPath(), "tempie" + ext);
|
var myTempFile = Path.Combine(Path.GetTempPath(), "tempie" + ext);
|
||||||
|
|
||||||
@@ -83,6 +98,17 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool TryGetContentViewer(string type,[NotNullWhen(true)] out ContentViewBase? contentViewBase){
|
||||||
|
contentViewBase = null;
|
||||||
|
if(!_contentContainers.TryGetValue(type, out var contentViewType) ||
|
||||||
|
!contentViewType.IsAssignableTo(typeof(ContentViewBase)))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
contentViewBase = (ContentViewBase)Activator.CreateInstance(contentViewType)!;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected override void InitialiseInDesignMode()
|
protected override void InitialiseInDesignMode()
|
||||||
{
|
{
|
||||||
@@ -144,15 +170,10 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModel
|
|||||||
if (SelectedEntry == null || !SelectedEntry.GetRoot().TryGetEntry(path, out var centry))
|
if (SelectedEntry == null || !SelectedEntry.GetRoot().TryGetEntry(path, out var centry))
|
||||||
throw new Exception("Not found! " + oriPath.Path);
|
throw new Exception("Not found! " + oriPath.Path);
|
||||||
|
|
||||||
if (appendHistory) AppendHistory(SearchText);
|
|
||||||
SearchText = oriPath.Path;
|
|
||||||
|
|
||||||
SelectedEntry = centry;
|
SelectedEntry = centry;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Console.WriteLine(e);
|
|
||||||
SearchText = oriPath.Path;
|
|
||||||
PopupService.Popup(e);
|
PopupService.Popup(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,11 +191,12 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModel
|
|||||||
|
|
||||||
private async Task<ContentEntry> CreateEntry(string serverUrl)
|
private async Task<ContentEntry> CreateEntry(string serverUrl)
|
||||||
{
|
{
|
||||||
var rurl = serverUrl.ToRobustUrl();
|
|
||||||
var info = await ContentService.GetBuildInfo(rurl, CancellationService.Token);
|
|
||||||
var loading = ViewHelperService.GetViewModel<LoadingContextViewModel>();
|
var loading = ViewHelperService.GetViewModel<LoadingContextViewModel>();
|
||||||
loading.LoadingName = "Loading entry";
|
loading.LoadingName = "Loading entry";
|
||||||
PopupService.Popup(loading);
|
PopupService.Popup(loading);
|
||||||
|
|
||||||
|
var rurl = serverUrl.ToRobustUrl();
|
||||||
|
var info = await ContentService.GetBuildInfo(rurl, CancellationService.Token);
|
||||||
var items = await ContentService.EnsureItems(info.RobustManifestInfo, loading,
|
var items = await ContentService.EnsureItems(info.RobustManifestInfo, loading,
|
||||||
CancellationService.Token);
|
CancellationService.Token);
|
||||||
|
|
||||||
|
|||||||
@@ -40,14 +40,14 @@ public partial class ServerListViewModel : ViewModelBase, IViewModelPage
|
|||||||
//Design think
|
//Design think
|
||||||
protected override void InitialiseInDesignMode()
|
protected override void InitialiseInDesignMode()
|
||||||
{
|
{
|
||||||
ServerViewContainer = new ServerViewContainer(this, RestService, CancellationService, DebugService, ViewHelperService);
|
ServerViewContainer = new ServerViewContainer(this, ViewHelperService);
|
||||||
HubErrors.Add(new Exception("UVI"));
|
HubErrors.Add(new Exception("UVI"));
|
||||||
}
|
}
|
||||||
|
|
||||||
//real think
|
//real think
|
||||||
protected override void Initialise()
|
protected override void Initialise()
|
||||||
{
|
{
|
||||||
ServerViewContainer = new ServerViewContainer(this, RestService, CancellationService, DebugService, ViewHelperService);
|
ServerViewContainer = new ServerViewContainer(this, ViewHelperService);
|
||||||
|
|
||||||
foreach (var info in HubService.ServerList) UnsortedServers.Add(info);
|
foreach (var info in HubService.ServerList) UnsortedServers.Add(info);
|
||||||
|
|
||||||
@@ -142,10 +142,7 @@ public partial class ServerListViewModel : ViewModelBase, IViewModelPage
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class ServerViewContainer(
|
public class ServerViewContainer(
|
||||||
ServerListViewModel serverListViewModel,
|
ServerListViewModel serverListViewModel,
|
||||||
RestService restService,
|
|
||||||
CancellationService cancellationService,
|
|
||||||
DebugService debugService,
|
|
||||||
ViewHelperService viewHelperService
|
ViewHelperService viewHelperService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@@ -210,13 +207,6 @@ public class ServerComparer : IComparer<ServerHubInfo>, IComparer<ServerStatus>,
|
|||||||
|
|
||||||
public int Compare((RobustUrl, ServerStatus) x, (RobustUrl, ServerStatus) y)
|
public int Compare((RobustUrl, ServerStatus) x, (RobustUrl, ServerStatus) y)
|
||||||
{
|
{
|
||||||
if (ReferenceEquals(x, y))
|
|
||||||
return 0;
|
|
||||||
if (ReferenceEquals(null, y))
|
|
||||||
return 1;
|
|
||||||
if (ReferenceEquals(null, x))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return Compare(x.Item2, y.Item2);
|
return Compare(x.Item2, y.Item2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ namespace Nebula.Launcher.ViewModels.Popup;
|
|||||||
public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadingHandler
|
public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadingHandler
|
||||||
{
|
{
|
||||||
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
[GenerateProperty] public override PopupMessageService PopupMessageService { get; }
|
||||||
|
[GenerateProperty] public CancellationService CancellationService { get; }
|
||||||
|
|
||||||
[ObservableProperty] private int _currJobs;
|
[ObservableProperty] private int _currJobs;
|
||||||
|
|
||||||
@@ -40,6 +41,11 @@ public sealed partial class LoadingContextViewModel : PopupViewModelBase, ILoadi
|
|||||||
return ResolvedJobs;
|
return ResolvedJobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Cancel(){
|
||||||
|
CancellationService.Cancel();
|
||||||
|
Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Initialise()
|
protected override void Initialise()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ public partial class ServerEntryModelView : ViewModelBase
|
|||||||
|
|
||||||
private ServerInfo? _serverInfo = null;
|
private ServerInfo? _serverInfo = null;
|
||||||
|
|
||||||
|
private string _lastError = "";
|
||||||
|
|
||||||
public async Task<ServerInfo?> GetServerInfo()
|
public async Task<ServerInfo?> GetServerInfo()
|
||||||
{
|
{
|
||||||
if (_serverInfo == null)
|
if (_serverInfo == null)
|
||||||
@@ -232,6 +234,9 @@ public partial class ServerEntryModelView : ViewModelBase
|
|||||||
|
|
||||||
DebugService.Log("PROCESS EXIT WITH CODE " + Process.ExitCode);
|
DebugService.Log("PROCESS EXIT WITH CODE " + Process.ExitCode);
|
||||||
|
|
||||||
|
if(Process.ExitCode != 0)
|
||||||
|
PopupMessageService.Popup($"Game exit with code {Process.ExitCode}.\nReason: {_lastError}");
|
||||||
|
|
||||||
Process.Dispose();
|
Process.Dispose();
|
||||||
Process = null;
|
Process = null;
|
||||||
}
|
}
|
||||||
@@ -240,6 +245,7 @@ public partial class ServerEntryModelView : ViewModelBase
|
|||||||
{
|
{
|
||||||
if (e.Data != null)
|
if (e.Data != null)
|
||||||
{
|
{
|
||||||
|
_lastError = e.Data;
|
||||||
DebugService.Error(e.Data);
|
DebugService.Error(e.Data);
|
||||||
CurrLog.Append(e.Data);
|
CurrLog.Append(e.Data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<pages:AccountInfoViewModel />
|
<pages:AccountInfoViewModel />
|
||||||
</Design.DataContext>
|
</Design.DataContext>
|
||||||
<Grid
|
<Grid
|
||||||
ColumnDefinitions="*,1*"
|
ColumnDefinitions="3*,2*"
|
||||||
Margin="15"
|
Margin="15"
|
||||||
RowDefinitions="*">
|
RowDefinitions="*">
|
||||||
<StackPanel Grid.Column="1" Grid.Row="0">
|
<StackPanel Grid.Column="1" Grid.Row="0">
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
<Border
|
<Border
|
||||||
BoxShadow="0 1 15 -2 #121212"
|
BoxShadow="0 1 15 -2 #121212"
|
||||||
CornerRadius="0,10,0,10"
|
CornerRadius="0,10,0,10"
|
||||||
Margin="5,5,5,5"
|
Margin="5,5,5,0"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
<Border.Background>
|
<Border.Background>
|
||||||
<LinearGradientBrush EndPoint="50%,100%" StartPoint="50%,0%">
|
<LinearGradientBrush EndPoint="50%,100%" StartPoint="50%,0%">
|
||||||
@@ -50,7 +50,6 @@
|
|||||||
</Border.Background>
|
</Border.Background>
|
||||||
<Panel>
|
<Panel>
|
||||||
<StackPanel Margin="10,5,5,5" Orientation="Horizontal">
|
<StackPanel Margin="10,5,5,5" Orientation="Horizontal">
|
||||||
<Label>Name:</Label>
|
|
||||||
<Label>
|
<Label>
|
||||||
<TextBlock Text="{Binding Login}" />
|
<TextBlock Text="{Binding Login}" />
|
||||||
</Label>
|
</Label>
|
||||||
@@ -107,19 +106,19 @@
|
|||||||
<Label VerticalAlignment="Center">
|
<Label VerticalAlignment="Center">
|
||||||
Login:
|
Login:
|
||||||
</Label>
|
</Label>
|
||||||
<TextBox Text="{Binding CurrentLogin}" />
|
<TextBox Text="{Binding CurrentLogin}" MinWidth="200" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Label HorizontalAlignment="Left" VerticalAlignment="Center">
|
<Label HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||||
Password:
|
Password:
|
||||||
</Label>
|
</Label>
|
||||||
<TextBox PasswordChar="#" Text="{Binding CurrentPassword}" />
|
<TextBox PasswordChar="#" MinWidth="200" Text="{Binding CurrentPassword}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<Label VerticalAlignment="Center">
|
<Label VerticalAlignment="Center">
|
||||||
Auth server:
|
Auth server:
|
||||||
</Label>
|
</Label>
|
||||||
<TextBox Text="{Binding CurrentAuthServer}" />
|
<TextBox MinWidth="200" Text="{Binding CurrentAuthServer}" />
|
||||||
<Button Command="{Binding ExpandAuthUrlCommand}" VerticalAlignment="Stretch">
|
<Button Command="{Binding ExpandAuthUrlCommand}" VerticalAlignment="Stretch">
|
||||||
<Label>+</Label>
|
<Label>+</Label>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -136,7 +135,7 @@
|
|||||||
ItemsSource="{Binding AuthUrls}"
|
ItemsSource="{Binding AuthUrls}"
|
||||||
Margin="5"
|
Margin="5"
|
||||||
SelectedItem="{Binding AuthItemSelect}"
|
SelectedItem="{Binding AuthItemSelect}"
|
||||||
SelectionMode="Toggle">
|
SelectionMode="Single">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Label>
|
<Label>
|
||||||
@@ -155,6 +154,14 @@
|
|||||||
<Label>Auth</Label>
|
<Label>Auth</Label>
|
||||||
</Button>
|
</Button>
|
||||||
</Border>
|
</Border>
|
||||||
|
<Border BoxShadow="{StaticResource DefaultShadow}">
|
||||||
|
<Button
|
||||||
|
Command="{Binding SaveProfileCommand}"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Center">
|
||||||
|
<Label>Save profile</Label>
|
||||||
|
</Button>
|
||||||
|
</Border>
|
||||||
<Button Command="{Binding ExpandAuthViewCommand}" HorizontalAlignment="Right">
|
<Button Command="{Binding ExpandAuthViewCommand}" HorizontalAlignment="Right">
|
||||||
<Label>
|
<Label>
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</Label>
|
</Label>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Button HorizontalAlignment="Right" VerticalAlignment="Center">
|
<Button HorizontalAlignment="Right" VerticalAlignment="Center" Command="{Binding Cancel}">
|
||||||
<Label>Cancel</Label>
|
<Label>Cancel</Label>
|
||||||
</Button>
|
</Button>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|||||||
Reference in New Issue
Block a user