Udostępnij za pośrednictwem


Komendanta

Browse sample. Przeglądanie przykładu

W aplikacji interfejsu użytkownika aplikacji wieloplatformowej platformy .NET (.NET MAUI), która używa wzorca Model-View-ViewModel (MVVM), powiązania danych są definiowane między właściwościami w modelu widoków, która jest zazwyczaj klasą pochodzącą z INotifyPropertyChangedklasy i właściwości w widoku, która jest zazwyczaj plikiem XAML. Czasami aplikacja musi wykraczać poza te powiązania właściwości, wymagając od użytkownika zainicjowania poleceń, które mają wpływ na coś w modelu widoków. Te polecenia są zwykle sygnalizowane przez kliknięcia przycisków lub naciśnięcia palcem i tradycyjnie są przetwarzane w pliku za pomocą kodu w programie obsługi dla Clicked zdarzenia Button lub Tapped zdarzenia TapGestureRecognizer.

Interfejs wiersza polecenia zapewnia alternatywne podejście do implementowania poleceń, które są znacznie lepiej dostosowane do architektury MVVM. Model widoku może zawierać polecenia, które są metodami wykonywanymi w reakcji na określone działanie w widoku, takim jak Button kliknięcie. Powiązania danych są definiowane między tymi poleceniami a elementem Button.

Aby zezwolić na powiązanie danych między modelem a Button modelem widoków, Button definiuje dwie właściwości:

Aby użyć interfejsu polecenia, należy zdefiniować powiązanie danych, które jest przeznaczone Command dla właściwości, w której źródło jest właściwością Button w modelu widoków typu ICommand. Model viewmodel zawiera kod skojarzony z tą ICommand właściwością, która jest wykonywana po kliknięciu przycisku. Właściwość można ustawić CommandParameter na dowolne dane, aby odróżnić wiele przycisków, jeśli wszystkie są powiązane z tą samą ICommand właściwością w modelu widoków.

Wiele innych widoków definiuje Command również właściwości i CommandParameter . Wszystkie te polecenia można obsłużyć w modelu widoków przy użyciu podejścia, które nie zależy od obiektu interfejsu użytkownika w widoku.

Polecenia

Interfejs ICommand jest zdefiniowany w przestrzeni nazw System.Windows.Input i składa się z dwóch metod i jednego zdarzenia:

public interface ICommand
{
    public void Execute (Object parameter);
    public bool CanExecute (Object parameter);
    public event EventHandler CanExecuteChanged;
}

Aby użyć interfejsu poleceń, model viewmodel powinien zawierać właściwości typu ICommand:

public ICommand MyCommand { private set; get; }

Model widoku musi również odwoływać się do klasy, która implementuje ICommand interfejs. W widoku Command właściwość obiektu Button jest powiązana z tym właściwością:

<Button Text="Execute command"
        Command="{Binding MyCommand}" />

Gdy użytkownik naciśnie metodę Button, Button wywołuje metodę Execute w ICommand obiekcie powiązanym z jego Command właściwością.

Gdy powiązanie jest najpierw zdefiniowane we Command właściwości Button, a powiązanie danych zmienia się w jakiś sposób, Button metoda CanExecute wywołuje metodę ICommand w obiekcie . Jeśli CanExecute funkcja zwróci wartość false, funkcja zostanie wyłączona Button . Oznacza to, że określone polecenie jest obecnie niedostępne lub nieprawidłowe.

Element Button dołącza również program obsługi w CanExecuteChanged przypadku zdarzenia ICommand. Zdarzenie jest wywoływane z poziomu modelu widoków. Po wywołaniu tego zdarzenia wywołania ButtonCanExecute ponownie. Funkcja Button włącza się w przypadku CanExecute zwracania true i wyłącza się, jeśli CanExecute zwraca wartość false.

Ostrzeżenie

Nie używaj IsEnabled właściwości , Button jeśli używasz interfejsu poleceń.

