Xamarin.Forms Komut Arabirimi
Model-View-ViewModel (MVVM) mimarisinde veri bağlamaları, genellikle öğesinden INotifyPropertyChanged
türetilen bir sınıf olan ViewModel'deki özellikler ve genel olarak XAML dosyası olan Görünüm'deki özellikler arasında tanımlanır. Bazen bir uygulamanın, kullanıcının ViewModel'de bir şeyi etkileyen komutları başlatmasını gerektirerek bu özellik bağlamalarının ötesine geçme gereksinimleri vardır. Bu komutlar genellikle düğme tıklamaları veya parmak dokunuşları ile işaretlenir ve geleneksel olarak bir veya olayının işleyicisindeki Clicked
Button
Tapped
TapGestureRecognizer
arka planda kod dosyasında işlenir.
Komut arabirimi, MVVM mimarisine çok daha uygun komutları uygulamak için alternatif bir yaklaşım sağlar. ViewModel'in kendisi, Görünüm'deki belirli bir etkinliğe tepki olarak yürütülen, tıklama gibi Button
yöntemler olan komutları içerebilir. Veri bağlamaları bu komutlarla Button
arasında tanımlanır.
ile ViewModel arasında Button
veri bağlamaya izin vermek için iki Button
özelliği tanımlar:
Command
türüSystem.Windows.Input.ICommand
CommandParameter
türüObject
Komut arabirimini kullanmak için, kaynağın ViewModel türünde ICommand
bir özellik Button
olduğu özelliğini hedefleyen Command
bir veri bağlaması tanımlarsınız. ViewModel, düğmeye tıklandığında yürütülen bu ICommand
özellikle ilişkilendirilmiş kodu içerir. Tümü ViewModel'deki aynı ICommand
özelliğe bağlıysa, birden çok düğmeyi ayırt etmek için rastgele verilere ayarlayabilirsinizCommandParameter
.
Command
ve CommandParameter
özellikleri de aşağıdaki sınıflar tarafından tanımlanır:
MenuItem
ve bu nedenle,ToolbarItem
MenuItem
TextCell
ve bu nedenle,ImageCell
TextCell
TapGestureRecognizer
SearchBar
SearchCommand
türüne ICommand
ve özelliğine sahip bir SearchCommandParameter
özelliği tanımlar. özelliği RefreshCommand
ListView
de türündedir ICommand
.
Bu komutların tümü ViewModel içinde, Görünüm'deki belirli kullanıcı arabirimi nesnesine bağımlı olmayan bir şekilde işlenebilir.
ICommand Arabirimi
System.Windows.Input.ICommand
Arabirim, öğesinin Xamarin.Formsbir parçası değildir. Bunun yerine System.Windows.Input ad alanında tanımlanır ve iki yöntemden ve bir olaydan oluşur:
public interface ICommand
{
public void Execute (Object parameter);
public bool CanExecute (Object parameter);
public event EventHandler CanExecuteChanged;
}
Komut arabirimini kullanmak için ViewModel'iniz türünde ICommand
özellikler içerir:
public ICommand MyCommand { private set; get; }
ViewModel ayrıca arabirimini uygulayan bir sınıfa ICommand
da başvurmalıdır. Bu sınıf kısa süre içinde açıklanacaktır. Görünüm'de, öğesinin Command
Button
özelliği bu özelliğe bağlıdır:
<Button Text="Execute command"
Command="{Binding MyCommand}" />
Kullanıcı tuşuna bastığındaButton
Button
, özelliğine Command
bağlı nesnede ICommand
yöntemini çağırırExecute
. Komut arabiriminin en basit kısmıdır.
CanExecute
yöntemi daha karmaşıktır. Bağlama özelliğinde Command
Button
ilk kez tanımlandığında ve veri bağlaması bir şekilde değiştiğinde, Button
nesnesindeki CanExecute
ICommand
yöntemini çağırır. döndürürse CanExecute
false
, Button
kendisini devre dışı bırakır. Bu, belirli bir komutun şu anda kullanılamadığını veya geçersiz olduğunu gösterir.
ayrıca Button
olayına CanExecuteChanged
ICommand
bir işleyici ekler. Olay ViewModel'in içinden tetiklenir. Olay tetiklendiğinde yeniden çağrılar Button
CanExecute
yapılır. döndürürse Button
CanExecute
true
kendisini etkinleştirir ve döndürürse CanExecute
false
kendisini devre dışı bırakır.
Önemli
Komut arabirimini IsEnabled
kullanıyorsanız özelliğini Button
kullanmayın.
Komut Sınıfı
ViewModel'iniz türünde ICommand
bir özellik tanımladığında, ViewModel'in arabirimini uygulayan bir sınıfı da içermesi veya buna başvurması ICommand
gerekir. Bu sınıfın ve CanExecute
yöntemlerini içermesi Execute
veya bunlara başvurması ve yöntemin CanExecuteChanged
farklı bir değer döndürebileceği her durumda CanExecute
olayı tetiklemesi gerekir.
Böyle bir sınıfı kendiniz yazabilir veya başka birinin yazdığı bir sınıfı kullanabilirsiniz. ICommand
Microsoft Windows'un bir parçası olduğundan, yıllardır Windows MVVM uygulamalarıyla kullanılmıştır. Uygulayan ICommand
bir Windows sınıfı kullanmak, ViewModel'lerinizi Windows uygulamaları ve Xamarin.Forms uygulamaları arasında paylaşmanıza olanak tanır.
ViewModel'leri Windows Xamarin.Forms arasında paylaşmak sorun değilse arabirimini uygulamak için içindeki Xamarin.Forms veya Command<T>
sınıfını ICommand
kullanabilirsinizCommand
. Bu sınıflar, sınıf oluşturucularında ve CanExecute
yöntemlerinin Execute
gövdelerini belirtmenize olanak sağlar. Aynı özelliğe bağlı birden çok görünümü ayırt etmek için ICommand
özelliğini kullandığınızda ve bu bir gereksinim olmadığında daha Command
basit sınıfını kullandığınızda CommandParameter
kullanınCommand<T>
.
Temel Komut
Örnek programdaki Kişi Girişi sayfasında ViewModel'de uygulanan bazı basit komutlar gösterilir.
, PersonViewModel
adlı Name
Age
ve Skills
bir kişiyi tanımlayan üç özelliği tanımlar. Bu sınıf herhangi bir ICommand
özellik içermiyor:
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));
}
}
Aşağıda PersonCollectionViewModel
gösterilen, türünde PersonViewModel
yeni nesneler oluşturur ve kullanıcının verileri doldurmasına izin verir. Bu amaçla, sınıfı türü bool
ve PersonEdit
türündeki PersonViewModel
özellikleri IsEditing
tanımlar. Buna ek olarak, sınıfı türün üç özelliğini ve türünde ICommand
IList<PersonViewModel>
adlı Persons
bir özelliği tanımlar:
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));
}
}
Bu kısaltılmış liste, sınıfın oluşturucusunu içermez. Bu, türün ICommand
üç özelliğinin tanımlandığı yerdir ve bu özellik kısa süre sonra gösterilir. türünün ICommand
ve özelliğinin üç özelliğinde Persons
yapılan değişikliklerin tetiklenen olaylarla sonuçlanmadığını PropertyChanged
fark edin. Bu özelliklerin tümü sınıf ilk oluşturulduğunda ayarlanır ve bundan sonra değişmez.
Sınıfının oluşturucusunu PersonCollectionViewModel
incelemeden önce, Kişi Girişi programı için XAML dosyasına bakalım. Bu, özelliği olarak ayarlanmış PersonCollectionViewModel
bir Grid
BindingContext
içerir. , Grid
Özelliği ViewModel'deki özelliğine bağlı olan Yeni Command
metnini, özelliğine NewCommand
bağlı özelliklere IsEditing
sahip bir giriş formunun yanı sıra , ve PersonViewModel
ViewModel'in özelliklerine SubmitCommand
bağlı iki CancelCommand
düğme daha içerirButton
. Son olarak ListView
, daha önce girilmiş olan kişilerin koleksiyonu görüntülenir:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.PersonEntryPage"
Title="Person Entry">
<Grid Margin="10">
<Grid.BindingContext>
<local:PersonCollectionViewModel />
</Grid.BindingContext>
<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="CenterAndExpand" />
<Button Text="Cancel"
Grid.Column="1"
Command="{Binding CancelCommand}"
VerticalOptions="CenterAndExpand" />
</Grid>
<!-- List of Persons -->
<ListView Grid.Row="3"
ItemsSource="{Binding Persons}" />
</Grid>
</ContentPage>
Şu şekilde çalışır: Kullanıcı önce Yeni düğmesine basar. Bu, giriş formunu etkinleştirir ancak Yeni düğmesini devre dışı bırakır. Kullanıcı daha sonra bir ad, yaş ve beceri girer. Düzenleme sırasında kullanıcı, baştan başlamak için İptal düğmesine basabilir. Yalnızca bir ad ve geçerli bir yaş girildiğinde Gönder düğmesi etkinleştirilir. Bu Gönder düğmesine basıldığında, kişi tarafından görüntülenen koleksiyona ListView
aktarılır. İptal veya Gönder düğmesine basıldıktan sonra, giriş formu temizlenir ve Yeni düğmesi yeniden etkinleştirilir.
Soldaki iOS ekranında geçerli bir yaş girilmeden önce düzen gösterilir. Android ekranında , bir yaş ayarlandıktan sonra Gönder düğmesi etkinleştirilir:
Programın var olan girişleri düzenlemek için herhangi bir özelliği yoktur ve sayfadan çıktığınızda girişleri kaydetmez.
Yeni, Gönder ve İptal düğmelerinin tüm mantığı , SubmitCommand
ve CancelCommand
özelliklerinin tanımları NewCommand
aracılığıyla işlenirPersonCollectionViewModel
. oluşturucu bu PersonCollectionViewModel
üç özelliği türündeki Command
nesnelere ayarlar.
sınıfının oluşturucusunun Command
türü ve Func<bool>
ve CanExecute
yöntemlerine Execute
karşılık gelen bağımsız değişkenleri Action
geçirmenize olanak tanır. Bu eylemleri ve işlevleri doğrudan oluşturucuda lambda işlevleri olarak tanımlamak en kolayıdır Command
. özelliği için nesnesinin Command
tanımı aşağıdadır NewCommand
:
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();
}
···
}
Kullanıcı Yeni düğmesine tıkladığında, execute
oluşturucuya Command
geçirilen işlev yürütülür. Bu, yeni PersonViewModel
bir nesne oluşturur, nesnenin PropertyChanged
olayı üzerinde bir işleyici ayarlar, olarak true
ayarlar IsEditing
ve oluşturucudan sonra tanımlanan yöntemi çağırırRefreshCanExecutes
.
sınıfı, Command
arabirimini ICommand
uygulamanın yanı sıra adlı ChangeCanExecute
bir yöntem de tanımlar. Yöntemin dönüş değerini değiştirebilecek herhangi bir şey olduğunda ViewModel'iniz CanExecute
bir ICommand
özelliği çağırmalıdırChangeCanExecute
. çağrısıChangeCanExecute
, sınıfının yöntemini tetiklesine CanExecuteChanged
neden olurCommand
. Button
, bu olay için bir işleyici eklemiş ve yeniden çağırarak CanExecute
ve ardından bu yöntemin dönüş değerine göre kendisini etkinleştirerek yanıt verir.
yöntemi çağırdığındaRefreshCanExecutes
, NewCommand
özelliği öğesine ChangeCanExecute
bir çağrı alır ve Button
yöntemi çağırdığındacanExecute
, artık özelliği şu anda true
olduğu için IsEditing
yöntemini döndürürfalse
.NewCommand
execute
PropertyChanged
Yeni PersonViewModel
nesnenin işleyicisi yöntemini SubmitCommand
çağırırChangeCanExecute
. Bu komut özelliği şu şekilde uygulanır:
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;
});
···
}
···
}
canExecute
için işleviSubmitCommand
, düzenlenmekte olan nesnede her özellik değiştiğinde PersonViewModel
çağrılır. Yalnızca özelliği en az bir karakter uzunluğunda ve Age
0'dan büyük olduğunda Name
döndürürtrue
. Bu sırada Gönder düğmesi etkinleştirilir.
execute
Submit işlevi, özelliği değiştirilmiş işleyicisini öğesinden PersonViewModel
kaldırır, nesnesini koleksiyona Persons
ekler ve her şeyi ilk koşullara döndürür.
İptal düğmesinin işlevi, nesneyi koleksiyona eklemek dışında Gönder düğmesinin yaptığı her şeyi yapar: execute
public class PersonCollectionViewModel : INotifyPropertyChanged
{
···
public PersonCollectionViewModel()
{
···
CancelCommand = new Command(
execute: () =>
{
PersonEdit.PropertyChanged -= OnPersonEditPropertyChanged;
PersonEdit = null;
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return IsEditing;
});
}
···
}
yöntemicanExecute
, düzenlenmekte olan herhangi bir PersonViewModel
zamanda döndürürtrue
.
Bu teknikler daha karmaşık senaryolara uyarlanabilir: içindeki PersonCollectionViewModel
bir özellik mevcut öğeleri düzenlemek için öğesinin ListView
özelliğine SelectedItem
bağlanabilir ve bu öğeleri silmek için bir Sil düğmesi eklenebilir.
ve canExecute
yöntemlerini lambda işlevleri olarak tanımlamak execute
gerekmez. Bunları ViewModel'de normal özel yöntemler olarak yazabilir ve oluşturucularda Command
bunlara başvurabilirsiniz. Ancak bu yaklaşım, ViewModel'de yalnızca bir kez başvuruda bulunan birçok yöntemle sonuçlanır.
Komut Parametrelerini Kullanma
Bazen bir veya daha fazla düğmenin (veya diğer kullanıcı arabirimi nesnelerinin) ViewModel'de aynı ICommand
özelliği paylaşması kullanışlı olabilir. Bu durumda, düğmeleri ayırt etmek için özelliğini kullanırsınız CommandParameter
.
Bu paylaşılan ICommand
özellikler için sınıfını Command
kullanmaya devam edebilirsiniz. sınıfı, türündeki Object
parametrelere sahip ve canExecute
yöntemlerini kabul execute
eden alternatif bir oluşturucu tanımlar. bu yöntemlere bu şekilde CommandParameter
geçirilir.
Ancak kullanırkenCommandParameter
, olarak ayarlanan CommandParameter
nesnenin türünü belirtmek için genel Command<T>
sınıfı kullanmak en kolayıdır. execute
Belirttiğiniz ve canExecute
yöntemleri bu tür parametrelere sahiptir.
Ondalık Klavye sayfasında, ondalık sayıları girmek için tuş takımının nasıl uygulandığı gösterilerek bu teknik gösterilir. BindingContext
için Grid
bir DecimalKeypadViewModel
şeklindedir. Entry
Bu ViewModel'in özelliği, özelliğine Text
Label
bağlıdır. Button
Tüm nesneler ViewModel'deki çeşitli komutlara bağlıdır: ClearCommand
, BackspaceCommand
ve DigitCommand
:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.DecimalKeypadPage"
Title="Decimal Keyboard">
<Grid WidthRequest="240"
HeightRequest="480"
ColumnSpacing="2"
RowSpacing="2"
HorizontalOptions="Center"
VerticalOptions="Center">
<Grid.BindingContext>
<local:DecimalKeypadViewModel />
</Grid.BindingContext>
<Grid.Resources>
<ResourceDictionary>
<Style TargetType="Button">
<Setter Property="FontSize" Value="32" />
<Setter Property="BorderWidth" Value="1" />
<Setter Property="BorderColor" Value="Black" />
</Style>
</ResourceDictionary>
</Grid.Resources>
<Label Text="{Binding Entry}"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
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>
10 basamak için 11 düğmesi ve ondalık noktası ile DigitCommand
bir bağlama paylaşır. bu CommandParameter
düğmeler arasında ayrımlar. olarak ayarlanan CommandParameter
değer, açıklık amacıyla orta nokta karakteriyle görüntülenen ondalık nokta dışında düğme tarafından görüntülenen metinle genel olarak aynıdır.
İşte program şu şekildedir:
Girilen sayı zaten bir ondalık nokta içerdiğinden, üç ekran görüntüsündeki ondalık nokta düğmesinin devre dışı olduğuna dikkat edin.
türündeki DecimalKeypadViewModel
string
bir Entry
özelliği (bir PropertyChanged
olayı tetikleyen tek özelliktir) ve türündeki ICommand
üç özelliği tanımlar:
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; }
}
düğmesine karşılık gelen ClearCommand
düğme her zaman etkindir ve girişi "0" olarak ayarlar:
public class DecimalKeypadViewModel : INotifyPropertyChanged
{
···
public DecimalKeypadViewModel()
{
ClearCommand = new Command(
execute: () =>
{
Entry = "0";
RefreshCanExecutes();
});
···
}
void RefreshCanExecutes()
{
((Command)BackspaceCommand).ChangeCanExecute();
((Command)DigitCommand).ChangeCanExecute();
}
···
}
Düğme her zaman etkinleştirildiğinden, oluşturucuda Command
bir canExecute
bağımsız değişken belirtmek gerekmez.
Sayı ve geri saydamlık girme mantığı biraz karmaşıktır çünkü basamak girilmemişse özelliği Entry
"0" dizesidir. Kullanıcı daha fazla sıfır içeriyorsa, Entry
yine de yalnızca bir sıfır içerir. Kullanıcı başka bir basamak yazarken, bu basamak sıfırın yerini alır. Ancak kullanıcı başka bir basamak öncesinde bir ondalık nokta yazdıysa , Entry
"0" dizesidir.
Geri Al düğmesi yalnızca girdinin uzunluğu 1'den büyükse veya "0" dizesine eşit değilse Entry
etkinleştirilir:
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";
});
···
}
···
}
Geri Al düğmesinin execute
işlevinin mantığı, işlevinin Entry
en az "0" dizesi olmasını sağlar.
DigitCommand
özelliği, her biri kendisini özelliğiyle tanımlayan 11 düğmeye CommandParameter
bağlıdır. DigitCommand
normal Command
sınıfın bir örneğine ayarlanabilir, ancak genel sınıfı kullanmak Command<T>
daha kolaydır. Komut arabirimini XAML ile kullanırken, CommandParameter
özellikler genellikle dizelerdir ve bu genel bağımsız değişkenin türüdür. ve execute
canExecute
işlevleri daha sonra türünde string
bağımsız değişkenlere sahiptir:
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("."));
});
}
···
}
yöntemi, execute
dize bağımsız değişkenini özelliğine Entry
ekler. Ancak, sonuç sıfırla (sıfır ve ondalık noktayla değil) başlıyorsa, ilk sıfır işlevi kullanılarak Substring
kaldırılmalıdır.
canExecute
yöntemi yalnızca bağımsız değişken ondalık noktaysa (ondalık ayırıcıya basıldığını gösterir) ve Entry
zaten bir ondalık nokta içeriyorsa döndürürfalse
.
execute
Tüm yöntemler, hem hem de ClearCommand
DigitCommand
için çağrı yapan öğesini çağırırRefreshCanExecutes
ChangeCanExecute
. Bu, girilen basamakların geçerli sırasına göre ondalık nokta ve geri al düğmelerinin etkinleştirilmesini veya devre dışı bırakılmasını sağlar.
Gezinti Menüleri için Zaman Uyumsuz Komut Oluşturma
Komut, gezinti menülerini uygulamak için kullanışlıdır. MainPage.xaml dosyasının bir bölümü aşağıdadır:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.MainPage"
Title="Data Binding Demos"
Padding="10">
<TableView Intent="Menu">
<TableRoot>
<TableSection Title="Basic Bindings">
<TextCell Text="Basic Code Binding"
Detail="Define a data-binding in code"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicCodeBindingPage}" />
<TextCell Text="Basic XAML Binding"
Detail="Define a data-binding in XAML"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:BasicXamlBindingPage}" />
<TextCell Text="Alternative Code Binding"
Detail="Define a data-binding in code without a BindingContext"
Command="{Binding NavigateCommand}"
CommandParameter="{x:Type local:AlternativeCodeBindingPage}" />
···
</TableSection>
</TableRoot>
</TableView>
</ContentPage>
XAML ile komut kullanılırken, CommandParameter
özellikler genellikle dizelere ayarlanır. Ancak bu durumda, türünde System.Type
olması için CommandParameter
bir XAML işaretleme uzantısı kullanılır.
Her Command
özellik adlı NavigateCommand
bir özelliğe bağlıdır. Bu özellik arka planda kod dosyasında tanımlanır MainPage.xaml.cs:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
NavigateCommand = new Command<Type>(
async (Type pageType) =>
{
Page page = (Page)Activator.CreateInstance(pageType);
await Navigation.PushAsync(page);
});
BindingContext = this;
}
public ICommand NavigateCommand { private set; get; }
}
Oluşturucu, özelliğini parametresini NavigateCommand
başlatan bir execute
yönteme System.Type
ayarlar ve ardından bu yönteme gider. PushAsync
Çağrısı bir await
işleç gerektirdiğinden execute
yöntemi zaman uyumsuz olarak işaretlenmelidir. Bu, parametre listesinden önce anahtar async
sözcüğüyle gerçekleştirilir.
Oluşturucu, bağlamaların bu sınıfta öğesine başvurması NavigateCommand
için sayfanın kendisini de ayarlarBindingContext
.
Bu oluşturucudaki kodun sırası bir fark yaratır: InitializeComponent
Çağrı XAML'nin ayrıştırılmasına neden olur, ancak o sırada adlı NavigateCommand
bir özelliğe bağlama çözümlenemez çünkü BindingContext
olarak ayarlanır null
. BindingContext
oluşturucuda ayarlanmadan önce NavigateCommand
ayarlanırsa, bağlama ayarlandığında çözümlenebilirBindingContext
, ancak o zaman NavigateCommand
hala null
olur. sonra ayarının NavigateCommand
bağlama üzerinde hiçbir etkisi olmaz çünkü bir değişiklik NavigateCommand
bir PropertyChanged
olayı tetiklemez ve bağlama bunun geçerli olduğunu NavigateCommand
bilmez.BindingContext
XAML ayrıştırıcısı bağlama tanımıyla karşılaştığında bağlamanın her iki bileşeni de ayarlandığından, çağrısından InitializeComponent
önce hem hem BindingContext
de NavigateCommand
(herhangi bir sırada) ayarı çalışır.
Veri bağlamaları bazen karmaşık olabilir, ancak bu makale dizisinde gördüğünüz gibi güçlü ve çok yönlüdür ve temel alınan mantığı kullanıcı arabiriminden ayırarak kodunuzu düzenlemeye büyük ölçüde yardımcı olur.