form validation with FluentValidation and MudBlazor in dialog - forms

I am using MudBlazor and i want validation form with fluentvalidation (EditForm) in dialog.
BookDialog.razor
<MudDialog>
<DialogContent>
<EditForm Model="#model">
<FluentValidationValidator />
<MudTextField Label="#L["Code"]" #bind-Value="model.Code" For="() => model.Code" />
<MudTextField Label="#L["Title"]" #bind-Value="model.Title" For="() => model.Title" />
</EditForm>
</DialogContent>
<DialogActions>
<MudButton OnClick="Cancel">Cancel</MudButton>
<MudButton Color="MudBlazor.Color.Primary" OnClick="Submit">Ok</MudButton>
</DialogActions>
</MudDialog>
#code{
[Parameter]
public BookInfo model { get; set; }
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
private void Cancel()
{
MudDialog.Cancel();
}
private void Submit()
{
MudDialog.Close(DialogResult.Ok<BookInfo>(model));
}
}
Index.razor
#inject IDialogService dialogService
<MudIconButton Icon="#Icons.Material.Filled.Add" OnClick="CreateBook"></MudIconButton>
#code{
private async Task CreateBook()
{
var parameters = new dialogParameters();
parameters.Add("model", new BookInfo());
var dialog = await dialogService.Show<BookDialog>("Create A Book", parameters).Result;
if (dialog.Data != null)
{
//....
}
}
}
BookValidator.cs
public class BookValidator : AbstractValidator<BookInfo>
{
public BookValidator()
{
CascadeMode = CascadeMode.Stop;
RuleFor(x => x.Code).NotEmpty().WithMessage("*");
RuleFor(x => x.Title).NotEmpty().WithMessage("*");
}
}
Error messages show correctly, but closes the dialog and not stop form submiting.

I fount a solution by validate model directly.
private void Submit()
{
var validator = new BookValidator();
var result = validator.Validate(model);
if (result.IsValid)
{
MudDialog.Close(DialogResult.Ok<BookInfo>(model));
}
}

Related

Subscribe to Close, but close only if item was saved