Gdy model viewmodel definiuje właściwość typu ICommand, model widoku musi również zawierać lub odwoływać się do klasy, która implementuje ICommand interfejs. Ta klasa musi zawierać lub odwoływać się do Execute metod i CanExecute oraz uruchamiać CanExecuteChanged zdarzenie za każdym razem, gdy CanExecute metoda może zwrócić inną wartość. Do zaimplementowania interfejsu można użyć klasy lub Command<T> dołączonej Command do programu ICommand .NET MAUI. Te klasy umożliwiają określenie treści Execute metod i CanExecute w konstruktorach klas.

Napiwek

Użyj Command<T> właściwości , aby CommandParameter odróżnić wiele widoków powiązanych z tą samą ICommand właściwością i Command klasę, jeśli nie jest to wymagane.

Podstawowe polecenia

W poniższych przykładach przedstawiono podstawowe polecenia zaimplementowane w modelu viewmodel.

Klasa PersonViewModel definiuje trzy właściwości o nazwie Name, Agei Skills definiujące osobę:

public class PersonViewModel : INotifyPropertyChanged
{
    string name;
    double age;
    string skills;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
        set { SetProperty(ref name, value); }
        get { return name; }
    }

    public double Age
    {
        set { SetProperty(ref age, value); }
        get { return age; }
    }

    public string Skills
    {
        set { SetProperty(ref skills, value); }
        get { return skills; }
    }

    public override string ToString()
    {
        return Name + ", age " + Age;
    }

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Klasa przedstawiona PersonCollectionViewModel poniżej tworzy nowe obiekty typu PersonViewModel i umożliwia użytkownikowi wypełnianie danych. W tym celu klasa definiuje IsEditing, typu i PersonEdit, typu boolPersonViewModel, właściwości. Ponadto klasa definiuje trzy właściwości typu ICommand i właściwość o nazwie Persons typu IList<PersonViewModel>:

public class PersonCollectionViewModel : INotifyPropertyChanged
{
    PersonViewModel personEdit;
    bool isEditing;

    public event PropertyChangedEventHandler PropertyChanged;
    ···

    public bool IsEditing
    {
        private set { SetProperty(ref isEditing, value); }
        get { return isEditing; }
    }

    public PersonViewModel PersonEdit
    {
        set { SetProperty(ref personEdit, value); }
        get { return personEdit; }
    }

    public ICommand NewCommand { private set; get; }
    public ICommand SubmitCommand { private set; get; }
    public ICommand CancelCommand { private set; get; }

    public IList<PersonViewModel> Persons { get; } = new ObservableCollection<PersonViewModel>();

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;

        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

W tym przykładzie zmiany trzech ICommand właściwości i Persons właściwość nie powodują PropertyChanged zgłoszenia zdarzeń. Te właściwości są ustawiane podczas pierwszego tworzenia klasy i nie zmieniają się.

W poniższym przykładzie pokazano kod XAML, który korzysta z elementu PersonCollectionViewModel:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.PersonEntryPage"
             Title="Person Entry">
    <ContentPage.BindingContext>
        <local:PersonCollectionViewModel />
    </ContentPage.BindingContext>
    <Grid Margin="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- New Button -->
        <Button Text="New"
                Grid.Row="0"
                Command="{Binding NewCommand}"
                HorizontalOptions="Start" />

        <!-- Entry Form -->
        <Grid Grid.Row="1"
              IsEnabled="{Binding IsEditing}">
            <Grid BindingContext="{Binding PersonEdit}">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Label Text="Name: " Grid.Row="0" Grid.Column="0" />
                <Entry Text="{Binding Name}"
                       Grid.Row="0" Grid.Column="1" />
                <Label Text="Age: " Grid.Row="1" Grid.Column="0" />
                <StackLayout Orientation="Horizontal"
                             Grid.Row="1" Grid.Column="1">
                    <Stepper Value="{Binding Age}"
                             Maximum="100" />
                    <Label Text="{Binding Age, StringFormat='{0} years old'}"
                           VerticalOptions="Center" />
                </StackLayout>
                <Label Text="Skills: " Grid.Row="2" Grid.Column="0" />
                <Entry Text="{Binding Skills}"
                       Grid.Row="2" Grid.Column="1" />
            </Grid>
        </Grid>

