Merge branch 'v2_communitytoolkit' of https://github.com/johnmbaughman/Terminal.Gui into v2_communitytoolkit

# Conflicts:
#	CommunityToolkitExample/LoginView.cs
#	CommunityToolkitExample/LoginViewModel.cs
#	CommunityToolkitExample/Message.cs
#	CommunityToolkitExample/Program.cs
#	CommunityToolkitExample/README.md
This commit is contained in:
John Baughman
2024-06-13 16:52:37 -05:00
2 changed files with 7 additions and 33 deletions

View File

@@ -11,7 +11,7 @@ internal partial class LoginViewModel : ObservableObject
private const string INVALID_LOGIN_MESSAGE = "Please enter a valid user name and password.";
private const string LOGGING_IN_PROGRESS_MESSAGE = "Logging in...";
private const string VALID_LOGIN_MESSAGE = "The input is valid!";
[ObservableProperty]
private bool _canLogin;
@@ -27,7 +27,7 @@ internal partial class LoginViewModel : ObservableObject
[ObservableProperty]
private string _usernameLengthMessage;
[ObservableProperty]
private ColorScheme? _validationColorScheme;

View File

@@ -2,21 +2,15 @@
This small demo gives an example of using the `CommunityToolkit.MVVM` framework's `ObservableObject`, `ObservableProperty`, and `IRecipient<T>` in conjunction with `Microsoft.Extensions.DependencyInjection`.
### Startup
Right away we use IoC to load our views and view models.
``` csharp
// As a public property for access further in the application if needed.
public static IServiceProvider Services { get; private set; }
. . .
...
// In Main
Services = ConfigureServices ();
. . .
...
private static IServiceProvider ConfigureServices ()
{
var services = new ServiceCollection ();
@@ -41,13 +35,9 @@ internal partial class LoginView : IRecipient<Message<LoginAction>>
{
// Initialize our Receive method
WeakReferenceMessenger.Default.Register (this);
...
ViewModel = viewModel;
...
passwordInput.TextChanged += (_, _) =>
{
ViewModel.Password = passwordInput.Text;
@@ -58,40 +48,30 @@ internal partial class LoginView : IRecipient<Message<LoginAction>>
if (!ViewModel.CanLogin) { return; }
ViewModel.LoginCommand.Execute (null);
};
...
// Let the view model know the view is intialized.
Initialized += (_, _) => { ViewModel.Initialized (); };
}
...
}
```
Momentarily slipping over to the view model, all bindable properties use some form of `ObservableProperty` with the class deriving from `ObservableObject`. Commands are of the `RelayCommand` type.
Momentarily slipping over to the view model, all bindable properties use some form of `ObservableProperty` with the class deriving from `ObservableObject`. Commands are of the `RelayCommand` type. The use of `ObservableProperty` generates the code for handling `INotifyPropertyChanged` and `INotifyPropertyChanging`.
``` csharp
internal partial class LoginViewModel : ObservableObject
{
...
[ObservableProperty]
private bool _canLogin;
private string _password;
...
public LoginViewModel ()
{
...
Password = string.Empty;
...
...
LoginCommand = new (Execute);
Clear ();
@@ -100,9 +80,7 @@ internal partial class LoginViewModel : ObservableObject
async void Execute () { await Login (); }
}
...
public RelayCommand LoginCommand { get; }
public string Password
@@ -121,7 +99,6 @@ The use of `WeakReferenceMessenger` provides one method of signaling the view fr
``` csharp
...
private async Task Login ()
{
SendMessage (LoginAction.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
@@ -149,7 +126,6 @@ private void ValidateLogin ()
CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password);
SendMessage (LoginAction.Validation);
}
...
```
@@ -176,5 +152,3 @@ public void Receive (Message<LoginAction> message)
Application.Refresh ();
}
```
There are other ways of handling cross-thread communication, this gives just one example.