My scenario:
In an MVVM pattern, the view should be closed when a command is executed on ViewModel, but only if the item was successfully saved.
The View looks like:
public class CentreUpdateWindow : ReactiveWindow<CentreUpdateViewModel>
{
public CentreUpdateWindow()
{
this.InitializeComponent();
this.WhenActivated(d =>
d(ViewModel!.SubmitCommand.Subscribe(CloseIfSuccessfullySaved))
);
}
private void CloseIfSaved(Centre? obj)
{
if (ViewModel!.SuccessfullySaved)
Close(obj);
}
// ...
And the ViewModel:
public class CentreUpdateViewModel : ViewModelBase, IId
{
// ...
public ReactiveCommand<Unit, dtoo.Centre?> SubmitCommand { get; }
private bool _SuccessfullySaved;
public bool SuccessfullySaved
{
get { return _SuccessfullySaved; }
protected set { this.RaiseAndSetIfChanged(ref _SuccessfullySaved, value); }
}
The question:
The code works fine, but I'm not comfortable with the if (ViewModel!.SuccessfullySaved). I guess should be a way to write subscribe expression more accurate.
Is there a more elegant way to Subscribe on WhenActivated more "reactiveuistic" ?
public CentreUpdateWindow()
{
this.InitializeComponent();
this.WhenActivated(d =>
d(
ViewModel
.WhenAnyValue(x => x.SuccessfullySaved)
.CombineLatest(ViewModel!.SubmitCommand,
(saved, obj) => (saved, obj))
.Where(s => s.saved)
.Select(s => s.obj)
.Subscribe(Close)
));
}

UWP MVVMCross bind property to method

How do I change the content of the second button, based on the method from the first button with MVVPCross?
Something like this:
MainPage.xaml:
<Button Content="Translate" Click="{x:Bind PhonewordTranslator.Translate}" />
<Button Content="{x:Bind PhonewordTranslatorViewModel.CallButtonText, Mode=TwoWay}" Click="{x:Bind PhonewordTranslatorViewModel.Call}" />
PhonewordTranslatorViewModel.cs:
public class PhonewordTranslatorViewModel : MvxViewModel
{
...
private string _callButtonText;
public string CallButtonText { get=>_callButtonText; set=>SetProperty(ref _callButtonText, value); }
public void Translate()
{
SetProperty(ref _callButtonText, "test123");
}
}
Try this:
public void Translate()
{
CallButtonText = "NewText";
RaisePropertyChanged(() => CallButtonText);
}
Please modify your translate method as below:
public void Translate()
{
CallButtonText = "test123";
}

Master/Details binding MVVM

I have some problem with correct binding my folder with images to master details and other operation with them.
So, I have model of folder and image
public class AppFolder
{
private long id;
private List<AppImage> appImages;
public AppFolder() { }
public List<AppImage> AppImages { get => appImages; set => appImages = value; }
public long Id { get => id; set => id = value; }
}
public class AppImage
{
private int id;
private string title;
private ImageSource appImageURL;
public AppImage() { }
public AppImage(string title, ImageSource imageSource)
{
Title = title;
AppImageURL = imageSource;
}
public int Id { get => id; set => id = value; }
public string Title { get => title; set => title = value; }
public ImageSource AppImageURL { get => appImageURL; set => appImageURL = value; }
}
And I bind List to Master/Details.
public class UserPhotosViewModel : ViewModelBase
{
private readonly IDataService dataService;
private readonly INavigationService navigationService;
public UserPhotosViewModel(IDataService dataService, INavigationService navigationService)
{
this.dataService = dataService;
this.navigationService = navigationService;
Initialize();
}
private async Task Initialize()
{
var item = new List<AppFolder>();
try
{
item = await dataService.GetDataList();
FolderList = item;
}
catch (Exception ex)
{
}
}
private List<AppFolder> folderList;
public List<AppFolder> FolderList
{
get { return folderList; }
set
{
folderList = value;
RaisePropertyChanged(nameof(FolderList));
}
}
}
Example xaml file
<controls:MasterDetailsView ItemsSource="{Binding FolderList}">
<controls:MasterDetailsView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Id}"></TextBlock>
</DataTemplate>
</controls:MasterDetailsView.ItemTemplate>
<controls:MasterDetailsView.DetailsTemplate>
<DataTemplate>
<controls:AdaptiveGridView ItemsSource="{Binding AppImages}"
OneRowModeEnabled="False"
ItemHeight="205"
DesiredWidth="205"
SelectionMode="Multiple"
Margin="0 6 0 0"
>
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate >
<Grid Background="White" Margin="10">
<Image
Source="{Binding AppImageURL}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
/>
<TextBlock Text="{Binding TextTitle}"></TextBlock>
</Grid>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
</DataTemplate>
</controls:MasterDetailsView.DetailsTemplate>
</controls:MasterDetailsView>
So, it's work correct and I saw my folders with images on page
enter image description here
Look nice and I think it all.
But when I want to add event and SelectedItem to AdaptiveGridView from MVVM model, I saw that it doesn't see them. Visual Studio show me that I could to write them in Model "AppFolder" but it's nonsens....
So, my question: How I can add event (binding command/method) to adaptive grid from UserPhotosViewModel?
Thank you for your time.
UPDATE
enter image description here
2) User double click on image and program send folder with this image and other to page and binding them to FlipView (imitation full screen viewer)
I try to add, but that way also offers to write event and property in model. I use this way for settings in navigation panel (parent control for master/details)
You just need to add command property in your AppFolder class like the following:
public class AppFolder:ViewModelBase
{
private long id;
private List<AppImage> appImages;
public AppFolder() { }
public List<AppImage> AppImages { get => appImages; set => appImages = value; }
public long Id { get => id; set => id = value; }
public RelayCommand<object> relayCommand { get; set; }
}
Then, in your UserPhotosViewModel, you could declare a method for initializing this command.
Since I do not know what the dataService.GetDataList() is. I just change this place in your code and make a simple code sample for you.
private void Initialize()
{
var item = new List<AppFolder>();
try
{
List<AppImage> ls = new List<AppImage>();
ls.Add(new AppImage() { Id = 1, Title = "aaa", AppImageURL = new BitmapImage(new Uri("ms-appx:///Assets/1.jpg")) });
ls.Add(new AppImage() { Id = 2, Title = "bbb", AppImageURL = new BitmapImage(new Uri("ms-appx:///Assets/2.jpg")) });
item.Add(new AppFolder() { Id = 1, AppImages = ls,relayCommand=new RelayCommand<object>(DoubleTapCommand) });
FolderList = item;
}
catch (Exception ex)
{
}
}
private void DoubleTapCommand(object obj)
{
//the obj will be an AppFolder object
}
<controls:MasterDetailsView.DetailsTemplate>
<DataTemplate>
<controls:AdaptiveGridView x:Name="grid" ItemsSource="{Binding AppImages}"
OneRowModeEnabled="False"
ItemHeight="205"
DesiredWidth="205"
SelectionMode="Multiple"
Margin="0 6 0 0">
<Interactivity:Interaction.Behaviors>
<Interactions:EventTriggerBehavior EventName="DoubleTapped">
<Interactions:InvokeCommandAction Command="{Binding relayCommand}" CommandParameter="{Binding}"></Interactions:InvokeCommandAction>
</Interactions:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate >
<Grid Background="White" Margin="10">
<Image
Source="{Binding AppImageURL}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Stretch="Uniform"
/>
<TextBlock Text="{Binding TextTitle}"></TextBlock>
</Grid>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
</controls:AdaptiveGridView>
</DataTemplate>
</controls:MasterDetailsView.DetailsTemplate>
1) User select N images and delete them (example)
About this requirement, I suggested that you'd better add a button to bind command for deleting selected items.