        <!-- Submit and Cancel Buttons -->
        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <Button Text="Submit"
                    Grid.Column="0"
                    Command="{Binding SubmitCommand}"
                    VerticalOptions="Center" />
            <Button Text="Cancel"
                    Grid.Column="1"
                    Command="{Binding CancelCommand}"
                    VerticalOptions="Center" />
        </Grid>

        <!-- List of Persons -->
        <ListView Grid.Row="3"
                  ItemsSource="{Binding Persons}" />
    </Grid>
</ContentPage>

W tym przykładzie właściwość strony BindingContext jest ustawiona na PersonCollectionViewModelwartość . Zawiera Grid element Button z tekstem Nowy z właściwością Command powiązaną NewCommand z właściwością w modelu viewmodel, formularzem wpisu z właściwościami powiązanymi IsEditing z właściwością, a także właściwościami PersonViewModelelementu i dwoma przyciskami powiązanymi z SubmitCommand właściwościami i CancelCommand modelu viewmodel. Spowoduje to ListView wyświetlenie kolekcji osób, które zostały już wprowadzone:

Poniższy zrzut ekranu przedstawia przycisk Prześlij włączony po ustawieniu wieku:

Person Entry.

Gdy użytkownik po raz pierwszy naciska przycisk Nowy , włącza formularz wpisu, ale wyłącza przycisk Nowy . Następnie użytkownik wprowadza nazwę, wiek i umiejętności. W dowolnym momencie edytowania użytkownik może nacisnąć przycisk Anuluj , aby rozpocząć od nowa. Tylko wtedy, gdy wprowadzono nazwę i prawidłowy wiek, jest włączony przycisk Prześlij . Naciśnięcie tego przycisku Prześlij spowoduje przeniesienie osoby do kolekcji wyświetlanej ListViewprzez element . Po naciśnięciu przycisku Anuluj lub Prześlij formularz wpisu zostanie wyczyszczone, a przycisk Nowy zostanie ponownie włączony.

Cała logika przycisków Nowy, Prześlij i Anuluj jest obsługiwana PersonCollectionViewModel za pomocą definicji NewCommandwłaściwości , SubmitCommandi CancelCommand . Konstruktor zestawu PersonCollectionViewModel tych trzech właściwości do obiektów typu Command.

Konstruktor Command klasy umożliwia przekazywanie argumentów typu Action i Func<bool> odpowiadających metodom Execute i CanExecute . Tę akcję i funkcję można zdefiniować jako funkcje lambda w konstruktorze Command :

public class PersonCollectionViewModel : INotifyPropertyChanged
{
    ···
    public PersonCollectionViewModel()
    {
        NewCommand = new Command(
            execute: () =>
            {
                PersonEdit = new PersonViewModel();
                PersonEdit.PropertyChanged += OnPersonEditPropertyChanged;
                IsEditing = true;
                RefreshCanExecutes();
            },
            canExecute: () =>
            {
                return !IsEditing;
            });
        ···
    }

    void OnPersonEditPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        (SubmitCommand as Command).ChangeCanExecute();
    }

    void RefreshCanExecutes()
    {
        (NewCommand as Command).ChangeCanExecute();
        (SubmitCommand as Command).ChangeCanExecute();
        (CancelCommand as Command).ChangeCanExecute();
    }
    ···
}

Gdy użytkownik kliknie przycisk Nowy , execute funkcja przekazana do konstruktora Command zostanie wykonana. Spowoduje to utworzenie nowego PersonViewModel obiektu, ustawienie procedury obsługi dla zdarzenia tego obiektu PropertyChanged , ustawienie na IsEditingtrue, i wywołanie RefreshCanExecutes metody zdefiniowanej po konstruktorze.

