使用ID区分视图
在TwoButtons程序中,您看到了一种共享事件处理程序的技术,通过比较对象来区分视图。 这在没有很多视图可以区分的情况下工作正常,但对于计算器程序来说这是一个糟糕的做法。
Element类定义了一个String类型的StyleId属性,专门用于识别视图。 它不用于Xamarin.Forms内部的任何东西,所以您可以将其设置为适用于应用程序的任何内容。 您可以使用if和else语句或在开关和大小写块中测试值,也可以使用Parse方法将字符串转换为数字或枚举成员。
以下程序不是计算器,而是一个数字键盘,它当然是计算器的一部分。 该程序被称为SimplestKeypad,并使用StackLayout来组织键的行和列。 (这个程序的目的之一就是要证明StackLayout对于这项工作来说不是很合适的工具!)
该程序总共创建五个StackLayout实例。 mainStack是垂直定向的,并且四个水平的StackLayout对象排列了10个数字按钮。 为了简单起见,键盘按电话顺序排列,而不是按计算器顺序排列:
public class SimplestKeypadPage : ContentPage
{
Label displayLabel;
Button backspaceButton;
public SimplestKeypadPage()
{
// Create a vertical stack for the entire keypad.
StackLayout mainStack = new StackLayout
{
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
// First row is the Label.
displayLabel = new Label
{
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
VerticalOptions = LayoutOptions.Center,
HorizontalTextAlignment = TextAlignment.End
};
mainStack.Children.Add(displayLabel);
// Second row is the backspace Button.
backspaceButton = new Button
{
Text = "\u21E6",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
IsEnabled = false
};
backspaceButton.Clicked += OnBackspaceButtonClicked;
mainStack.Children.Add(backspaceButton);
// Now do the 10 number keys.
StackLayout rowStack = null;
for (int num = 1; num <= 10; num++)
{
if ((num - 1) % 3 == 0)
{
rowStack = new StackLayout
{
Orientation = StackOrientation.Horizontal
};
mainStack.Children.Add(rowStack);
}
Button digitButton = new Button
{
Text = (num % 10).ToString(),
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
StyleId = (num % 10).ToString()
};
digitButton.Clicked += OnDigitButtonClicked;
// For the zero button, expand to fill horizontally.
if (num == 10)
{
digitButton.HorizontalOptions = LayoutOptions.FillAndExpand;
}
rowStack.Children.Add(digitButton);
}
this.Content = mainStack;
}
void OnDigitButtonClicked(object sender, EventArgs args)
{
Button button = (Button)sender;
displayLabel.Text += (string)button.StyleId;
backspaceButton.IsEnabled = true;
}
void OnBackspaceButtonClicked(object sender, EventArgs args)
{
string text = displayLabel.Text;
displayLabel.Text = text.Substring(0, text.Length - 1);
backspaceButton.IsEnabled = displayLabel.Text.Length > 0;
}
}
这10个数字键共享一个Clicked处理程序。 StyleId属性表示与键关联的数字,因此程序可以简单地将该数字附加到由标签显示的字符串。 StyleId恰好与Button的Text属性相同,并且可以使用Text属性来代替,但在一般情况下,事情并不总是那么方便。
Backspace Button在功能上有很大的不同,以保证它自己的Clicked处理程序,尽管将两种方法结合到一起可以充分利用它们可能具有的任何代码。
为了给键盘稍大一点的尺寸,所有文本都使用NamedSize.Large给出一个FontSize。 以下是SimplestKeypad程序的三个效果图:
当然,您需要重复按下按键,直到您看到程序如何响应一串非常大的数字,并且您会发现它没有充分预测到这种情况。 当标签变得太宽时,它开始控制垂直StackLayout的整体宽度,并且按钮也开始移动。
此外,如果按钮包含字母或符号而不是数字,则按钮将错位,因为每个按钮宽度均基于其内容。
你能用HorizontalOptions属性上的Expands标志来解决这个问题吗? 不可以。扩展标志会导致额外的空间在StackLayout中的视图之间平均分配。 每个视图将以相同的数量相加增加,但按钮的宽度始终不同,并且它们将始终具有不同的宽度。 例如,查看TwoButtons或ButtonLambdas程序中的两个按钮。 这些按钮的HorizontalOptions属性设置为Fill?andExpand,但它们宽度不同,因为按钮内容的宽度不同。
这些程序的一个更好的解决方案是第17章中提到的称为网格的布局。