Skip to content

Commit

Permalink
Merge pull request #64 from ChrisPulman/FixForPasswordBox
Browse files Browse the repository at this point in the history
Refactor and Fix PasswordBox
  • Loading branch information
ChrisPulman authored Feb 17, 2024
2 parents 34a5e26 + 4024b20 commit a0cb486
Show file tree
Hide file tree
Showing 18 changed files with 934 additions and 558 deletions.
1 change: 1 addition & 0 deletions src/CrissCross.WPF.UI.Test/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public partial class App
services.AddSingleton<DashboardPage>().AddSingleton<DashboardViewModel>();
services.AddSingleton<DataPage>().AddSingleton<DataViewModel>();
services.AddSingleton<SettingsPage>().AddSingleton<SettingsViewModel>();
services.AddSingleton<LoginPage>().AddSingleton<LoginViewModel>();

// Configuration
services.Configure<AppConfig>(context.Configuration.GetSection(nameof(AppConfig)));
Expand Down
Binary file added src/CrissCross.WPF.UI.Test/Assets/key-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/CrissCross.WPF.UI.Test/Assets/user-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
63 changes: 63 additions & 0 deletions src/CrissCross.WPF.UI.Test/ViewModels/LoginViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// Copyright (c) Chris Pulman. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reactive;
using ReactiveUI;

namespace CrissCross.WPF.UI.Test;

/// <summary>
/// Login View Model.
/// </summary>
/// <seealso cref="CrissCross.RxObject" />
public class LoginViewModel : RxObject
{
private string? _password;
private string? _username;

/// <summary>
/// Initializes a new instance of the <see cref="LoginViewModel"/> class.
/// </summary>
public LoginViewModel() =>
LoginCommand = ReactiveCommand.Create(() =>
{
// This is a placeholder for the actual login logic
if (Password == "1234" && Username == "User")
{
Password = string.Empty;
Username = string.Empty;
}
});

/// <summary>
/// Gets the login command.
/// </summary>
/// <value>
/// The login command.
/// </value>
public ReactiveCommand<Unit, Unit> LoginCommand { get; }

/// <summary>
/// Gets or sets the password.
/// </summary>
/// <value>
/// The password.
/// </value>
public string? Password
{
get => _password;
set => this.RaiseAndSetIfChanged(ref _password, value);
}

/// <summary>
/// Gets or sets the username.
/// </summary>
/// <value>
/// The username.
/// </value>
public string? Username
{
get => _username;
set => this.RaiseAndSetIfChanged(ref _username, value);
}
}
6 changes: 6 additions & 0 deletions src/CrissCross.WPF.UI.Test/ViewModels/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ private void InitializeViewModel()
Content = "Data",
Icon = new SymbolIcon { Symbol = SymbolRegular.DataHistogram24 },
TargetPageType = typeof(Views.Pages.DataPage)
},
new NavigationViewItem()
{
Content = "Login",
Icon = new SymbolIcon { Symbol = SymbolRegular.LockClosed24 },
TargetPageType = typeof(Views.Pages.LoginPage)
}
];

Expand Down
181 changes: 181 additions & 0 deletions src/CrissCross.WPF.UI.Test/Views/Pages/LoginPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
<Page
x:Class="CrissCross.WPF.UI.Test.Views.Pages.LoginPage"
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:local="clr-namespace:CrissCross.WPF.UI.Test.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="https://github.com/ChrisPulman/CrissCross.ui"
Width="800"
Height="550"
d:DataContext="{d:DesignInstance local:LoginPage,
IsDesignTimeCreatable=False}"
Background="Transparent"
mc:Ignorable="d">

<Border CornerRadius="12">
<Border
BorderThickness="2"
CornerRadius="10"
Opacity="0.95">

<Border.BorderBrush>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Offset="0" Color="{DynamicResource SystemAccentColorSecondary}" />
<GradientStop Offset="0.75" Color="{DynamicResource SystemAccentColorTertiary}" />
<GradientStop Offset="1" Color="{DynamicResource SystemAccentColorPrimary}" />
</LinearGradientBrush>
</Border.BorderBrush>
<!-- Background color. -->
<Border.Background>
<LinearGradientBrush StartPoint="0,1" EndPoint="1,0">
<GradientStop Offset="0" Color="#060531" />
<GradientStop Offset="1" Color="#1B1448" />
</LinearGradientBrush>
</Border.Background>

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition />
</Grid.RowDefinitions>

<ui:TextBlock
Grid.Column="0"
Margin="10,0,0,0"
VerticalAlignment="Center"
FontFamily="Montserrat"
FontSize="10"
Foreground="DarkGray"
Text="LOG IN" />
<StackPanel
Grid.Row="1"
Width="320"
Orientation="Vertical">