Oprócz implementowania interfejsu ICommandCommand klasa definiuje również metodę o nazwie ChangeCanExecute. Model widoku powinien wywołać ChangeCanExecuteICommand właściwość za każdym razem, gdy coś się stanie, co może zmienić wartość CanExecute zwracaną metody. Wywołanie metody powoduje, że ChangeCanExecute klasa uruchamia metodę CanExecuteChanged .Command Element Button zawiera procedurę obsługi dla tego zdarzenia i odpowiada, wywołując CanExecute ponownie, a następnie włączając się na podstawie zwracanej wartości tej metody.

execute Gdy metoda wywołania NewCommandRefreshCanExecutesmetody , NewCommand właściwość pobiera wywołanie metody ChangeCanExecutei Button wywołuje canExecute metodę , która zwraca false teraz, ponieważ IsEditing właściwość ma teraz truewartość .

Procedura PropertyChanged obsługi dla nowego PersonViewModel obiektu wywołuje metodę ChangeCanExecuteSubmitCommand:

public class PersonCollectionViewModel : INotifyPropertyChanged
{
    ···
    public PersonCollectionViewModel()
    {
        ···
        SubmitCommand = new Command(
            execute: () =>
            {
                Persons.Add(PersonEdit);
                PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
                PersonEdit = null;
                IsEditing = false;
                RefreshCanExecutes();
            },
            canExecute: () =>
            {
                return PersonEdit != null &&
                       PersonEdit.Name != null &&
                       PersonEdit.Name.Length > 1 &&
                       PersonEdit.Age > 0;
            });
        ···
    }
    ···
}

Funkcja canExecute dla SubmitCommand elementu jest wywoływana za każdym razem, gdy w edytowanym obiekcie jest zmieniana PersonViewModel właściwość. Zwraca true tylko wtedy, Age gdy Name właściwość ma co najmniej jeden znak i jest większa niż 0. W tym czasie przycisk Prześlij zostanie włączony.

Funkcja executeSubmit usuwa program obsługi zmienionej właściwości z PersonViewModelobiektu , dodaje obiekt do Persons kolekcji i zwraca wszystko do stanu początkowego.

Funkcja executeprzycisku Anuluj wykonuje wszystko, co przycisk Prześlij , z wyjątkiem dodania obiektu do kolekcji:

public class PersonCollectionViewModel : INotifyPropertyChanged
{
    ···
    public PersonCollectionViewModel()
    {
        ···
        CancelCommand = new Command(
            execute: () =>
            {
                PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
                PersonEdit = null;
                IsEditing = false;
                RefreshCanExecutes();
            },
            canExecute: () =>
            {
                return IsEditing;
            });
    }
    ···
}

Metoda canExecute zwraca true wartość w dowolnym momencie PersonViewModel , gdy element jest edytowany.

Uwaga

Nie jest konieczne zdefiniowanie execute metod i canExecute jako funkcji lambda. Można je zapisywać jako metody prywatne w modelu viewmodel i odwoływać się do nich w Command konstruktorach. Jednak takie podejście może spowodować wiele metod, do których odwołuje się tylko raz w modelu widoku.

Używanie parametrów polecenia

Czasami jest to wygodne dla jednego lub kilku przycisków lub innych obiektów interfejsu użytkownika, aby współużytkować tę samą ICommand właściwość w modelu widoków. W takim przypadku można użyć CommandParameter właściwości , aby odróżnić przyciski.

Możesz nadal używać Command klasy dla tych właściwości udostępnionych ICommand . Klasa definiuje alternatywny konstruktor, który akceptuje execute metody i canExecute z parametrami typu Object. W ten sposób CommandParameter metoda jest przekazywana do tych metod. Jednak podczas określania CommandParameterklasy , najłatwiej jest użyć klasy ogólnej Command<T> do określenia typu obiektu ustawionego na CommandParameterwartość . Metody execute i canExecute , które określisz, mają parametry tego typu.

