如何解决Xamarin.Forms XAML Label IsVisible条件未按预期进行评估
在我的项目中,我必须选择页面上的几个选项。
每个选项的类型均为MyCustomType
,并声明了公共字符串Name
属性。
每个选项都通过标签显示。当我单击标签时,我会显示选项列表并选择它。
选择了一个选项后,带有该选项的占位符文本(如select an item
)的空标签应显示在带有刚刚选择的选项的标签下方。
我为每个选项使用单独的标签,而不是ListView元素(客户对特定外观的要求)。
选项数量有限,可以说等于四个。
在我的viewmodel中,我声明了list属性(它已在viewmodel构造函数中初始化):
public List<MyCustomType> AllOptions { get; }
在我的XAML页面中,标签声明为:
<Label Text="{Binding AllOptions[0].Name}" >
<Label Text="{Binding AllOptions[1].Name}" IsVisible="{Binding AllOptions[0],Converter={StaticResource NullToFalseBoolConverter}}">
<Label Text="{Binding AllOptions[2].Name}" IsVisible="{Binding AllOptions[1],Converter={StaticResource NullToFalseBoolConverter}}">
<Label Text="{Binding AllOptions[3].Name}" IsVisible="{Binding AllOptions[2],Converter={StaticResource NullToFalseBoolConverter}}">
转换器NullToFalseBoolConverter
如下所示:
public class NullToFalseBoolConverter : IValueConverter
{
public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
{
return value != null;
}
public object ConvertBack(object value,CultureInfo culture)
{
throw new NotImplementedException();
}
}
问题在于标签声明中指定的IsVisible条件不起作用。
显示所有标签。
断点设置为Convert
的{{1}}方法的第一行。
我不明白为什么会这样。
有什么想法吗?
解决方法
这很有趣,但是以下方法解决了我的问题。
我已经将AllOptions
声明为List
(没有用)和ObservableCollection
(也没有用)。
我应该将列表声明为数组:
public MyCustomType[] AllOptions { get; }
我的标签开始正确显示,一个接一个地设置。
处理完它的值后,如果我得到空值,则意味着我们已经到了填充选项的末尾。
,与其尝试绑定,不如考虑使用既支持ItemSource又支持数据模板的布局类型。所以这就像一个ListView / CollectionView / Stacklayout
例如,如果您决定使用StackLayout例如:
<StackLayout
...
BindableLayout.ItemsSource="{Binding AllOptions}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Text="{Binding Name}" IsVisible="{Binding .,Converter={StaticResource NullToFalseBoolConverter}}">
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
此方法的优点在于,由于所有标签都遵循相同的方法,因此您现在不仅可以A)编写更简洁的代码,而且B)利用MVVM模式。现在,这当然意味着每个控件都将转换器应用到它们上。但是,如果仍然不想在第一个元素中包含它,那么我们要做的就是更改您的类型以包含index属性。如果您想知道Binding .
的语法含义,那意味着我们只是为该元素绑定了该集合的整个对象。
public int Index {get; set;}
在构建该数组的位置进行设置,然后在转换器中要做的就是:
public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
{
var element = (MyCustomType) value;
if(element.Index != 0)
return value != null;
else
return true;
}
编辑
因此,除了将所选项目传递到命令之外,您还可以执行以下操作。我假设您的总体页面是,但是同一概念实际上适用于任何类型的页面。
-
在上设置
x:Name
属性,为其提供所需的任何名称。例如: -
在标签上定义
<GestureRecognizer>
<Label Text="{Binding Name}" IsVisible="{Binding .,Converter={StaticResource NullToFalseBoolConverter}}"> <Label.GestureRecognizers> <TapGestureRecognizer Command="{Binding BindingContext.YourCommandName,Source={x:Reference root}}" CommandParameter="{Binding .}"/> </Label.GestureRecognizers>
-
在绑定到页面的视图模型中,如下创建以下命令:
公共ICommand YourCommandName => new Command(x => YourCustomMethodHere(x));
-
最后创建处理您选择的对象的方法
public void YourCustomMethodHere(MyCustomType type){}
因此,上面的XAML代码所做的是,我们将Label的命令绑定到整个父视图模型,当某项位于其ItemSource定义的DataTemplate内时,其视图模型实际上就是该模型正在使用的数据模板;这就是为什么我们将其源VM设置为整体父级的原因。 CommandParameter="{Binding .}"
与以前的逻辑相同,我们将绑定整个数据模板项,在这种情况下,就是为该元素呈现的MyCustomType
。这样,每次点击标签时,我们会将标签及其数据传递给我们现在在VM中定义的命令。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。