<ui:Image
Width="100"
Height="100"
Source="/Assets/CrissCrossIcon_256.png" />

<ui:TextBlock
HorizontalAlignment="Center"
FontFamily="Montserrat"
FontSize="25"
FontWeight="Medium"
Foreground="White"
Text="CrissCross Test App" />

<ui:TextBlock
Margin="0,5,0,0"
FontFamily="Montserrat"
FontSize="12"
FontWeight="Medium"
Foreground="LightGray"
Text="A Reactive User Interface for Wpf."
TextAlignment="Center"
TextWrapping="Wrap" />

<StackPanel
Width="220"
Margin="0,35,0,0"
Orientation="Vertical">
<ui:TextBlock
FontFamily="Montserrat"
FontSize="12"
FontWeight="Medium"
Foreground="DarkGray"
Text="Username" />

<ui:TextBox
x:Name="UserName"
Height="28"
Margin="0,5,0,0"
Padding="20,0,0,0"
VerticalContentAlignment="Center"
BorderBrush="DarkGray"
BorderThickness="0,0,0,2"
CaretBrush="LightGray"
ClearButtonEnabled="False"
FontFamily="Montserrat"
FontSize="13"
FontWeight="Medium"
Foreground="White">
<ui:TextBox.Icon>
<ui:ImageIcon
Width="16"
Height="16"
Source="/Assets/user-icon.png" />
</ui:TextBox.Icon>
</ui:TextBox>

<ui:TextBlock
Margin="0,15,0,0"
FontFamily="Montserrat"
FontSize="12"
FontWeight="Medium"
Foreground="DarkGray"
Text="Password" />

<ui:PasswordBox
x:Name="Password"
Height="28"
Margin="0,5,0,0"
Padding="20,0,0,0"
VerticalContentAlignment="Center"
BorderBrush="DarkGray"
BorderThickness="0,0,0,2"
CaretBrush="LightGray"
FontFamily="Montserrat"
FontSize="13"
FontWeight="Medium"
Foreground="White">
<ui:PasswordBox.Icon>
<ui:ImageIcon
Width="16"
Height="16"
Source="/Assets/key-icon.png" />
</ui:PasswordBox.Icon>
</ui:PasswordBox>
</StackPanel>


<ui:Button
x:Name="LoginButton"
Margin="0,50,0,0"
BorderThickness="0"
Content="LOG IN"
Cursor="Hand"
FontFamily="Montserrat"
FontSize="12"
Foreground="White"
IsDefault="true">

<ui:Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="#462AD8" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#28AEED" />
</Trigger>
</Style.Triggers>
</Style>
</ui:Button.Style>

<ui:Button.Template>
<ControlTemplate TargetType="Button">
<Border
Width="150"
Height="40"
Background="{TemplateBinding Background}"
CornerRadius="20">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</ui:Button.Template>
</ui:Button>
</StackPanel>
</Grid>
</Border>
</Border>
</Page>
41 changes: 41 additions & 0 deletions src/CrissCross.WPF.UI.Test/Views/Pages/LoginPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Chris Pulman. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reactive.Linq;
using ReactiveMarbles.ObservableEvents;
using ReactiveUI;

namespace CrissCross.WPF.UI.Test.Views.Pages;

/// <summary>
/// Interaction logic for LoginView.xaml.
/// </summary>
public partial class LoginPage
{
/// <summary>
/// Initializes a new instance of the <see cref="LoginPage" /> class.
/// </summary>
/// <param name="loginViewModel">The login view model.</param>
public LoginPage(LoginViewModel loginViewModel)
{
InitializeComponent();
ViewModel = loginViewModel;

// Bind the password
ViewModel.WhenAnyValue(x => x.Password).Subscribe(password => Password.Password = password ?? string.Empty);
Password.Events().PasswordChanged.Select(_ => Password.Password).BindTo(ViewModel, x => x.Password);

// Bind the username
ViewModel.WhenAnyValue(x => x.Username).Subscribe(x => UserName.Text = x);
UserName.Events().TextChanged.Select(_ => UserName.Text).BindTo(ViewModel, x => x.Username);

LoginButton.Command = ViewModel.LoginCommand;
UserName.Focus();
}

/// <summary>
/// Gets viewModel used by the view.
/// Optionally, it may implement <see cref="T:CrissCross.WPF.UI.Controls.INavigationAware" /> and be navigated by <see cref="T:CrissCross.WPF.UI.Controls.INavigationView" />.
/// </summary>
public LoginViewModel ViewModel { get; }
}
Loading

0 comments on commit a0cb486

Please sign in to comment.