I need to activate a button when a textbox has a specific type/format of text input (FilterString
) based on which radiobutton is selected without breaking mvvm pattern.
Basically in the CanExecute method of the RelayCommand instance of the button do something like
public bool CanDoStuff(object param)
{
if (rb_1.IsChecked == true) {
if (string.IsNullOrEmpty(FilterString)) {
return false;
} else
return true;
}
else if (rb_2.IsChecked == true) {
DateTime searchDate;
if (DateTime.TryParseExact(FilterString, "dd-MM-yyyy", CultureInfo.InvariantCulture, DateTimeStyles.None, out searchDate)) {
return true;
} else
return false;
}
else if (rb_3.IsChecked == true) {
Decimal k;
if (Decimal.TryParse(FilterString, out k)) {
return true;
} else
return false;
}
else
return true;
}
But I can't access radiobuttons like above in a proper mvvm setup. Is there a different approach for this like using IDataErrorInfo or something and how do I do that?
CodePudding user response:
It's recommended to not interpret button states directly. Rather abstract them to a meaningful state value in context of their purpose.
- You can always bind each
RadioButton
to a dedicated property. - You can use a
IValueConverter
to convert the button's state to a meaningful value e.g. anenum
. - You can, of course, use an
ICommand
to send the state as a meaningful value e.g. anenum
. - Attach a
Click
event handler
Solution 3) is good because it eliminates the more complex Binding
definitions introduced e.g. by 2) which is uses a IValueConverter
. It makes the code more readable.
Because grouped RadioButton
are mutual exclusive, you basically need to create a ICommand
for each RadioButton
group.
You can find a common reusable ICommand
implementation, the RelayComand
, here: Microsoft Docs: Relaying Command Logic.
For example, if you want to use an array of RadioButton
to allow the user to pick a currency, you could first implement an enum
to create constants that represent a currency. Then use a enum
value for each RadioButton
and send it using the ButtonBase.CommandParameter
property:
Currency.cs
public enum Currency
{
Default = 0,
Euro,
BritishPound,
JapaneseYen,
UsDollar
}
MainViewModel.cs
class MainViewModel : INotifyPropertyChagned
{
public Currency SelectedCurrency { get; private set; }
// E.g., binding source for a TextBox
// TODO::Raise INotifyPropertyChanged.PropertyChanged event
public string Value { get; set; }
public ICommand SelectCurrencyCommand { get; private set; }
public ICommand SaveCommand { get; private set; }
public MainViewModel()
{
this.SelectCurrencyCommand = new RelayCommand(ExecuteSelectCurrencyCommand, commandParameter => true);
this.SaveCommand = new RelayCommand(ExecuteSaveCommand, CanExecuteSaveCommand);
}
private void ExecuteSelectCurrencyCommand(object commandParameter)
{
this.SelectedCurrency = (Currency)commandParameter;
}
// Your CanExecute handler, that depends on the state of the radio buttons.
private bool CanExecuteSaveCommand(object commandParameter)
{
decimal decimalValue;
switch (this.SelectedCurrency)
{
case Currency.Euro:
return Decimal.TryParse(this.Value, out decimalValue);
case Currency.BritishPound:
return Decimal.TryParse(this.Value, out decimalValue);
case Currency.JapaneseYen:
break;
case Currency.UsDollar:
break;
case Currency.Default:
break;
default:
return false;
}
}
}
MainWindow.xaml
<Window>
<Window.DataContext>
<MainViewModel />
</Window.DataContext>
<StackPanel>
<RadioButton Command="{Binding SelectCurrencyCommand}"
CommandParameter="{x:Static Currency.Euro}" />
<RadioButton Command="{Binding SelectCurrencyCommand}"
CommandParameter="{x:Static Currency.BritishPound}" />
<RadioButton Command="{Binding SelectCurrencyCommand}"
CommandParameter="{x:Static Currency.JapaneseYen}" />
<TextBox Text="{Binding Value}" />
<Button Content="Save"
Command="{Binding SaveCommand}" />
</StackPanel>
</Window>