Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W aplikacji wieloplatformowej interfejsu użytkownika .NET (.NET MAUI), która korzysta ze wzorca Model-View-ViewModel (MVVM), powiązania danych są definiowane między właściwościami w viewmodelu, który jest zazwyczaj klasą pochodzącą z INotifyPropertyChanged, a właściwościami w widoku, który 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 dotknięcia palcem i tradycyjnie są przetwarzane w pliku code-behind w programie obsługi zdarzeń dla zdarzenia ClickedButton lub zdarzenia TappedTapGestureRecognizer.
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 odpowiedzi na konkretną akcję w widoku, taką jak kliknięcie Button. Powiązania danych są definiowane między tymi poleceniami a elementem Button.
Aby umożliwić powiązanie danych pomiędzy Button a modelem-widokiem, Button definiuje dwie właściwości:
-
CommandtypuSystem.Windows.Input.ICommand -
CommandParametertypuObject
Aby użyć interfejsu polecenia, należy zdefiniować powiązanie danych, które celuje w właściwość Command, gdzie źródłem jest właściwość w modelu widoku typu Button. Viewmodel zawiera kod skojarzony z tą ICommand właściwością, który jest wykonywany po kliknięciu przycisku. Właściwość CommandParameter można ustawić dla dowolnych danych, aby odróżnić wiele przycisków, jeśli wszystkie są powiązane z tą samą ICommand właściwością w modelu widoku.
Wiele innych widoków również definiuje właściwości Command 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 korzystać z interfejsu komend, 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 właściwość Command obiektu Button jest powiązana z tą właściwością:
<Button Text="Execute command"
Command="{Binding MyCommand}" />
Gdy użytkownik naciśnie Button, Button wywołuje metodę Execute w obiekcie ICommand powiązanym z jego właściwością Command.
Gdy powiązanie jest najpierw zdefiniowane dla właściwości Command w Button, i gdy powiązanie danych zmienia się w jakiś sposób, Button wykonuje wywołanie metody CanExecute na obiekcie ICommand. Jeśli CanExecute zwróci false, wtedy Button wyłącza się. Oznacza to, że określone polecenie jest obecnie niedostępne lub nieprawidłowe.
Element Button dołącza również program obsługi zdarzenia CanExecuteChanged na ICommand. Zdarzenie musi być wywoływane ręcznie w modelu widoku za każdym razem, gdy zmieniają się warunki wpływające na CanExecute wynik. Gdy to zdarzenie zostanie wywołane, Button ponownie wywołuje CanExecute. Funkcja Button włącza się, jeśli CanExecute zwraca true, i wyłącza się, jeśli CanExecute zwraca false.
Ważne
W przeciwieństwie do niektórych struktur interfejsu użytkownika (takich jak WPF), program .NET MAUI nie wykrywa automatycznie, kiedy wartość zwracana CanExecute może ulec zmianie. Należy ręcznie zgłosić CanExecuteChanged zdarzenie (lub wywołać ChangeCanExecute() na klasie Command) za każdym razem, gdy nastąpi jakakolwiek zmiana warunku, która miałaby wpływ na CanExecute wynik. Zazwyczaj odbywa się to po zmodyfikowaniu właściwości, od których CanExecute zależy.
Uwaga / Notatka
Możesz także zamiast metody IsEnabled, skorzystać z właściwości Button lub używać ich razem. W programie .NET MAUI 7 i wcześniejszych wersjach nie było możliwe użycie IsEnabled właściwości Button przy użyciu interfejsu poleceń, ponieważ zwracana wartość metody CanExecute zawsze zastępowała właściwość IsEnabled. Jest to naprawione w programie .NET MAUI 8 i nowszym; właściwość IsEnabled jest teraz dostępna dla Button poleceń. Należy jednak pamiętać, że zarówno IsEnabled właściwość, jak i CanExecute metoda muszą teraz zwracać wartość true, aby kontrolka mogła zostać włączona (oraz kontrolka nadrzędna musi być również włączona).
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 metod Execute i CanExecute, oraz ręcznie wywoływać zdarzenie CanExecuteChanged za każdym razem, gdy metoda CanExecute może zwrócić inną wartość. Aby zaimplementować interfejs Command, można użyć klasy Command<T> lub ICommand dołączonej do .NET MAUI. Te klasy umożliwiają określenie treści metod Execute i CanExecute w konstruktorach klas.
Wskazówka
Użyj Command<T>, gdy korzystasz z właściwości CommandParameter do rozróżnienia między wieloma widokami powiązanymi z tą samą właściwością ICommand, lub klasę Command, gdy to nie jest wymagane.
Podstawowe komendy
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 bool, oraz PersonEdit, typu PersonViewModel, 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 w trzech właściwościach ICommand oraz właściwości Persons nie powodują generowania zdarzeń PropertyChanged. 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"
x:DataType="local:PersonCollectionViewModel">
<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 x:DataType="local:PersonViewModel"
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 PersonCollectionViewModel. Zawiera Grid, który zawiera Button z tekstem Nowy, z właściwością Command powiązaną z właściwością NewCommand w modelu viewmodel, formularz wpisu z właściwościami powiązanymi z właściwością IsEditing, a także element z właściwościami PersonViewModel oraz dwa przyciski powiązane z właściwościami SubmitCommand i CancelCommand w modelu viewmodel.
ListView wyświetla kolekcję osób już wprowadzonych:
Poniższy zrzut ekranu przedstawia przycisk Prześlij włączony po ustawieniu wieku:
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 . Kliknięcie przycisku Prześlij spowoduje przeniesienie osoby do kolekcji wyświetlanej przez ListView. Po naciśnięciu przycisku Anuluj lub Prześlij, formularz wpisu zostanie wyczyszczony, a przycisk Nowy stanie się ponownie aktywny.
Cała logika przycisków Nowy, Prześlij i Anuluj jest obsługiwana w PersonCollectionViewModel za pomocą definicji NewCommand, SubmitCommand i CancelCommand. Konstruktor PersonCollectionViewModel ustawia te trzy właściwości na obiekty 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 obiektu PersonViewModel, ustawienie procedury obsługi dla zdarzenia PropertyChanged tego obiektu, ustawienie IsEditing na true, oraz wywołanie metody RefreshCanExecutes, zdefiniowanej po konstruktorze.
Oprócz implementowania interfejsu ICommandCommand klasa definiuje również metodę o nazwie ChangeCanExecute. Model widoku musi wywołać ChangeCanExecute dla właściwości ICommand za każdym razem, gdy zdarzy się coś, co może zmienić wartość zwracaną przez metodę CanExecute. Wywołanie ChangeCanExecute powoduje, że klasa Command uruchamia zdarzenie CanExecuteChanged. 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.
Gdy metoda execute wywołania NewCommand wywołuje RefreshCanExecutes, właściwość NewCommand odwołuje się do ChangeCanExecute, a Button wywołuje metodę canExecute, która teraz zwraca false z powodu zmiany wartości właściwości IsEditing na true.
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 elementu SubmitCommand jest wywoływana za każdym razem, gdy zmienia się właściwość PersonViewModel w edytowanym obiekcie. Zwraca true tylko wtedy, gdy właściwość Name ma co najmniej jeden znak, a Age jest większe niż 0. W tym czasie przycisk Prześlij zostanie włączony.
Funkcja executeSubmit usuwa program obsługi zmienionej właściwości z obiektu PersonViewModel, dodaje obiekt do kolekcji Persons i zwraca wszystko do stanu początkowego.
Funkcja execute przycisku 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 w dowolnym momencie, gdy PersonViewModel jest edytowany.
Uwaga / Notatka
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ć klasy Command dla tych wspólnych właściwości ICommand. Klasa definiuje alternatywny konstruktor, który akceptuje metody execute i canExecute z parametrami typu Object. W ten sposób CommandParameter jest przekazywany do tych metod. Jednak podczas określania CommandParameter najłatwiej jest użyć ogólnej klasy Command<T> do określenia typu obiektu ustawionego na wartość CommandParameter. 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"
x:DataType="local:DecimalKeypadViewModel">
<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="⇦"
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="·"
Grid.Row="5" Grid.Column="2"
Command="{Binding DigitCommand}"
CommandParameter="." />
</Grid>
</ContentPage>
W tym przykładzie BindingContext strony 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 punktu dziesiętnego dzieli powiązanie z DigitCommand.
CommandParameter rozróżnia 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:
Definiuje DecimalKeypadViewModel właściwość typu Entry i trzy właściwości typu string:ICommand
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 aktywny, nie ma potrzeby określania argumentu canExecute 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 funkcji execute przycisku Backspace gwarantuje, że Entry 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 klasy Command<T>. W przypadku używania interfejsu poleceń z językiem XAML, CommandParameter właściwości są zwykle ciągami znaków, które określają typ argumentu generycznego. 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 ciąg znaków jako argument do właściwości Entry. 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łują execute, która następnie wywołuje RefreshCanExecutes zarówno dla ChangeCanExecute, jak i DigitCommand. Dzięki temu przyciski punktów dziesiętnych i backspace są włączone lub wyłączone w oparciu o bieżącą sekwencję wprowadzonych cyfr.
Przeglądanie przykładu