How can I configure the color of the feedback messages in Wicket Sessions?

The Problem
Hello,
I am trying to configure the color of Wickets feedback messages. I am currently maintaining a Wicket GUI (Wicket 7.6.1). It seems that Session.get().warn("Watch out!") prints a green warning box, annotated with the CSS class alert-success. I would like it to change its color to yellow.
What I got so far:
I found that Session.get().getApplication().getResourceSettings() gives me access to some resource settings, including a properties factory. But I don't know how to use it. Also, I have looked for markup files related to my Session but not found any.
Any help would be greatly appreciated!
You can create your custom feedback panel if you want.
CustomFeedBackPanel.html
<wicket:panel>
<div wicket:id="feedbackul">
<wicket:container wicket:id="messages">
<p wicket:id="message"></p>
</wicket:container>
</div>
</wicket:panel>
CustomFeedBackPanel.java
public class CustomFeedbackPanel extends Panel implements IFeedback {
private static final long serialVersionUID = 1L;
private final MessageListView messageListView;
WebMarkupContainer messagesContainer = new WebMarkupContainer("feedbackul") {
private static final long serialVersionUID = 1L;
#Override
protected void onConfigure() {
super.onConfigure();
setVisible(anyMessage());
}
};
public CustomFeedbackPanel(final String id) {
this(id, null);
}
public CustomFeedbackPanel(final String id, IFeedbackMessageFilter filter) {
super(id);
add(messagesContainer);
messageListView = new MessageListView("messages");
messagesContainer.add(messageListView);
if (filter != null) {
setFilter(filter);
}
}
public final boolean anyErrorMessage() {
return anyMessage(FeedbackMessage.ERROR);
}
public final boolean anyMessage() {
return anyMessage(FeedbackMessage.UNDEFINED);
}
public final boolean anyMessage(int level) {
List<FeedbackMessage> msgs = getCurrentMessages();
for (FeedbackMessage msg : msgs) {
if (msg.isLevel(level)) {
return true;
}
}
return false;
}
public final FeedbackMessagesModel getFeedbackMessagesModel() {
return (FeedbackMessagesModel) messageListView.getDefaultModel();
}
public final IFeedbackMessageFilter getFilter() {
return getFeedbackMessagesModel().getFilter();
}
public final CustomFeedbackPanel setFilter(IFeedbackMessageFilter filter) {
getFeedbackMessagesModel().setFilter(filter);
return this;
}
public final Comparator<FeedbackMessage> getSortingComparator() {
return getFeedbackMessagesModel().getSortingComparator();
}
public final CustomFeedbackPanel setSortingComparator(Comparator<FeedbackMessage> sortingComparator) {
getFeedbackMessagesModel().setSortingComparator(sortingComparator);
return this;
}
#Override
public boolean isVersioned() {
return false;
}
public final CustomFeedbackPanel setMaxMessages(int maxMessages) {
messageListView.setViewSize(maxMessages);
return this;
}
protected String getCSSClass(final FeedbackMessage message) {
String css = "feedback";
if (message.getLevel() == FeedbackMessage.ERROR
|| message.getLevel() == FeedbackMessage.FATAL) {
css = "feedback error";
}
if (message.getLevel() == FeedbackMessage.SUCCESS) {
css = "feedback success";
}
if (message.getLevel() == FeedbackMessage.WARNING) {
css = "feedback warn";
}
return css;
}
protected final List<FeedbackMessage> getCurrentMessages() {
final List<FeedbackMessage> messages = messageListView.getModelObject();
return Collections.unmodifiableList(messages);
}
protected FeedbackMessagesModel newFeedbackMessagesModel() {
return new FeedbackMessagesModel(this);
}
protected Component newMessageDisplayComponent(String id, FeedbackMessage message) {
Serializable serializable = message.getMessage();
Label label = new Label(id, (serializable == null) ? "" : serializable.toString());
label.setEscapeModelStrings(CustomFeedbackPanel.this.getEscapeModelStrings());
//label.add(new AttributeModifier("class",getCSSClass(message)));
return label;
}
private final class MessageListView extends ListView<FeedbackMessage> {
private static final long serialVersionUID = 1L;
public MessageListView(final String id) {
super(id);
setDefaultModel(newFeedbackMessagesModel());
}
#Override
protected IModel<FeedbackMessage> getListItemModel(
final IModel<? extends List<FeedbackMessage>> listViewModel, final int index) {
return new AbstractReadOnlyModel<FeedbackMessage>() {
private static final long serialVersionUID = 1L;
#Override
public FeedbackMessage getObject() {
if (index >= listViewModel.getObject().size()) {
return null;
} else {
return listViewModel.getObject().get(index);
}
}
};
}
#Override
protected void populateItem(final ListItem<FeedbackMessage> listItem) {
final FeedbackMessage message = listItem.getModelObject();
message.markRendered();
final Component label = newMessageDisplayComponent("message", message);
final AttributeModifier levelModifier = AttributeModifier.replace("class",
getCSSClass(message));
//label.add(levelModifier);
listItem.add(levelModifier);
listItem.add(label);
messagesContainer.add(levelModifier);
}
}
}
Main thing you should consider getCssClass() method. You can change according to your requirement.I have modified just for your reference.
protected String getCSSClass(final FeedbackMessage message) {
String css = "feedback";
if (message.getLevel() == FeedbackMessage.ERROR
|| message.getLevel() == FeedbackMessage.FATAL) {
css = "alert error";
}
if (message.getLevel() == FeedbackMessage.SUCCESS) {
css = "alert success";
}
if (message.getLevel() == FeedbackMessage.WARNING) {
css = "alert warn";
}
return css;
}
Feedback messages are rendered by FeedbackPanel class. It seems your application uses custom implementation of FeedbackPanel that renders the messages as Bootstrap Alerts.
By default Wicket sets feedbackMessage<LogLevel> (e.g. feedbackMessageWarning) as a CSS class to all messages, so you can style them however you want.
An alternative to not create a custom FeedbackPanel and new HTML/Java files is to use enclosures:
Using Twitter Bootstrap classes:
<wicket:enclosure>
<div class="alert alert-danger alert-dismissible">
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
<h4><i class="icon fa fa-ban"></i> Error on form validation!</h4>
<div wicket:id="errorMessages"></div>
</div>
</wicket:enclosure>
In page constructor:
FeedbackCollector collector = new FeedbackCollector(this);
ExactErrorLevelFilter errorFilter = new ExactErrorLevelFilter(FeedbackMessage.ERROR);
add(new FeedbackPanel("errorMessages", errorFilter) {
#Override public boolean isVisible() {
return !collector.collect(errorFilter).isEmpty();
}
});
Since Wicket 6 feedback messages are attached to components, so you can use a FeedbackCollector and a filter to get and display desired messages. The advantages of enclosures is:
you don't need to create new files;
it works similar to fragments/panels;
it's only rendered if desired messages exists;
Hope it helps.