W poniższym przykładzie pokazano klawiaturę do wprowadzania liczb dziesiętnych:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:DataBindingDemos"
             x:Class="DataBindingDemos.DecimalKeypadPage"
             Title="Decimal Keyboard">
    <ContentPage.BindingContext>
        <local:DecimalKeypadViewModel />
    </ContentPage.BindingContext>
    <ContentPage.Resources>
        <Style TargetType="Button">
            <Setter Property="FontSize" Value="32" />
            <Setter Property="BorderWidth" Value="1" />
            <Setter Property="BorderColor" Value="Black" />
        </Style>
    </ContentPage.Resources>

    <Grid WidthRequest="240"
          HeightRequest="480"
          ColumnDefinitions="80, 80, 80"
          RowDefinitions="Auto, Auto, Auto, Auto, Auto, Auto"
          ColumnSpacing="2"
          RowSpacing="2"
          HorizontalOptions="Center"
          VerticalOptions="Center">
        <Label Text="{Binding Entry}"
               Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
               Margin="0,0,10,0"
               FontSize="32"
               LineBreakMode="HeadTruncation"
               VerticalTextAlignment="Center"
               HorizontalTextAlignment="End" />
        <Button Text="CLEAR"
                Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
                Command="{Binding ClearCommand}" />
        <Button Text="&#x21E6;"
                Grid.Row="1" Grid.Column="2"
                Command="{Binding BackspaceCommand}" />
        <Button Text="7"
                Grid.Row="2" Grid.Column="0"
                Command="{Binding DigitCommand}"
                CommandParameter="7" />
        <Button Text="8"
                Grid.Row="2" Grid.Column="1"
                Command="{Binding DigitCommand}"
                CommandParameter="8" />        
        <Button Text="9"
                Grid.Row="2" Grid.Column="2"
                Command="{Binding DigitCommand}"
                CommandParameter="9" />
        <Button Text="4"
                Grid.Row="3" Grid.Column="0"
                Command="{Binding DigitCommand}"
                CommandParameter="4" />
        <Button Text="5"
                Grid.Row="3" Grid.Column="1"
                Command="{Binding DigitCommand}"
                CommandParameter="5" />
        <Button Text="6"
                Grid.Row="3" Grid.Column="2"
                Command="{Binding DigitCommand}"
                CommandParameter="6" />
        <Button Text="1"
                Grid.Row="4" Grid.Column="0"
                Command="{Binding DigitCommand}"
                CommandParameter="1" />
        <Button Text="2"
                Grid.Row="4" Grid.Column="1"
                Command="{Binding DigitCommand}"
                CommandParameter="2" />
        <Button Text="3"
                Grid.Row="4" Grid.Column="2"
                Command="{Binding DigitCommand}"
                CommandParameter="3" />
        <Button Text="0"
                Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2"
                Command="{Binding DigitCommand}"
                CommandParameter="0" />
        <Button Text="&#x00B7;"
                Grid.Row="5" Grid.Column="2"
                Command="{Binding DigitCommand}"
                CommandParameter="." />
    </Grid>
</ContentPage>

W tym przykładzie strona BindingContext to DecimalKeypadViewModel. Właściwość Entry tego modelu viewmodel jest powiązana z Text właściwością Label. Button Wszystkie obiekty są powiązane z poleceniami w modelu widoków: ClearCommand, BackspaceCommandi DigitCommand. 11 przycisków dla 10 cyfr i punkt dziesiętny współużytkuje powiązanie z DigitCommand. Rozróżniane CommandParameter są te przyciski. Wartość ustawiona na CommandParameter jest zazwyczaj taka sama jak tekst wyświetlany przez przycisk z wyjątkiem przecinka dziesiętnego, który dla celów jasności jest wyświetlany z środkowym znakiem kropki:

Decimal keyboard.

Definiuje DecimalKeypadViewModel właściwość typu string i trzy właściwości typu ICommand:Entry

public class DecimalKeypadViewModel : INotifyPropertyChanged
{
    string entry = "0";

    public event PropertyChangedEventHandler PropertyChanged;
    ···

    public string Entry
    {
        private set
        {
            if (entry != value)
            {
                entry = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Entry"));
            }
        }
        get
        {
            return entry;
        }
    }

    public ICommand ClearCommand { private set; get; }
    public ICommand BackspaceCommand { private set; get; }
    public ICommand DigitCommand { private set; get; }
}

Przycisk odpowiadający ClearCommand elementowi jest zawsze włączony i ustawia wpis z powrotem na "0":

public class DecimalKeypadViewModel : INotifyPropertyChanged
{
    ···
    public DecimalKeypadViewModel()
    {
        ClearCommand = new Command(
            execute: () =>
            {
                Entry = "0";
                RefreshCanExecutes();
            });
        ···
    }

    void RefreshCanExecutes()
    {
        ((Command)BackspaceCommand).ChangeCanExecute();
        ((Command)DigitCommand).ChangeCanExecute();
    }
    ···
}

Ponieważ przycisk jest zawsze włączony, nie jest konieczne określenie canExecute argumentu w konstruktorze Command .

Przycisk Backspace jest włączony tylko wtedy, gdy długość wpisu jest większa niż 1 lub jeśli Entry nie jest równa ciągu "0":

public class DecimalKeypadViewModel : INotifyPropertyChanged
{
    ···
    public DecimalKeypadViewModel()
    {
        ···
        BackspaceCommand = new Command(
            execute: () =>
            {
                Entry = Entry.Substring(0, Entry.Length - 1);
                if (Entry == "")
                {
                    Entry = "0";
                }
                RefreshCanExecutes();
            },
            canExecute: () =>
            {
                return Entry.Length > 1 || Entry != "0";
            });
        ···
    }
    ···
}

Logika execute funkcji przycisku Backspace gwarantuje, że Entry element jest co najmniej ciągiem "0".

Właściwość DigitCommand jest powiązana z 11 przyciskami, z których każda identyfikuje się z właściwością CommandParameter . Właściwość DigitCommand jest ustawiona na wystąpienie Command<T> klasy . W przypadku używania interfejsu poleceń z językiem XAML CommandParameter właściwości są zwykle ciągami, które są typem argumentu ogólnego. Funkcje execute i canExecute mają argumenty typu string:

public class DecimalKeypadViewModel : INotifyPropertyChanged
{
    ···
    public DecimalKeypadViewModel()
    {
        ···
        DigitCommand = new Command<string>(
            execute: (string arg) =>
            {
                Entry += arg;
                if (Entry.StartsWith("0") && !Entry.StartsWith("0."))
                {
                    Entry = Entry.Substring(1);
                }
                RefreshCanExecutes();
            },
            canExecute: (string arg) =>
            {
                return !(arg == "." && Entry.Contains("."));
            });
    }
    ···
}

Metoda execute dołącza argument ciągu do Entry właściwości . Jeśli jednak wynik zaczyna się od zera (ale nie zera i punktu dziesiętnego), to początkowe zero musi zostać usunięte przy użyciu Substring funkcji . canExecute Metoda zwraca tylko false wtedy, gdy argument jest punktem dziesiętnym (wskazującym, że punkt dziesiętny jest naciskany) i Entry zawiera już punkt dziesiętny. Wszystkie metody wywołają metodę executeRefreshCanExecutes, która następnie wywołuje metodę ChangeCanExecute zarówno , jak DigitCommand i ClearCommand. Dzięki temu przyciski punktów dziesiętnych i backspace są włączone lub wyłączone w oparciu o bieżącą sekwencję wprowadzonych cyfr.