Skip to content

Commit cccf8a0

Browse files
committed
Add initial ObservableValidator sample
1 parent 55bc9db commit cccf8a0

File tree

6 files changed

+176
-2
lines changed

6 files changed

+176
-2
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Threading.Tasks;
6+
7+
namespace MvvmSample.Core.Services;
8+
9+
/// <summary>
10+
/// The default <see langword="interface"/> for a service that shows dialogs
11+
/// </summary>
12+
public interface IDialogService
13+
{
14+
/// <summary>
15+
/// Shows a message dialog with a title and custom content.
16+
/// </summary>
17+
/// <param name="title">The title of the message dialog.</param>
18+
/// <param name="message">The content of the message dialog.</param>
19+
Task ShowMessageDialogAsync(string title, string message);
20+
}

samples/MvvmSample.Core/ViewModels/ObservableValidatorPageViewModel.cs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,75 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
6+
using System.ComponentModel.DataAnnotations;
7+
using System.Linq;
58
using CommunityToolkit.Mvvm.ComponentModel;
9+
using CommunityToolkit.Mvvm.Input;
610
using MvvmSample.Core.Services;
711

812
namespace MvvmSample.Core.ViewModels;
913

1014
public partial class ObservableValidatorPageViewModel : SamplePageViewModel
1115
{
12-
public ObservableValidatorPageViewModel(IFilesService filesService)
16+
public ObservableValidatorPageViewModel(IFilesService filesService, IDialogService dialogService)
1317
: base(filesService)
1418
{
19+
Form = new ObservableForm(dialogService);
1520
}
1621

17-
public ObservableForm Form { get; } = new();
22+
public ObservableForm Form { get; }
1823

1924
public partial class ObservableForm : ObservableValidator
2025
{
26+
private readonly IDialogService DialogService;
2127

28+
public ObservableForm(IDialogService dialogService)
29+
{
30+
DialogService = dialogService;
31+
}
32+
33+
public event EventHandler? FormSubmissionCompleted;
34+
public event EventHandler? FormSubmissionFailed;
35+
36+
[ObservableProperty]
37+
[Required]
38+
[MinLength(2)]
39+
[MaxLength(100)]
40+
private string? firstName;
41+
42+
[ObservableProperty]
43+
[Required]
44+
[MinLength(2)]
45+
[MaxLength(100)]
46+
private string? lastName;
47+
48+
[ObservableProperty]
49+
[Required]
50+
[EmailAddress]
51+
private string? email;
52+
53+
[ICommand]
54+
private void Submit()
55+
{
56+
ValidateAllProperties();
57+
58+
if (HasErrors)
59+
{
60+
FormSubmissionFailed?.Invoke(this, EventArgs.Empty);
61+
}
62+
else
63+
{
64+
FormSubmissionCompleted?.Invoke(this, EventArgs.Empty);
65+
}
66+
}
67+
68+
[ICommand]
69+
private void ShowErrors()
70+
{
71+
string message = string.Join(Environment.NewLine, GetErrors().Select(e => e.ErrorMessage));
72+
73+
_ = DialogService.ShowMessageDialogAsync("Validation errors", message);
74+
}
2275
}
2376
}