How to change a radio box from true to false using MVVM

So I have a radio button that I want to change from being unchecked to being checked based on if a button is clicked. So
the XAML code I have is:
<RadioButton GroupName="rdoExchange" Grid.Row="2" Grid.Column="0" x:Name="PauseRadioButton" Command="{Binding PauseCommand}" IsChecked="{Binding Path=check, Mode=TwoWay}" Margin="3"/>
And the View Model Code:
public string check = "True";
public void Reset(object obj)
{
check = "True";
}
private ICommand m_PauseCommand;
public ICommand PauseCommand
{
get
{
return m_PauseCommand;
}
set
{
m_PauseCommand = value;
}
}
private ICommand m_ResetCommand;
public ICommand ResetCommand
{
get
{
return m_ResetCommand;
}
set
{
m_ResetCommand = value;
}
}
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string name = "")
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
I've left out the relaycommand code and several other parts that I feel would be irrelevant to solving the problem.
Would something like this work?
XAML:
<RadioButton GroupName="rdoExchange" IsChecked="{Binding Path=OptionOneChecked, Mode=TwoWay}"/>
<Button Command="{Binding ToggleOptionOne}" Height="20" />
View Model:
public class ViewModel: NotificationObject
{
private bool _optionOneChecked;
public bool OptionOneChecked
{
get { return _optionOneChecked; }
set
{
if (value.Equals(_optionOneChecked)) return;
_optionOneChecked = value;
RaisePropertyChanged("OptionOneChecked");
}
}
public ICommand ToggleOptionOne
{
get { return new DelegateCommand(() => OptionOneChecked = !OptionOneChecked); }
}
}
using the NotificationObject class from the PRISM NuGet package.