上下文菜單
單元格可以定義以特定于平台的方式調用的上下文菜單。 這樣的上下文菜單通常允許使用者對ListView中的特定項執行操作。 例如,當與顯示學生的ListView一起使用時,這樣的上下文菜單允許使用者對特定學生執行動作。
CellContextMenu程式示範了這種技術。 它定義了一個包含四個項的上下文菜單:
- 重置GPA(将學生的平均成績設定為2.5)
- 移至頂部(将學生移至清單頂部)
- 移動到底部(類似地将學生移到底部)
- 删除(從清單中删除學生)
在iOS上,通過向左滑動項目來調用上下文菜單。 在Android和Windows 10 Mobile上,您将手指按到該項目并按住它直到出現菜單。 這是結果:

iOS螢幕上隻顯示一個菜單項,這是從清單中删除學生的項目。 必須為iOS特别标記從ListView中删除條目的菜單項。 Android螢幕列出了螢幕頂部的前兩個菜單項。 隻有Windows運作時才會列出它們。
要檢視其他菜單項,請點選iOS上的“更多”按鈕和Android上的垂直省略号。 其他項目顯示在iOS螢幕底部的清單中以及Android螢幕右上角的下拉清單中:
點選其中一個菜單項執行該操作。
要為單元格建立上下文菜單,可以将MenuItem類型的對象添加到Cell類定義的ContextActions集合中。 你已經遇到過MenuItem。 它是第13章“位圖”中描述的ToolbarItem類的基類。
MenuItem定義了五個屬性:
- 字元串類型的文本
- FileImageSource類型的圖示,用于從平台項目通路位圖
- IsDestructive類型為bool
- 類型為ICommand的指令
- 類型為object的CommandParameter
此外,MenuItem定義了Clicked事件。 您可以在Clicked處理程式中處理菜單操作,或者如果菜單操作是在ViewModel-ICommand對象中實作的話。
以下是在CellContextMenu程式中初始化ContextActions集合的方法:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:school="clr-namespace:SchoolOfFineArt;assembly=SchoolOfFineArt"
x:Class="CellContextMenu.CellContextMenuPage">
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness"
iOS="0, 20, 0, 0" />
</ContentPage.Padding>
<ContentPage.BindingContext>
<school:SchoolViewModel />
</ContentPage.BindingContext>
<StackLayout BindingContext="{Binding StudentBody}">
<Label Text="{Binding School}"
FontSize="Large"
FontAttributes="Bold"
HorizontalTextAlignment="Center" />
<ListView ItemsSource="{Binding Students}">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell ImageSource="{Binding PhotoFilename}"
Text="{Binding FullName}"
Detail="{Binding GradePointAverage,
StringFormat='G.P.A. = {0:F2}'}">
<ImageCell.ContextActions>
<MenuItem Text="Reset GPA"
Command="{Binding ResetGpaCommand}" />
<MenuItem Text="Move to top"
Command="{Binding MoveToTopCommand}" />
<MenuItem Text="Move to bottom"
Command="{Binding MoveToBottomCommand}" />
<MenuItem Text="Remove"
IsDestructive="True"
Command="{Binding RemoveCommand}" />
</ImageCell.ContextActions>
</ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
請注意,“删除”項的IsDestructive屬性設定為True。 這是導緻項目在iOS螢幕上以紅色顯示的屬性,按照慣例,該屬性會從集合中删除該項目。
MenuItem定義了一個Icon屬性,您可以将其設定為存儲在平台項目中的位圖(非常類似于ToolbarItem使用的圖示),但它僅适用于Android,并且位圖替換了Text描述。
所有四個MenuItem對象的Command屬性都綁定到Student類中的屬性。
Student對象是單元格的綁定上下文,是以它也是這些MenuItem對象的綁定上下文。 以下是在Student中定義和初始化屬性的方法:
public class Student : ViewModelBase
{
__
public Student()
{
ResetGpaCommand = new Command(() => GradePointAverage = 2.5);
MoveToTopCommand = new Command(() => StudentBody.MoveStudentToTop(this));
MoveToBottomCommand = new Command(() => StudentBody.MoveStudentToBottom(this));
RemoveCommand = new Command(() => StudentBody.RemoveStudent(this));
}
__
// Properties for implementing commands.
[XmlIgnore]
public ICommand ResetGpaCommand { private set; get; }
[XmlIgnore]
public ICommand MoveToTopCommand { private set; get; }
[XmlIgnore]
public ICommand MoveToBottomCommand { private set; get; }
[XmlIgnore]
public ICommand RemoveCommand { private set; get; }
[XmlIgnore]
public StudentBody StudentBody { set; get; }
}
隻有ResetGpaCommand可以在Student類中完全處理。 其他三個指令需要通路StudentBody類中的學生集合。 是以,當首次加載資料時,SchoolViewModel将每個Student對象中的StudentBody屬性設定為帶有學生集合的StudentBody對象。 這允許通過調用StudentBody中的以下方法來實作Move和Remove指令:
public class StudentBody : ViewModelBase
{
__
public void MoveStudentToTop(Student student)
{
Students.Move(Students.IndexOf(student), 0);
}
public void MoveStudentToBottom(Student student)
{
Students.Move(Students.IndexOf(student), Students.Count - 1);
}
public void RemoveStudent(Student student)
{
Students.Remove(student);
}
}
由于Students集合是ObservableCollection,是以ListView重繪自身以反映學生的新數字或新順序。