Goffo.MVVM
1.1.0
dotnet add package Goffo.MVVM --version 1.1.0
NuGet\Install-Package Goffo.MVVM -Version 1.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Goffo.MVVM" Version="1.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Goffo.MVVM" Version="1.1.0" />
<PackageReference Include="Goffo.MVVM" />
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Goffo.MVVM --version 1.1.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Goffo.MVVM, 1.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#addin nuget:?package=Goffo.MVVM&version=1.1.0
#tool nuget:?package=Goffo.MVVM&version=1.1.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
READ ME
MVVM
MVVM Library for startup
Version Updates
<u>1.1.0</u>
- Added methods to AbstractViewModel for StartLoading and StopLoading and added property LoadingIsComplete
Includes
- Abstract View Model with Logging
- Abstract Command
- Abstract Async Command
- Navigation for View Models
Contents
- Dependency Injection Examples
- How to use Abstract View Model
- How to use Abstract Command
- How to use Abstract Async Command
- How to use Navigation
- View Models with Interfaces
Dependency Injection
- Add using Goffo.MVVM.Extensions
- Use extension method RegisterGoffoMVVM
Example: WPF
using Goffo.MVVM.Library.ViewModels;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Windows;
namespace Goffo.MVVM.WPF;
public partial class App : Application
{
private readonly IHost _host;
public App()
{
_host = Host.CreateDefaultBuilder()
.ConfigureLogging((context, logger) =>
{
logger.ClearProviders();
logger.AddDebug();
logger.AddConsole();
})
.ConfigureServices((context, services) =>
{
services.RegisterGoffoMVVM();
services.RegisterMVVMLibrary();
services.AddSingleton<MainWindow>(provider =>
{
MainWindow window = new()
{
DataContext = provider.CreateScope().ServiceProvider.GetRequiredService<MainViewModel>()
};
return window;
});
})
.Build();
}
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
_host.Services.GetRequiredService<MainWindow>().Show();
await _host.StartAsync();
}
protected override async void OnExit(ExitEventArgs e)
{
base.OnExit(e);
await _host.StopAsync();
}
}
Example: Blazor
- Server
using Goffo.MVVM.Blazor.Components;
using Goffo.MVVM.Extensions;
using Goffo.MVVM.Library.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
builder.Services.RegisterGoffoMVVM();
....
- Client
using Goffo.MVVM.Extensions;
using Goffo.MVVM.Library.Extensions;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.Services.RegisterGoffoMVVM();
await builder.Build().RunAsync();
How to use Abstract View Model
using Goffo.MVVM.Base.ViewModels;
using Goffo.MVVM.Navigation;
using Microsoft.Extensions.Logging;
namespace Goffo.MVVM.Library.Examples;
public class ExampleViewModel : AbstractViewModel<ExampleViewModel>
{
public ExampleViewModel(ILogger<ExampleViewModel> logger, NavigationCommand navigationCommand) : base(logger, navigationCommand)
{
}
public void DoSomething()
{
// Do something
}
public async Task DoSomethingAsync()
{
// Do something async
await Task.Delay(1000);
}
}
How to use Abstract Command
using Goffo.MVVM.Base.Commands;
namespace Goffo.MVVM.Library.Examples;
public class ExampleCommand : AbstractCommand<ExampleViewModel>
{
public ExampleCommand(ExampleViewModel viewModel) : base(viewModel)
{
}
public override void Execute(object? parameter = null)
{
// Command Logic goes here
base.ViewModel.DoSomething();
}
}
How to use Abstract Async Command
using Goffo.MVVM.Base.Commands;
namespace Goffo.MVVM.Library.Examples;
public class ExampleAsyncCommand : AbstractAsyncCommand<ExampleViewModel>
{
public ExampleAsyncCommand(ExampleViewModel viewModel) : base(viewModel)
{
}
public override async Task ExecuteAsync(object? parameter = null)
{
try
{
// Command Logic goes here
await base.ViewModel.DoSomethingAsync();
OnCompleted();
}
catch (Exception ex)
{
OnException(ex);
}
}
protected override void OnCompleted()
{
// Do something after the command has completed
base.OnCompleted();
}
protected override void OnException(Exception exception)
{
// Do something when an exception occurs
base.OnException(exception);
}
}
How to use Navigation
Create a ViewModel to be the Navigator
- Inherit from INavigator
- Inject the NavigationCommand if not using Abstract View Model
- Subscribe to the Navigate EventHandler
- Inject NavigationViewModelFactory to use in OnNavigate Method to navigate to different view models
using Goffo.MVVM.Base.ViewModels;
using Goffo.MVVM.Navigation;
using Microsoft.Extensions.Logging;
namespace Goffo.MVVM.Library.ViewModels;
public class MainViewModel : AbstractViewModel<MainViewModel>, INavigator
{
private readonly NavigationViewModelFactory _navigationViewModelFactory;
public MainViewModel(ILogger<MainViewModel> logger, NavigationCommand navigationCommand, NavigationViewModelFactory navigationViewModelFactory) : base(logger, navigationCommand)
{
_navigationViewModelFactory = navigationViewModelFactory;
base.NavigationCommand.Navigate += NavigationCommand_Navigate;
base.NavigateToViewModel = _navigationViewModelFactory.GetNavigationViewModel<HomeViewModel>();
}
public override void Dispose()
{
base.NavigationCommand.Navigate -= NavigationCommand_Navigate;
base.Dispose();
}
private void NavigationCommand_Navigate(object? sender, NavigationEventArgs e)
{
OnNavigate(e.NavigateToView);
}
public void OnNavigate(string? navigateToView)
{
// Navigation Logic goes here
switch (navigateToView)
{
case Views.Home:
NavigateToViewModel = _navigationViewModelFactory.GetNavigationViewModel<HomeViewModel>();
break;
case Views.About:
NavigateToViewModel = _navigationViewModelFactory.GetNavigationViewModel<AboutViewModel>();
break;
case Views.Contact:
NavigateToViewModel = _navigationViewModelFactory.GetNavigationViewModel<ContactViewModel>();
break;
default:
break;
}
base.OnPropertyChanged(nameof(NavigateToViewModel));
}
}
Give View Models Ability to Navigate
- Inherit from the INavigationViewModel
- Set the NavigateToView name
using Goffo.MVVM.Base.ViewModels;
using Goffo.MVVM.Library.Commands;
using Goffo.MVVM.Navigation;
using Microsoft.Extensions.Logging;
namespace Goffo.MVVM.Library.ViewModels
{
public class AboutViewModel : AbstractViewModel<AboutViewModel>, INavigationViewModel
{
public AboutViewModel(ILogger<AboutViewModel> logger, NavigationCommand navigationCommand) : base(logger, navigationCommand)
{
NavigateHomeCommand = new AboutCommandNavigateHome(this);
}
public AboutCommandNavigateHome NavigateHomeCommand { get; init; }
// This is the View Name that will be used to navigate to this view
public string NavigateToView => Views.About;
public void NavigateHome()
{
NavigationCommand.Execute(Views.Home);
}
}
}
Example Command to use for Navigation
using Goffo.MVVM.Base.Commands;
using Goffo.MVVM.Library.ViewModels;
namespace Goffo.MVVM.Library.Commands;
public class AboutCommandNavigateHome : AbstractCommand<AboutViewModel>
{
public AboutCommandNavigateHome(AboutViewModel viewModel) : base(viewModel)
{
}
public override void Execute(object? parameter = null)
{
base.ViewModel.NavigateHome();
}
}
Navigation Example: WPF
MainWindow XAML
<Window x:Class="Goffo.MVVM.WPF.MainWindow"
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:local="clr-namespace:Goffo.MVVM.WPF"
xmlns:views="clr-namespace:Goffo.MVVM.WPF.Views"
xmlns:library="clr-namespace:Goffo.MVVM.Library;assembly=Goffo.MVVM.Library"
xmlns:viewmodels="clr-namespace:Goffo.MVVM.Library.ViewModels;assembly=Goffo.MVVM.Library"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<Style x:Key="NoCircleRadioButton" TargetType="RadioButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="RadioButton">
<Border Background="Transparent">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Row="1" Grid.Column="1" Background="Black" HorizontalAlignment="Stretch">
<StackPanel Background="Black" Orientation="Horizontal" Margin="10" HorizontalAlignment="Stretch">
<TextBlock FontSize="36" FontWeight="Bold" Foreground="Red" Margin="0 0 20 0">MY APP</TextBlock>
<RadioButton Content="Home" GroupName="navGroup" Style="{StaticResource NoCircleRadioButton}" Command="{Binding NavigationCommand}" CommandParameter="{x:Static library:Views.Home}" Cursor="Hand" Margin="10 7 0 0" Foreground="Red" FontSize="24" FontWeight="SemiBold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
</StackPanel>
</Border>
<Border Grid.Row="1" Grid.Column="2" Background="Black" HorizontalAlignment="Right">
<StackPanel Background="Black" Orientation="Horizontal" Margin="10" HorizontalAlignment="Stretch">
<RadioButton Content="About" GroupName="navGroup" Style="{StaticResource NoCircleRadioButton}" Command="{Binding NavigationCommand}" CommandParameter="{x:Static library:Views.About}" Cursor="Hand" Margin="10 7 10 0" Foreground="Red" FontSize="24" FontWeight="SemiBold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
<RadioButton Content="Contact" GroupName="navGroup" Style="{StaticResource NoCircleRadioButton}" Command="{Binding NavigationCommand}" CommandParameter="{x:Static library:Views.Contact}" Cursor="Hand" Margin="10 7 10 0" Foreground="Red" HorizontalAlignment="Left" FontSize="24" FontWeight="SemiBold" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"></RadioButton>
</StackPanel>
</Border>
<ContentControl Grid.Row="2" Grid.RowSpan="2" Grid.Column="0" Grid.ColumnSpan="3" Content="{Binding NavigateToViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type viewmodels:HomeViewModel}">
<views:Home></views:Home>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:AboutViewModel}">
<views:About></views:About>
</DataTemplate>
<DataTemplate DataType="{x:Type viewmodels:ContactViewModel}">
<views:Contact></views:Contact>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Grid>
</Window>
Page Navigation
- Bind to your Command
<UserControl x:Class="Goffo.MVVM.WPF.Views.About"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Goffo.MVVM.WPF.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Margin="20" HorizontalAlignment="Center" VerticalAlignment="Top" FontSize="36" FontWeight="Bold" Foreground="LightGreen">THIS IS THE ABOUT PAGE</TextBlock>
<Button Width="200" Height="50" FontWeight="Bold" FontSize="16" Padding="5" Command="{Binding NavigateHomeCommand}">Go To Home Page</Button>
</Grid>
</UserControl>
Navigation Example: Blazor
NavMenu
- Need to make NavMenu (or your own menu) Interactive
- Inject your Navigator View Model
- Subscribe to the OnPropertyChanged EventHandler
- Use NavigationManager to navigate when Property changing is the NavigateToViewModel
@using Goffo.MVVM.Library
@using Goffo.MVVM.Navigation
@rendermode InteractiveAuto
@implements IDisposable
@inject ILogger<NavMenu> _logger
@inject MainViewModel _viewModel
@inject NavigationManager _navigationManager
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">Goffo.MVVM.Blazor</a>
</div>
</div>
<input type="checkbox" title="Navigation menu" class="navbar-toggler" />
<div class="nav-scrollable" onclick="document.querySelector('.navbar-toggler').click()">
<nav class="nav flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
</NavLink>
</div>
</nav>
</div>
@code
{
protected override void OnInitialized()
{
base.OnInitialized();
_viewModel.PropertyChanged += ViewModel_PropertyChanged!;
}
public void Dispose()
{
_viewModel.PropertyChanged -= ViewModel_PropertyChanged!;
}
private void ViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs args)
{
if (args.PropertyName == nameof(_viewModel.NavigateToViewModel))
{
if (_viewModel.NavigateToViewModel is not null)
{
if (_viewModel.NavigateToViewModel.NavigateToView == Views.Home)
{
_navigationManager.NavigateTo("");
}
else
{
_navigationManager.NavigateTo(_viewModel.NavigateToViewModel.NavigateToView);
}
}
else
{
_logger.LogWarning("Navigate To View Model was NULL");
}
}
}
}
Page Navigation
- Create a method that calls your command that will navigate
@page "/about"
@rendermode InteractiveAuto
@inject AboutViewModel _viewModel
<PageTitle>About</PageTitle>
<h1>About</h1>
<a style="color: blue; text-decoration: underline; cursor: pointer;" @onclick="OnNavigateHome">Click To Go Home</a>
@code
{
private void OnNavigateHome()
{
_viewModel.NavigateHomeCommand.Execute();
}
}
View Models with Interfaces
- Implement the IViewModel interface on your View Model interfaces
namespace Goffo.MVVM.Base.ViewModels;
public interface IViewModel : INotifyPropertyChanged, IDisposable, IAsyncDisposable
{
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
net9.0
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Made all Validation Messages on AbstractBaseViewModel to be full properties and virtual