第十五章:交互式界面(三)

简介:

常见的陷阱
假设您希望Slider值的范围是1到100.您可以设置最小值和最大值,如下所示:

<Slider ValueChanged="OnSliderValueChanged"
        Minimum="1"
        Maximum="100"
        VerticalOptions="CenterAndExpand" />

但是,当您运行该程序的新版本时,会引发ArgumentException,并带有文本说明“Value是Minimum的无效值。”这是什么意思?
当XAML解析器遇到Slider标记时,将实例化Slider,然后按照它们在Slider标记中出现的顺序设置属性和事件。但是,当Minimum属性设置为1时,最大值现在等于最小值。那不可能。 Maximum属性必须大于Minimum。 Slider通过引发异常来表明这个问题。
在Slider类的内部,在回调方法集中将Minimum和Maximum值与用于创建Minimum和Maximum可绑定属性的BindableProperty.Create方法调用的validateValue参数进行比较。如果Minimum小于Maximum,则validateValue回调返回true,表示值有效。此回调触发的返回值为false表示异常。这是可绑定属性实现有效性检查的标准方法。
这不是XAML特有的问题。如果您在代码中按此顺序实例化和初始化Slider属性,也会发生这种情况。解决方案是颠倒设置最小值和最大值的顺序。首先将Maximum属性设置为100.这是合法的,因为现在范围介于0和100之间。然后将Minimum属性设置为1:

<Slider ValueChanged="OnSliderValueChanged"
        Maximum="100"
        Minimum="1"
        VerticalOptions="CenterAndExpand" />

但是,这会导致另一个运行时错误。 现在,它是ValueChanged处理程序中的NullReferenceException。 这是为什么?
Slider的Value属性必须在Minimum和Maximum值的范围内,因此当Minimum属性设置为1时,Slider会自动将其Value属性调整为1。
在内部,Value在一个回调方法中调整,该方法设置为BindableProperty.Create方法的coerceValue参数,该方法调用Minimum,Maximum和Value属性。 回调方法返回经受此强制后设置的属性的调整值。 在此示例中,当Minimum设置为1时,coerceValue方法将滑块的Value属性设置为1,而coerceValue回调则返回新值Minimum,其值保持为1。
但是,由于强制,Value属性已更改,这会导致ValueChanged事件触发。 代码隐藏文件中的ValueChanged处理程序尝试设置Label的Text属性,但XAML解析器尚未实例化Label元素。 标签字段为空。
这个问题有几个解决方案。 最安全和最通用的解决方案是在事件处理程序中检查标签权限的空值:

void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
{
    if (label != null)
    {
        label.Text = String.Format("Slider = {0}", args.NewValue);
    }
}

但是,您还可以通过将TagC中的ValueChanged事件的赋值移动到已设置Maximum和Minimum属性之后来解决此问题:

<Slider Maximum="100"
        Minimum="1"
        ValueChanged="OnSliderValueChanged"
        VerticalOptions="CenterAndExpand" />

在设置了Minimum属性后,Value属性仍然被强制为1,但尚未分配ValueChanged事件处理程序,因此不会触发任何事件。
假设Slider的默认范围是0到1.您可能希望Label在程序首次启动时显示Slider的初始值。 您可以在XAML文件中将Label的Text属性初始化为“Slider = 0”,但如果您想将文本更改为稍微不同的文本,则需要在两个位置更改它。
您可以尝试在XAML文件中为Slider指定一个滑块名称,然后将一些代码添加到构造函数中:

public SliderDemoPage()
{
    InitializeComponent();
    slider.Value = 0;
}

当InitializeComponent返回时,XAML文件中的所有元素都已创建并初始化,因此如果此代码导致Slider触发ValueChanged事件,那应该不是问题。
但它不会起作用。 Slider的值已经为0,因此再次将其设置为0不会执行任何操作。 你可以试试这个:

public SliderDemoPage()
{
    InitializeComponent();
    slider.Value = 1;
    slider.Value = 0;
}

那可行。 但是您可能希望在代码中添加注释,以便其他程序员以后不会删除将Value设置为1的语句,因为它似乎是不必要的。
或者您可以通过直接调用处理程序来模拟事件。 ValueChangedEventArgs构造函数的两个参数是旧值和新值(按此顺序),但OnSliderValueChanged处理程序仅使用NewValue属性,因此其他参数是什么或它们是否相等无关紧要:

public partial class SliderDemoPage : ContentPage
{
    public SliderDemoPage()
    {
        InitializeComponent();
        OnSliderValueChanged(null, new ValueChangedEventArgs(0, 0));
    }
    void OnSliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        label.Text = String.Format("Slider = {0}", args.NewValue);
    }
}

这也有效。 但是请记住将参数设置为对OnSliderValueChanged的调用,以便它们与处理程序所期望的一致。 如果使用将sender参数强制转换为Slider对象的代码替换处理程序主体,则需要在OnSliderValueChanged调用中使用有效的第一个参数。
当您使用数据绑定将Label与Slider连接时,涉及事件处理程序的问题就会消失,您将在下一章中了解到这些问题。 您仍然需要以正确的顺序设置Slider的属性,但是您将不会遇到事件处理程序的任何问题,因为事件处理程序将消失。

目录
相关文章
|
JavaScript Android开发 Windows
|
JavaScript Android开发 iOS开发
|
JavaScript Android开发 索引
|
JavaScript Android开发
|
JavaScript Android开发 iOS开发