Goffo.MVVM
1.0.0
There is a newer version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package Goffo.MVVM --version 1.0.0
NuGet\Install-Package Goffo.MVVM -Version 1.0.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.0.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Goffo.MVVM" Version="1.0.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.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: Goffo.MVVM, 1.0.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.0.0
#tool nuget:?package=Goffo.MVVM&version=1.0.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
MVVM
MVVM Library for startup
Includes
- Abstract View Model with Logging
- Abstract Command
- Abstract Async Command
- Navigation for View Models
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();
}
}
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.
Initial Release