samples/MvvmSampleUwp/App.xaml.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e)
4545
Ioc.Default.ConfigureServices(
4646
new ServiceCollection()
4747
//Services
48+
.AddSingleton<IDialogService, DialogService>()
4849
.AddSingleton<IFilesService, FilesService>()
4950
.AddSingleton<ISettingsService, SettingsService>()
5051
.AddSingleton(RestService.For<IRedditService>("https://www.reddit.com/"))

samples/MvvmSampleUwp/MvvmSampleUwp.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128
<Compile Include="Converters\TaskResultConverter.cs" />
129129
<Compile Include="Helpers\TitleBarHelper.cs" />
130130
<Compile Include="Properties\AssemblyInfo.cs" />
131+
<Compile Include="Services\DialogService.cs" />
131132
<Compile Include="Services\FileService.cs" />
132133
<Compile Include="Services\SettingsService.cs" />
133134
<Compile Include="Shell.xaml.cs">
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Threading.Tasks;
7+
using MvvmSample.Core.Services;
8+
using Windows.UI.Xaml.Controls;
9+
10+
#nullable enable
11+
12+
namespace MvvmSampleUwp.Services;
13+
14+
/// <summary>
15+
/// A <see langword="class"/> that implements the <see cref="IDialogService"/> <see langword="interface"/> using UWP APIs.
16+
/// </summary>
17+
public sealed class DialogService : IDialogService
18+
{
19+
/// <inheritdoc/>
20+
public Task ShowMessageDialogAsync(string title, string message)
21+
{
22+
ContentDialog dialog = new();
23+
dialog.Title = title;
24+
dialog.CloseButtonText = "Close";
25+
dialog.DefaultButton = ContentDialogButton.Close;
26+
dialog.Content = message;
27+
28+
return dialog.ShowAsync().AsTask();
29+
}
30+
}

samples/MvvmSampleUwp/Views/ObservableValidatorPage.xaml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,81 @@
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6+
xmlns:interactions="using:Microsoft.Xaml.Interactions.Core"
7+
xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
68
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9+
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
710
NavigationCacheMode="Enabled"
811
mc:Ignorable="d">
912

1013
<ScrollViewer Padding="{StaticResource DocumentationPageContentPadding}" CanContentRenderOutsideBounds="True">
1114
<StackPanel Spacing="16">
15+
<TextBox
16+
Width="560"
17+
HorizontalAlignment="Left"
18+
Header="Enter your first:"
19+
IsSpellCheckEnabled="False"
20+
PlaceholderText="First name"
21+
Text="{x:Bind ViewModel.Form.FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
22+
<TextBox
23+
Width="560"
24+
HorizontalAlignment="Left"
25+
Header="Enter your last name:"
26+
IsSpellCheckEnabled="False"
27+
PlaceholderText="Last name"
28+
Text="{x:Bind ViewModel.Form.LastName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
29+
<TextBox
30+
Width="560"
31+
HorizontalAlignment="Left"
32+
Header="Enter your email address:"
33+
IsSpellCheckEnabled="False"
34+
PlaceholderText="Email"
35+
Text="{x:Bind ViewModel.Form.Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
36+
37+
<Button Command="{x:Bind ViewModel.Form.SubmitCommand}" Content="Submit" />
38+
39+
<!-- Popups -->
40+
<Grid>
41+
<muxc:InfoBar
42+
x:Name="SuccessInfoBar"
43+
Title="Success"
44+
Message="The form was filled in correctly."
45+
Severity="Success">
46+
<interactivity:Interaction.Behaviors>
47+
<interactions:EventTriggerBehavior EventName="FormSubmissionCompleted" SourceObject="{x:Bind ViewModel.Form}">
48+
<interactions:ChangePropertyAction
49+
PropertyName="IsOpen"
50+
TargetObject="{x:Bind SuccessInfoBar}"
51+
Value="True" />
52+
<interactions:ChangePropertyAction
53+
PropertyName="IsOpen"
54+
TargetObject="{x:Bind FailureInfoBar}"
55+
Value="False" />
56+
</interactions:EventTriggerBehavior>
57+
</interactivity:Interaction.Behaviors>
58+
</muxc:InfoBar>
59+
<muxc:InfoBar
60+
x:Name="FailureInfoBar"
61+
Title="Error"
62+
Message="The form was filled in with some errors."
63+
Severity="Error">
64+
<muxc:InfoBar.ActionButton>
65+
<Button Content="Show errors" Command="{x:Bind ViewModel.Form.ShowErrorsCommand}" />
66+
</muxc:InfoBar.ActionButton>
67+
<interactivity:Interaction.Behaviors>
68+
<interactions:EventTriggerBehavior EventName="FormSubmissionFailed" SourceObject="{x:Bind ViewModel.Form}">
69+
<interactions:ChangePropertyAction
70+
PropertyName="IsOpen"
71+
TargetObject="{x:Bind SuccessInfoBar}"
72+
Value="False" />
73+
<interactions:ChangePropertyAction
74+
PropertyName="IsOpen"
75+
TargetObject="{x:Bind FailureInfoBar}"
76+
Value="True" />
77+
</interactions:EventTriggerBehavior>
78+
</interactivity:Interaction.Behaviors>
79+
</muxc:InfoBar>
80+
</Grid>
1281
</StackPanel>
1382
</ScrollViewer>
1483
</Page>

0 commit comments

Comments
 (0)