I am following the MVVM design pattern for my .NET MAUI app, and have a DecimalDigitsBehavior behavior that is applied to my Entries:
<Label Text="UNITS" StyleClass="InputHeader" />
<Frame StyleClass="InputFrame">
<Entry Placeholder="0.0" Keyboard="Numeric" Text="{Binding My_Unit}">
<Entry.Behaviors>
<behaviors:DecimalDigitsBehavior MaxDecimalDigits="{Binding MaxUnitDecimalDigits}" />
</Entry.Behaviors>
</Entry>
</Frame>
<Label Text="DISCOUNT %" StyleClass="InputHeader" />
<Frame StyleClass="InputFrame">
<Entry Placeholder="0.00" Keyboard="Numeric" Text="{Binding My_Discount}">
<Entry.Behaviors>
<behaviors:DecimalDigitsBehavior MaxDecimalDigits="2" />
</Entry.Behaviors>
</Entry>
</Frame>
For clarity, I've included my second Entry using a static prop value "2" for MaxDecimalDigits, which works fine. But it does not work for my case of the first Entry, when I am using a Binding to determine that value.
This binding source is from an ObservableProperty, and is set on my page load. The below is from my corresponding ViewModel associated to the .xaml page:
[ObservableProperty]
private int maxUnitDecimalDigits;
...
public void ApplyQueryAttributes(IDictionary<string, object> query)
{
....
MaxUnitDecimalDigits = myService.UnitSetting == "0.1" ? 1 : 0; // HERE, it should cause it to trigger, but it doesn't!
}
Below is my custom decimal digits behavior for reference (just a typical behavior class using regex to validate):
using System.Text.RegularExpressions;
namespace MCoreMatter.Behaviors
{
public class DecimalDigitsBehavior : Behavior<Entry>
{
// Create a BindableProperty for MaxDecimalDigits
public static readonly BindableProperty MaxDecimalDigitsProperty =
BindableProperty.Create(nameof(MaxDecimalDigits), typeof(int), typeof(DecimalDigitsBehavior), 2);
public int MaxDecimalDigits
{
get => (int)GetValue(MaxDecimalDigitsProperty);
set => SetValue(MaxDecimalDigitsProperty, value);
}
protected override void OnAttachedTo(Entry entry)
{
entry.TextChanged += OnEntryTextChanged;
entry.Unfocused += OnEntryUnfocused;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(Entry entry)
{
entry.TextChanged -= OnEntryTextChanged;
entry.Unfocused -= OnEntryUnfocused;
base.OnDetachingFrom(entry);
}
private void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
if (sender is Entry entry)
{
string pattern = $@"^-?\d*(\.\d{{0,{MaxDecimalDigits}}})?$";
var isValid = Regex.IsMatch(args.NewTextValue, pattern);
if (!isValid)
{
entry.Text = args.OldTextValue;
entry.CursorPosition = entry.Text.Length;
}
}
}
private void OnEntryUnfocused(object sender, EventArgs args)
{
if (sender is Entry entry)
{
string text = entry.Text.TrimEnd('.');
if (double.TryParse(text, out double value))
{
entry.Text = string.Format("{0:0." + new string('0', MaxDecimalDigits) + "}", value);
}
else
{
entry.Text = string.Format("{0:0." + new string('0', MaxDecimalDigits) + "}", 0);
}
}
}
}
}
I have added debugging statements to verify that the behaviors are being attached to the entries upon page load, but when my ObservableProperty MaxUnitDecimalDigits is updated, no changes to the behavior took effect (the field remains using 2 as per the default MaxUnitDecimalDigits prop value).
Appreciate the help!
You could have multiple
Entryinputs with differingMaxDecimalDigitsapplied. When yourUnitSettingchanges, it will updateIsVisibleto always ensure that the rightEntryis shown. This works even better if you made aTwoWaybinding to a string in yourViewModelso that a change in oneEntrywill be reflected in the others.