UWP MVVMCross bind property to method - mvvm

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";
}

Related

How to implement Activity/Wait Indicator in dotnet Maui?

I needed to implement a wait indicator for a page in my Maui app.
Searching gave me this, but no step by step instructions.
So how do I do this?
Overview:
The control to display the animation is called ActivityIndicator.
ActivityIndicator is a visual element, should be part of your page.
So, add an ActivityIndicator to your xaml.
The state of the indicator is part of logic - should live in your view model.
So, add a bindable property to your view model, and bind ActivityIndicator.IsRunning to this property.
Sample (I haven't tested, just for illustration)
Page (xaml):
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:customcontrols="clr-namespace:Waiter.Maui.CustomControls"
x:Class="..." >
<ContentPage.Content>
<ActivityIndicator IsRunning="{Binding IsBusy}" />
<Button Text="Go" Command="{Binding GoCommand}" />
</ContentPage.Content>
</ContentPage>
ViewModel:
namespace MyNamespace
{
public class MyViewModel : BaseViewModel
{
public MyViewModel()
{
GoCommand = new Command(execute: OnGo, canExecute: true);
}
public Command GoCommand { get; }
private void OnGo()
{
MainThread.InvokeOnMainThreadAsync(async () =>
{
IsBusy = true;
Thread.Sleep(5000);
IsBusy = false;
return result;
});
}
}
}
BaseViewModel class (so that it can be re-used, from existing community content):
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Waiter.Maui.Pages
{
public class BaseViewModel : INotifyPropertyChanged
{
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
I want to point out few things.
First of all, this "IsBusy" that I see getting recommended all around, is working strategy. I can only recommend using CommunityToolkit.MVVM, and letting it do your job, and handle all notification code instead of you.
However, using such boolean variable, is no different than using Lock, Mutex, Semaphore, etc. A programmer has to be very careful how and when it is changed, otherwise all kinds of bugs may occur.
In reality, most problems can be solved with commanding itself.
Specifically CanExecute property is more than enough.
I recommend this:
https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-binding/commanding?view=net-maui-7.0
Before becoming slave to manual changing bool variables.

Custom control - event handler to main app when inside value changed

I want to be able to add an event from my custom control to the outside world
as I change a value in my custom control, I use TwoWay, but I also want an event to be generated in my main app
I just cannot find anything relevant to this
the main app xaml contains this line :
<custom:MyComp x:Name="myComp" ValueChanged="SomeFunction" Value="{ Binding Path=someIntVariable, Mode=TwoWay}"></custom:MyComp>
how do I implement a ValueChanged event in the custom control ?
my control xaml:
<UserControl ...>
<StackPanel Orientation="Horizontal" >
...
<TextBox x:Name="MyCompTextBox" Width="50" Height="20" TextChanged="MyCompTextBox_TextChanged"/>
...
</StackPanel>
</UserControl>
the code
public partial class MyComp: UserControl
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(MyComp), new FrameworkPropertyMetadata(0, OnValuePropertyChangedCallback));
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
private static void OnValuePropertyChangedCallback(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
MyComp mMyComp= source as MyComp;
int newValue=(int)e.NewValue;
myComp.MyCompTextBox.Text = newValue.ToString();
}
public MyComp()
{
InitializeComponent();
}
private void MyCompTextBox_TextChanged(object sender, EventArgs e)
{
int _bpm = int.ParseMyCompTextBox.Text);
Value = _bpm;
MyCompTextBox.Text = Value.ToString();
// here I want to trigger an even to the main app !!!
}
}
thanks for your help

form validation with FluentValidation and MudBlazor in dialog

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));
}
}

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.

RaiseCanExecuteChanged more convenience

I'd like to RaiseCanExecuteChanged when CanExecute condition got changed.
E.g.:
public class ViewModel
{
public viewModel()
{
Command = new RelayCommand(action,condition);
}
private bool condition()
{
return this.Condition1&&this.Condition2&&this.Condition3;
}
public bool Condition1
{
get{...}
set{.... **command.RaiseCanExecuteChanged();}**
}
public bool Condition2
{
get{...}
set{.... command.**RaiseCanExecuteChanged();}**
}
public bool Condition3
{
get{...}
set{.... **command.RaiseCanExecuteChanged();}**
}
}
That works fine.
But I don't like to write so many RaiseCanExecuteChanged, I want to set these changes automatically.
E.g
In RelayCommand, create a new method named RaiseChanged
public void RaiseChanged(XXXXXX XXX, params string[] propertyNames)
{
// for each property in propertyNames,
// RaiseCanExecuteChanged();
}
I put ViewModel vm as the parameters, and use vm.PropertyChanged+=(s,e)=>{}
But I don't think it's a good way to do this.
Does anyone have other ideas?
I develop my solution where I can do like that:
C# View Model:
public bool CanExecuteMethod(object sender)
{
}
public void ButtonExecuteMethod(object sender)
{
}
public event Action EventNotifyCanExecuteChanged;
private Action _DelegateNotifyCanExecuteChanged;
public Action DelegateNotifyCanExecuteChanged
{
get { return _DelegateNotifyCanExecuteChanged; }
set { _DelegateNotifyCanExecuteChanged = value; }
}
public void CanExecuteFlag
{
if (EventNotifyCanExecuteChanged != null) { EventNotifyCanExecuteChanged(); }
if (_DelegateNotifyCanExecuteChanged != null) { _DelegateNotifyCanExecuteChanged();}
}
XAML:
< Button Content="Button Cmd-ExCeCh" HorizontalAlignment="Left" Margin="27,231,0,0"
VerticalAlignment="Top" Width="120"
Command="{mark:BindCommandResource MainWindowViewModel,
ExecuteMethodName=ButtonExecuteMethod,
CanExecuteMethodName=CanExecuteMethod,
EventToInvokeCanExecuteChanged=EventNotifyCanExecuteChanged,
PropertyActionCanExecuteChanged=DelegateNotifyCanExecuteChanged}" />
I put/share this solution in my open source project MVVM-WPF XAML Mark-up Binding Extensions - http://wpfmvvmbindingext.codeplex.com