Created
September 13, 2013 16:19
-
-
Save julesx/6552792 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.ComponentModel; | |
using System.Linq; | |
using System.Runtime.Serialization; | |
namespace d2mSoftware | |
{ | |
[Serializable] | |
public class ServerInfoVm : INotifyPropertyChanged, IDataErrorInfo | |
{ | |
public string FullServerAddress { get { return "https://" + ServerAddress + ":" + ServerPort; } } | |
#region Property Changes | |
public void NotifyPropertyChanged(string _property) | |
{ | |
OnPropertyChanged(_property); | |
} | |
public event PropertyChangedEventHandler PropertyChanged; | |
// Create the OnPropertyChanged method to raise the event | |
protected void OnPropertyChanged(string name) | |
{ | |
PropertyChangedEventHandler handler = PropertyChanged; | |
if (handler != null) | |
{ | |
handler(this, new PropertyChangedEventArgs(name)); | |
} | |
} | |
#endregion | |
#region UI Elements Enabled Controllers | |
public bool AllowRememberPassword { get; set; } | |
public bool AllowDelete { get; set; } | |
#endregion | |
#region Server Info Values | |
public bool LoginThisServer { get; set; } | |
public string ServerName | |
{ | |
get { return _serverName; } | |
set | |
{ | |
_serverName = value; | |
OnPropertyChanged("ServerName"); | |
} | |
} | |
public string ServerPort { get; set; } | |
public string Username { get; set; } | |
public string Password { get; set; } | |
public bool RememberUsername { get; set; } | |
public bool RememberPassword { get; set; } | |
public string ServerAddress | |
{ | |
get { return _serverAddress; } | |
set { _serverAddress = value.Replace("https://", "").Replace("http://", ""); } | |
} | |
private string _serverName; | |
private string _serverAddress; | |
#endregion | |
#region C'Tors | |
public ServerInfoVm() | |
{ | |
AllowRememberPassword = false; | |
RememberUsername = true; | |
} | |
public ServerInfoVm ShallowCopy() | |
{ | |
return (ServerInfoVm)MemberwiseClone(); | |
} | |
public ServerInfoVm(string name, string address, string port, string username, string password, bool rememberUsername, bool rememberPassword, bool allowRememberPassword) | |
{ | |
ServerName = name; | |
ServerAddress = address; | |
ServerPort = port; | |
Username = username; | |
Password = password; | |
RememberUsername = rememberUsername; | |
RememberPassword = rememberPassword; | |
AllowRememberPassword = allowRememberPassword; | |
} | |
#endregion | |
#region IDataErrorInfo Members | |
public string Error | |
{ | |
get { return this[null]; } | |
} | |
public string this[string propertyName] | |
{ | |
get | |
{ | |
string result = string.Empty; | |
propertyName = propertyName ?? string.Empty; | |
if (propertyName == string.Empty || propertyName == "ServerName") | |
{ | |
if (string.IsNullOrEmpty(this.ServerName)) | |
result += "Server name is required" + Environment.NewLine; | |
if (!string.IsNullOrEmpty(this.ServerName) && LoginVm.Current.InstacomServers.Any(item => item != this && item.ServerName == this.ServerName)) | |
result += "Server name must be unique" + Environment.NewLine; | |
} | |
if (propertyName == string.Empty || propertyName == "ServerAddress") | |
if (string.IsNullOrEmpty(this.ServerAddress)) | |
result += "Server address is required" + Environment.NewLine; | |
if (propertyName == string.Empty || propertyName == "ServerPort") | |
{ | |
double n; | |
if (string.IsNullOrEmpty(this.ServerPort) || !Double.TryParse(this.ServerPort, out n)) | |
result += "Server port must be numeric" + Environment.NewLine; | |
} | |
if (propertyName == string.Empty || propertyName == "Username") | |
if (string.IsNullOrEmpty(this.Username)) | |
result += "Username is required" + Environment.NewLine; | |
return result.TrimEnd(); | |
} | |
} | |
#endregion | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Specialized; | |
using System.Windows.Media; | |
using System.Net; | |
using System.Threading; | |
using System.Windows; | |
using System.Windows.Input; | |
namespace d2mSoftware.Windows | |
{ | |
public partial class ServerInfoWindow | |
{ | |
private readonly ServerInfoVm _serverInfoVm = new ServerInfoVm(); | |
private readonly bool _add; | |
#region C'Tors | |
public ServerInfoWindow() | |
{ | |
InitializeComponent(); | |
DataContext = _serverInfoVm; | |
Title = "Add Server"; | |
Loaded += ServerInfo_Loaded; | |
_add = true; | |
} | |
public ServerInfoWindow(ServerInfoVm serverInfoVM) | |
{ | |
InitializeComponent(); | |
_serverInfoVm = serverInfoVM; | |
DataContext = _serverInfoVm; | |
Loaded += ServerInfo_Loaded; | |
_serverInfoVm.AllowDelete = true; | |
if (!String.IsNullOrEmpty(_serverInfoVm.Password)) | |
TxtPassword.Password = "aaaaaaaaa"; | |
Title = "Edit Server"; | |
} | |
#endregion | |
public void TestCredentials(ServerInfoVm serverInfoVm) | |
{ | |
try | |
{ | |
var postData = new NameValueCollection { { "username", serverInfoVm.Username }, { "password", serverInfoVm.Password } }; | |
using (var wb = new WebClient()) | |
{ | |
byte[] rawResponse = wb.UploadValues(serverInfoVm.FullServerAddress + Helper.AuthPostUrl + "TestLogin", "POST", postData); | |
bool response = Convert.ToBoolean(wb.Encoding.GetString(rawResponse)); | |
Application.Current.Dispatcher.Invoke((Action) delegate | |
{ | |
CredentialsTestSpinner.Visibility = Visibility.Hidden; | |
TxtCredentialsTestResult.Text = response ? char.ConvertFromUtf32(0xf00c) : char.ConvertFromUtf32(0xf00d); | |
TxtCredentialsTestResult.Foreground = response ? Brushes.Green : Brushes.Red; | |
}); | |
} | |
} | |
catch (Exception ex) | |
{ | |
Application.Current.Dispatcher.Invoke((Action) delegate | |
{ | |
CredentialsTestSpinner.Visibility = Visibility.Hidden; | |
TxtCredentialsTestResult.Text = char.ConvertFromUtf32(0xf00d); | |
TxtCredentialsTestResult.Foreground = Brushes.Red; | |
}); | |
Helper.LogMan.Error("ServerInfoWindow:TestCredentials ex: " + ex.Message); | |
} | |
} | |
public void ForgotPost(string type, ServerInfoVm serverInfoVM) | |
{ | |
string response = "Error"; | |
try | |
{ | |
var postData = new NameValueCollection { { "id", serverInfoVM.Username }, { "passType", type } }; | |
using (var wb = new WebClient()) | |
{ | |
byte[] rawResponse = wb.UploadValues(serverInfoVM.FullServerAddress + Helper.AuthPostUrl + "ChangePassKeyRequest", "POST", postData); | |
response = wb.Encoding.GetString(rawResponse); | |
Application.Current.Dispatcher.Invoke((Action) delegate | |
{ | |
ForgotKeySpinner.Visibility = Visibility.Hidden; | |
ForgotPasswordSpinner.Visibility = Visibility.Hidden; | |
if (Enum.IsDefined(typeof(LoginReturn), response)) | |
{ | |
if (response == "OK") | |
{ | |
TxtForgotResult.Text = "Check Email"; | |
TxtForgotResult.Foreground = Brushes.Green; | |
} | |
else | |
{ | |
TxtForgotResult.Text = response; | |
TxtForgotResult.Foreground = Brushes.Red; | |
} | |
} | |
}); | |
} | |
} | |
catch (Exception ex) | |
{ | |
Application.Current.Dispatcher.Invoke((Action)delegate | |
{ | |
ForgotKeySpinner.Visibility = Visibility.Hidden; | |
ForgotPasswordSpinner.Visibility = Visibility.Hidden; | |
TxtForgotResult.Text = "Error"; | |
TxtForgotResult.Foreground = Brushes.Red; | |
}); | |
Helper.LogMan.Error("PostHelper:ForgotPost ex: " + ex.Message); | |
} | |
} | |
void ServerInfo_Loaded(object sender, RoutedEventArgs e) | |
{ | |
if (String.IsNullOrEmpty(TxtUsername.Text) && !String.IsNullOrEmpty(TxtServerName.Text)) | |
TxtUsername.Focus(); | |
else if (String.IsNullOrEmpty(TxtPassword.Password) && !String.IsNullOrEmpty(TxtServerName.Text)) | |
TxtPassword.Focus(); | |
else | |
{ | |
TxtServerName.Focus(); | |
TxtServerName.Select(TxtServerName.Text.Length, 0); | |
} | |
TxtPassword.PasswordChanged += TxtPassword_OnPasswordChanged; | |
} | |
private void BtnSave_OnClick(object sender, RoutedEventArgs e) | |
{ | |
if (!ServerValidator.Validate()) | |
ServerValidator.GetFirstInvalidElement().Focus(); | |
else | |
{ | |
SaveServerInfo(); | |
Close(); | |
} | |
} | |
private void SaveServerInfo() | |
{ | |
if (_add) | |
LoginVm.Current.InstacomServers.Add(_serverInfoVm); | |
RebuildProperties(); | |
} | |
private void RebuildProperties() | |
{ | |
Application.Current.Dispatcher.Invoke((Action) delegate | |
{ | |
if (Properties.Settings.Default.Servers == null) | |
Properties.Settings.Default.Servers = new StringCollection(); | |
else | |
Properties.Settings.Default.Servers.Clear(); | |
foreach (var vm in LoginVm.Current.InstacomServers) | |
{ | |
var username = vm.RememberUsername ? vm.Username : ""; | |
var password = vm.RememberPassword ? vm.Password : ""; | |
var vmClone = new ServerInfoVm(vm.ServerName, vm.ServerAddress, vm.ServerPort, username, password, vm.RememberUsername, vm.RememberPassword, vm.AllowRememberPassword); | |
Properties.Settings.Default.Servers.Add(Helper.JSS.Serialize(vmClone)); | |
} | |
Properties.Settings.Default.Save(); | |
}); | |
} | |
private void BtnCancel_OnClick(object sender, RoutedEventArgs e) | |
{ | |
Close(); | |
} | |
private void BtnDelete_OnClick(object sender, RoutedEventArgs e) | |
{ | |
DeleteServerInfo(); | |
Close(); | |
} | |
private void DeleteServerInfo() | |
{ | |
Application.Current.Dispatcher.Invoke((Action)delegate | |
{ | |
LoginVm.Current.InstacomServers.Remove(_serverInfoVm); | |
RebuildProperties(); | |
Properties.Settings.Default.Save(); | |
}); | |
} | |
private void TestServer() | |
{ | |
try | |
{ | |
var webRequest = (HttpWebRequest)WebRequest.Create(_serverInfoVm.FullServerAddress + "/InstacomServer/SignalR/negotiate"); | |
webRequest.AllowAutoRedirect = false; | |
var response = (HttpWebResponse)webRequest.GetResponse(); | |
Application.Current.Dispatcher.Invoke((Action)delegate | |
{ | |
ServerTestSpinner.Visibility = Visibility.Hidden; | |
TxtServerTestResult.Text = response.StatusCode == HttpStatusCode.OK ? char.ConvertFromUtf32(0xf00c) : char.ConvertFromUtf32(0xf00d); | |
TxtServerTestResult.Foreground = response.StatusCode == HttpStatusCode.OK ? Brushes.Green : Brushes.Red; | |
}); | |
} | |
catch (Exception ex) | |
{ | |
Application.Current.Dispatcher.Invoke((Action)delegate | |
{ | |
ServerTestSpinner.Visibility = Visibility.Hidden; | |
TxtServerTestResult.Text = char.ConvertFromUtf32(0xf00d); | |
TxtServerTestResult.Foreground = Brushes.Red; | |
}); | |
Helper.LogMan.Error("ServerInfoWindow:TestServer ex: " + ex.Message); | |
} | |
} | |
private void BtnTestServer_Click(object sender, RoutedEventArgs e) | |
{ | |
if (!ServerValidator.Validate()) | |
ServerValidator.GetFirstInvalidElement().Focus(); | |
else | |
{ | |
TxtServerTestResult.Text = ""; | |
ServerTestSpinner.Visibility = Visibility.Visible; | |
new Thread(TestServer).Start(); | |
} | |
} | |
private void TxtPassword_OnPasswordChanged(object sender, RoutedEventArgs e) | |
{ | |
_serverInfoVm.Password = TxtPassword.Password; | |
} | |
private void BtnForgotPassword_OnPreviewMouseDown(object sender, MouseButtonEventArgs e) | |
{ | |
if (!ServerValidator.Validate()) | |
ServerValidator.GetFirstInvalidElement().Focus(); | |
else if (!CredentialsValidator.Validate()) | |
CredentialsValidator.GetFirstInvalidElement().Focus(); | |
else | |
{ | |
TxtForgotResult.Text = ""; | |
ForgotPasswordSpinner.Visibility = Visibility.Hidden; | |
var thread = new Thread(() => ForgotPost("password", _serverInfoVm)); | |
thread.Start(); | |
} | |
} | |
private void BtnForgotKey_OnPreviewMouseDown(object sender, MouseButtonEventArgs e) | |
{ | |
if (!ServerValidator.Validate()) | |
ServerValidator.GetFirstInvalidElement().Focus(); | |
else if (!CredentialsValidator.Validate()) | |
CredentialsValidator.GetFirstInvalidElement().Focus(); | |
else | |
{ | |
TxtForgotResult.Text = ""; | |
ForgotKeySpinner.Visibility = Visibility.Hidden; | |
var thread = new Thread(() => ForgotPost("key", _serverInfoVm)); | |
thread.Start(); | |
} | |
} | |
private void BtnTestCredentials_OnClick(object sender, RoutedEventArgs e) | |
{ | |
if (!ServerValidator.Validate()) | |
ServerValidator.GetFirstInvalidElement().Focus(); | |
else if (!CredentialsValidator.Validate()) | |
CredentialsValidator.GetFirstInvalidElement().Focus(); | |
else | |
{ | |
TxtCredentialsTestResult.Text = ""; | |
TxtForgotResult.Text = ""; | |
CredentialsTestSpinner.Visibility = Visibility.Visible; | |
var thread = new Thread(() => TestCredentials(_serverInfoVm)); | |
thread.Start(); | |
} | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Window x:Class="d2mSoftware.Windows.ServerInfoWindow" | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | |
xmlns:d2MSoftware="clr-namespace:d2mSoftware" | |
xmlns:userControls="clr-namespace:d2mSoftware.User_Controls" | |
mc:Ignorable="d" | |
UseLayoutRounding="True" ResizeMode="NoResize" | |
Title="ServerInfoWindow" Height="415" Width="300" d:DataContext="{d:DesignData d2MSoftware:ServerInfoVM}"> | |
<Grid> | |
<Grid.Resources> | |
<d2MSoftware:CustomBoolToVisibilityConverter x:Key="CustomBooleanToVisibilityConverter" /> | |
</Grid.Resources> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition Width="5" /> | |
<ColumnDefinition /> | |
<ColumnDefinition Width="5" /> | |
</Grid.ColumnDefinitions> | |
<Grid.RowDefinitions> | |
<RowDefinition Height="5" /> | |
<RowDefinition Height="120" /> | |
<RowDefinition Height="10" /> | |
<RowDefinition Height="200" /> | |
<RowDefinition Height="40" /> | |
<RowDefinition Height="5" /> | |
</Grid.RowDefinitions> | |
<GroupBox Grid.Column="1" Grid.Row="1" BorderThickness="1" BorderBrush="LightGray"> | |
<GroupBox.Header> | |
<TextBlock FontWeight="Bold" Text="Server Information" /> | |
</GroupBox.Header> | |
<Grid> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition Width="65" /> | |
<ColumnDefinition /> | |
<ColumnDefinition Width="20" /> | |
</Grid.ColumnDefinitions> | |
<Grid.RowDefinitions> | |
<RowDefinition Height="5" /> | |
<RowDefinition Height="30" /> | |
<RowDefinition Height="30" /> | |
<RowDefinition Height="30" /> | |
</Grid.RowDefinitions> | |
<d2MSoftware:ErrorProvider Grid.Row="0" Grid.Column="0" x:Name="ServerValidator" /> | |
<Label Grid.Row="1" VerticalAlignment="Center" Content="Name:" /> | |
<TextBox Grid.Row="1" Grid.Column="1" Style="{StaticResource ErrorCheckTextBox}" Text="{Binding ServerName}" TabIndex="0" Height="25" VerticalContentAlignment="Center" Name="TxtServerName" /> | |
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Server:" /> | |
<TextBox Style="{StaticResource ErrorCheckTextBox}" Grid.Row="2" Grid.Column="1" Text="{Binding ServerAddress}" TabIndex="1" Height="25" VerticalAlignment="Center" VerticalContentAlignment="Center" Name="TxtServerAddress" /> | |
<Label Grid.Row="3" Grid.Column="0" Content="Port:" VerticalAlignment="Center" /> | |
<TextBox Grid.Row="3" Grid.Column="1" Style="{StaticResource ErrorCheckTextBox}" Text="{Binding ServerPort}" TabIndex="2" HorizontalAlignment="Left" Height="25" Width="40" VerticalAlignment="Center" VerticalContentAlignment="Center" Name="TxtServerPort" /> | |
<Button BorderBrush="#74C2E1" Background="LightBlue" Style="{DynamicResource RoundedButton}" TabIndex="3" Grid.Row="3" Grid.Column="1" Name="BtnTestServer" Width="75" HorizontalAlignment="Right" Content="Test" Height="25" Click="BtnTestServer_Click" /> | |
<userControls:AjaxSpinnerControl Margin="0,0,2,0" Grid.Row="3" Grid.Column="2" x:Name="ServerTestSpinner" Visibility="Hidden" HorizontalAlignment="Right" /> | |
<TextBlock Name="TxtServerTestResult" Grid.Row="3" Grid.Column="2" HorizontalAlignment="Center" FontFamily="/Resources/#FontAwesome" VerticalAlignment="Center" /> | |
</Grid> | |
</GroupBox> | |
<GroupBox Grid.Row="3" Grid.Column="1"> | |
<GroupBox.Header> | |
<TextBlock FontWeight="Bold" Text="Account Information" /> | |
</GroupBox.Header> | |
<Grid> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition Width="65" /> | |
<ColumnDefinition /> | |
</Grid.ColumnDefinitions> | |
<Grid.RowDefinitions> | |
<RowDefinition Height="5" /> | |
<RowDefinition Height="30" /> | |
<RowDefinition Height="30" /> | |
<RowDefinition Height="5" /> | |
<RowDefinition Height="44" /> | |
<RowDefinition Height="22" /> | |
<RowDefinition Height="22" /> | |
<RowDefinition Height="22" /> | |
</Grid.RowDefinitions> | |
<d2MSoftware:ErrorProvider Grid.Row="0" Grid.Column="0" x:Name="CredentialsValidator" /> | |
<Label Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" Content="Username:" /> | |
<TextBox Grid.Row="1" Grid.Column="1" Style="{StaticResource ErrorCheckTextBox}" Text="{Binding Username}" Width="177" TabIndex="4" Height="25" HorizontalAlignment="Left" VerticalContentAlignment="Center" Name="TxtUsername" /> | |
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" Content="Password:" /> | |
<PasswordBox Grid.Row="2" Grid.Column="1" Width="177" HorizontalAlignment="Left" TabIndex="5" Height="25" VerticalContentAlignment="Center" Name="TxtPassword" /> | |
<Grid Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Width="255"> | |
<Grid.RowDefinitions> | |
<RowDefinition /> | |
<RowDefinition /> | |
</Grid.RowDefinitions> | |
<Grid.ColumnDefinitions> | |
<ColumnDefinition /> | |
<ColumnDefinition Width="20" /> | |
</Grid.ColumnDefinitions> | |
<CheckBox Grid.Row="0" Grid.ColumnSpan="2" TabIndex="5" IsChecked="{Binding RememberUsername}" HorizontalAlignment="Left" VerticalAlignment="Center" Content="Remember username"/> | |
<CheckBox Grid.Row="1" Grid.ColumnSpan="2" TabIndex="6" IsChecked="{Binding RememberPassword}" IsEnabled="{Binding AllowRememberPassword}" HorizontalAlignment="Left" VerticalAlignment="Center" Content="Remember password"/> | |
<Button Grid.RowSpan="2" BorderBrush="#74C2E1" Background="LightBlue" Style="{DynamicResource RoundedButton}" TabIndex="6" Name="BtnTestCredentials" Width="75" HorizontalAlignment="Right" Content="Test" Height="25" Click="BtnTestCredentials_OnClick" /> | |
<userControls:AjaxSpinnerControl x:Name="CredentialsTestSpinner" Grid.RowSpan="2" Grid.Column="1" Visibility="Hidden" /> | |
<TextBlock Name="TxtCredentialsTestResult" Grid.RowSpan="2" Grid.Column="1" HorizontalAlignment="Center" FontFamily="/Resources/#FontAwesome" VerticalAlignment="Center" /> | |
</Grid> | |
<Button Grid.Row="5" Grid.ColumnSpan="2" HorizontalAlignment="Center" Style="{StaticResource HyperlinkLikeButton}" Name="BtnForgotPassword" PreviewMouseDown="BtnForgotPassword_OnPreviewMouseDown" Height="23"> | |
<TextBlock VerticalAlignment="Center" Text="Forget your Password?" /> | |
</Button> | |
<userControls:AjaxSpinnerControl Grid.Row="5" Grid.Column="1" x:Name="ForgotPasswordSpinner" Visibility="Hidden" HorizontalAlignment="Right" Margin="0,0,25,0"/> | |
<Button Grid.Row="6" Grid.ColumnSpan="2" HorizontalAlignment="Center" Style="{StaticResource HyperlinkLikeButton}" Name="BtnForgotKey" PreviewMouseDown="BtnForgotKey_OnPreviewMouseDown" Height="23"> | |
<TextBlock VerticalAlignment="Center" Text="Forget your Private Key?" /> | |
</Button> | |
<userControls:AjaxSpinnerControl Grid.Row="6" Grid.Column="1" x:Name="ForgotKeySpinner" Visibility="Hidden" HorizontalAlignment="Right" Margin="0,0,25,0"/> | |
<TextBlock Grid.Row="7" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Name="TxtForgotResult" /> | |
</Grid> | |
</GroupBox> | |
<UniformGrid Columns="3" Grid.Row="4" Grid.Column="1"> | |
<Button BorderBrush="#74C2E1" Background="LightBlue" Style="{DynamicResource RoundedButton}" Content="Delete" Name="BtnDelete" Click="BtnDelete_OnClick" Width="75" Height="27" Visibility="{Binding AllowDelete, Converter={StaticResource CustomBooleanToVisibilityConverter}}" /> | |
<Button BorderBrush="#74C2E1" Background="LightBlue" Style="{DynamicResource RoundedButton}" Name="BtnCancel" Click="BtnCancel_OnClick" TabIndex="8" Width="75" Height="27" Content="Cancel" /> | |
<Button BorderBrush="#74C2E1" Background="LightBlue" Style="{DynamicResource RoundedButton}" Name="BtnSave" Click="BtnSave_OnClick" TabIndex="7" Width="75" Height="27" Content="Save" /> | |
</UniformGrid> | |
</Grid> | |
</Window> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment