├── .gitignore
├── example
├── PasswordBoxMVVMExample.csproj.user
├── App.xaml
├── PasswordBoxMVVMExample.csproj
├── ViewModels
│ ├── ViewModelBase.cs
│ └── LoginViewModel.cs
├── AssemblyInfo.cs
├── MainWindow.xaml
├── Views
│ ├── LoginView.xaml.cs
│ └── LoginView.xaml
├── App.xaml.cs
├── MainWindow.xaml.cs
└── Commands
│ └── LoginCommand.cs
├── command-reference.txt
├── PasswordBoxMVVM
├── PasswordBoxMVVM.csproj.user
├── AssemblyInfo.cs
├── Components
│ ├── BindablePasswordBox.xaml
│ └── BindablePasswordBox.xaml.cs
└── PasswordBoxMVVM.csproj
├── .github
└── workflows
│ └── nuget.yml
└── PasswordBoxMVVM.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | .vs/
2 | obj/
3 | bin/
4 | secrets.txt
5 |
--------------------------------------------------------------------------------
/example/PasswordBoxMVVMExample.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/command-reference.txt:
--------------------------------------------------------------------------------
1 | # PACKING
2 | dotnet pack -p:PackageVersion=1.0.0 --configuration Release
3 |
4 | # PUSHING
5 | dotnet nuget push ./bin/Release/PasswordBoxMVVM.1.0.0.nupkg -s https://api.nuget.org/v3/index.json -k
6 |
7 |
--------------------------------------------------------------------------------
/PasswordBoxMVVM/PasswordBoxMVVM.csproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Designer
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/App.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/PasswordBoxMVVMExample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/example/ViewModels/ViewModelBase.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 |
3 | namespace PasswordBoxMVVM.ViewModels
4 | {
5 | public class ViewModelBase : INotifyPropertyChanged
6 | {
7 | public event PropertyChangedEventHandler PropertyChanged;
8 |
9 | public virtual void OnPropertyChanged(string propertyName)
10 | {
11 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/example/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/PasswordBoxMVVM/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/example/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/PasswordBoxMVVM/Components/BindablePasswordBox.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/Views/LoginView.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Windows;
5 | using System.Windows.Controls;
6 | using System.Windows.Data;
7 | using System.Windows.Documents;
8 | using System.Windows.Input;
9 | using System.Windows.Media;
10 | using System.Windows.Media.Imaging;
11 | using System.Windows.Navigation;
12 | using System.Windows.Shapes;
13 |
14 | namespace PasswordBoxMVVM.Views
15 | {
16 | ///
17 | /// Interaction logic for LoginView.xaml
18 | ///
19 | public partial class LoginView : UserControl
20 | {
21 | public LoginView()
22 | {
23 | InitializeComponent();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/example/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using PasswordBoxMVVM.ViewModels;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Configuration;
5 | using System.Data;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using System.Windows;
9 |
10 | namespace PasswordBoxMVVM
11 | {
12 | ///
13 | /// Interaction logic for App.xaml
14 | ///
15 | public partial class App : Application
16 | {
17 | protected override void OnStartup(StartupEventArgs e)
18 | {
19 | MainWindow = new MainWindow()
20 | {
21 | DataContext = new LoginViewModel()
22 | };
23 |
24 | MainWindow.Show();
25 |
26 | base.OnStartup(e);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/example/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Windows;
7 | using System.Windows.Controls;
8 | using System.Windows.Data;
9 | using System.Windows.Documents;
10 | using System.Windows.Input;
11 | using System.Windows.Media;
12 | using System.Windows.Media.Imaging;
13 | using System.Windows.Navigation;
14 | using System.Windows.Shapes;
15 |
16 | namespace PasswordBoxMVVM
17 | {
18 | ///
19 | /// Interaction logic for MainWindow.xaml
20 | ///
21 | public partial class MainWindow : Window
22 | {
23 | public MainWindow()
24 | {
25 | InitializeComponent();
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/PasswordBoxMVVM/PasswordBoxMVVM.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netcoreapp3.1
5 | true
6 | PasswordBoxMVVM
7 | SingletonSean
8 | A password box that allows binding.
9 | password box wpf binding mvvm
10 | https://github.com/SingletonSean/wpf-mvvm-password-box
11 | https://github.com/SingletonSean/wpf-mvvm-password-box
12 | git
13 | true
14 | snupkg
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/example/ViewModels/LoginViewModel.cs:
--------------------------------------------------------------------------------
1 | using PasswordBoxMVVM.Commands;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Windows.Input;
6 |
7 | namespace PasswordBoxMVVM.ViewModels
8 | {
9 | public class LoginViewModel : ViewModelBase
10 | {
11 | private string _username;
12 | public string Username
13 | {
14 | get
15 | {
16 | return _username;
17 | }
18 | set
19 | {
20 | _username = value;
21 | OnPropertyChanged(nameof(Username));
22 | }
23 | }
24 |
25 | private string _password;
26 | public string Password
27 | {
28 | get
29 | {
30 | return _password;
31 | }
32 | set
33 | {
34 | _password = value;
35 | OnPropertyChanged(nameof(Password));
36 | }
37 | }
38 |
39 | public ICommand LoginCommand { get; }
40 |
41 | public LoginViewModel()
42 | {
43 | LoginCommand = new LoginCommand(this);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/.github/workflows/nuget.yml:
--------------------------------------------------------------------------------
1 | name: "Deploy to NuGet"
2 |
3 | on:
4 | push:
5 | tags:
6 | - 'v*'
7 |
8 | env:
9 | PROJECT_PATH: 'PasswordBoxMVVM/PasswordBoxMVVM.csproj'
10 | PACKAGE_OUTPUT_DIRECTORY: ${{ github.workspace }}\output
11 | NUGET_SOURCE_URL: 'https://api.nuget.org/v3/index.json'
12 |
13 | jobs:
14 | deploy:
15 | name: 'Deploy'
16 | runs-on: 'windows-latest'
17 | steps:
18 | - name: 'Checkout'
19 | uses: actions/checkout@v2
20 |
21 | - name: 'Install dotnet'
22 | uses: actions/setup-dotnet@v1
23 | with:
24 | dotnet-version: '3.1.x'
25 |
26 | - name: 'Restore packages'
27 | run: dotnet restore ${{ env.PROJECT_PATH }}
28 |
29 | - name: 'Build project'
30 | run: dotnet build ${{ env.PROJECT_PATH }} --no-restore --configuration Release
31 |
32 | - name: 'Get Version'
33 | id: version
34 | uses: battila7/get-version-action@v2
35 |
36 | - name: 'Pack project'
37 | run: dotnet pack ${{ env.PROJECT_PATH }} --no-restore --no-build --configuration Release --include-symbols -p:PackageVersion=${{ steps.version.outputs.version-without-v }} --output ${{ env.PACKAGE_OUTPUT_DIRECTORY }}
38 |
39 | - name: 'Push package'
40 | run: dotnet nuget push ${{ env.PACKAGE_OUTPUT_DIRECTORY }}\*.nupkg -k ${{ secrets.NUGET_AUTH_TOKEN }} -s ${{ env.NUGET_SOURCE_URL }}
--------------------------------------------------------------------------------
/example/Commands/LoginCommand.cs:
--------------------------------------------------------------------------------
1 | using PasswordBoxMVVM.ViewModels;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Text;
6 | using System.Windows;
7 | using System.Windows.Input;
8 |
9 | namespace PasswordBoxMVVM.Commands
10 | {
11 | public class LoginCommand : ICommand
12 | {
13 | private readonly LoginViewModel _viewModel;
14 |
15 | public LoginCommand(LoginViewModel viewModel)
16 | {
17 | _viewModel = viewModel;
18 |
19 | _viewModel.PropertyChanged += ViewModel_PropertyChanged;
20 | }
21 |
22 | public event EventHandler CanExecuteChanged;
23 |
24 | public bool CanExecute(object parameter)
25 | {
26 | return !string.IsNullOrEmpty(_viewModel.Username) &&
27 | !string.IsNullOrEmpty(_viewModel.Password);
28 | }
29 |
30 | public void Execute(object parameter)
31 | {
32 | MessageBox.Show($"Username: {_viewModel.Username}\nPassword: {_viewModel.Password}", "Info",
33 | MessageBoxButton.OK, MessageBoxImage.Information);
34 | }
35 |
36 | private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
37 | {
38 | CanExecuteChanged?.Invoke(this, new EventArgs());
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/PasswordBoxMVVM.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30413.136
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PasswordBoxMVVMExample", "example\PasswordBoxMVVMExample.csproj", "{36EF3498-9140-43BA-9B9E-B342E77B8DFD}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PasswordBoxMVVM", "PasswordBoxMVVM\PasswordBoxMVVM.csproj", "{832A17EA-C363-4A48-B27E-C011B62DC09A}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Release|Any CPU = Release|Any CPU
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {36EF3498-9140-43BA-9B9E-B342E77B8DFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17 | {36EF3498-9140-43BA-9B9E-B342E77B8DFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
18 | {36EF3498-9140-43BA-9B9E-B342E77B8DFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
19 | {36EF3498-9140-43BA-9B9E-B342E77B8DFD}.Release|Any CPU.Build.0 = Release|Any CPU
20 | {832A17EA-C363-4A48-B27E-C011B62DC09A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {832A17EA-C363-4A48-B27E-C011B62DC09A}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {832A17EA-C363-4A48-B27E-C011B62DC09A}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {832A17EA-C363-4A48-B27E-C011B62DC09A}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {B48F9BFD-E3AE-40DC-9CFB-A3B50DCC7FBF}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/PasswordBoxMVVM/Components/BindablePasswordBox.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 | using System.Windows.Controls;
3 | using System.Windows.Data;
4 |
5 | namespace PasswordBoxMVVM.Components
6 | {
7 | public partial class BindablePasswordBox : UserControl
8 | {
9 | private bool _isPasswordChanging;
10 |
11 | public static readonly DependencyProperty PasswordProperty =
12 | DependencyProperty.Register("Password", typeof(string), typeof(BindablePasswordBox),
13 | new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
14 | PasswordPropertyChanged, null, false, UpdateSourceTrigger.PropertyChanged));
15 |
16 | private static void PasswordPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
17 | {
18 | if(d is BindablePasswordBox passwordBox)
19 | {
20 | passwordBox.UpdatePassword();
21 | }
22 | }
23 |
24 | public string Password
25 | {
26 | get { return (string)GetValue(PasswordProperty); }
27 | set { SetValue(PasswordProperty, value); }
28 | }
29 |
30 | public BindablePasswordBox()
31 | {
32 | InitializeComponent();
33 | }
34 |
35 | private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
36 | {
37 | _isPasswordChanging = true;
38 | Password = passwordBox.Password;
39 | _isPasswordChanging = false;
40 | }
41 |
42 | private void UpdatePassword()
43 | {
44 | if(!_isPasswordChanging)
45 | {
46 | passwordBox.Password = Password;
47 | }
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/example/Views/LoginView.xaml:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
57 |
58 |
59 |
60 |
61 |
65 |
66 |
67 |
--------------------------------------------------------------------------------