【问题标题】:Xamarin.Forms. XAML Label IsVisible condition is not getting evaluated as expectedXamarin.Forms。 XAML 标签 IsVisible 条件未按预期进行评估
【发布时间】:2020-12-17 06:16:53
【问题描述】:

在我的项目中,我必须在一个页面上选择多个选项。

每个选项都有一个类型 MyCustomType 并声明了公共字符串 Name 属性。

每个选项都通过标签显示。当我点击标签时,我会显示选项列表并选择它。

选择一个选项后,带有另一个选项的占位符文本(如select an item)的空标签应显示在刚刚选择选项的标签下方。

我为每个选项使用单独的标签,而不是 ListView 元素(客户对特定外观的要求)。

选项的数量是有限的,假设它等于四个。

在我的视图模型中,我声明了列表属性(它已在视图模型构造函数中初始化):

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, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

问题是在标签声明中指定的 IsVisible 条件不起作用。

显示所有标签。

并且断点,设置为NullToFalseBoolConverterConvert方法的第一行没有到达。

我不明白为什么会这样。

有什么想法吗?

【问题讨论】:

  • 你试过用 ObservableCollection 代替 List 吗?而你的“MyCustomType”实现了 INotifyPropertyChanged?
  • 您在调试期间是否在输出窗口中看到任何绑定错误?有时它们很难被注意到。
  • @BradleyUffner 我已将所有文本输出复制到记事本并按exceptionerror 字词搜索。没有发生错误或异常。
  • @JorgeFernandezHerrero 是的,我也尝试过 ObservableCollection。 MyCustomType 是纯数据模型类型。它只保存字符串值,并且这个值在运行时不会改变。在这种情况下,我为什么要为MyCustomType 实现 INotifyPropertyChanged?
  • @JorgeFernandezHerrero 我找到了解决方案,如果您有兴趣,请查看。

标签: c# xaml xamarin xamarin.forms


【解决方案1】:

与其尝试绑定,不如考虑使用既支持 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 模式。现在,当然这确实意味着每个控件也会将转换器应用于它们;但是,如果仍然不想在第一个元素中包含它,那么我们所要做的就是更改您的类型以包含索引属性。如果您想知道 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;
}

编辑

因此,除了将所选项目传递给您的命令方面您想要做的事情之外,您还可以执行以下操作。我假设您的整个页面是 a ,但同样的概念确实适用于任何类型的页面。

  1. 在 上设置一个x:Name 属性,给它起任何你想要的名字。例如:

  2. 在标签上定义&lt;GestureRecognizer&gt;

&lt;Label Text="{Binding Name}" IsVisible="{Binding ., Converter={StaticResource NullToFalseBoolConverter}}"&gt; &lt;Label.GestureRecognizers&gt; &lt;TapGestureRecognizer Command="{Binding BindingContext.YourCommandName, Source={x:Reference root}}" CommandParameter="{Binding .}"/&gt; &lt;/Label.GestureRecognizers&gt;

  1. 在绑定到页面的视图模型中,按如下方式创建以下命令:

    public ICommand YourCommandName => new Command(x => YourCustomMethodHere(x));

  2. 最后创建处理你选择的对象的方法

    public void YourCustomMethodHere(MyCustomType type) {}

所以上面的 XAML 代码所做的就是我们将 Label 的命令绑定到整个父视图模型,当一个项目在其 ItemSource 定义的 DataTemplate 内部时,它的视图模型实际上是模型正在使用的数据模板;这就是为什么我们将其源虚拟机设置为整个父虚拟机的原因。 CommandParameter="{Binding .}" 与之前的逻辑相同,我们正在绑定整个数据模板项,在这种情况下,MyCustomType 已为该元素呈现。这样,每次点击该标签时,我们都会将该标签及其数据传递给我们现在在 VM 中定义的命令。

【讨论】:

  • 感谢您提供如此详细的回答。我稍后会检查这种方法,如果它有效,我会接受你的回答作为解决方案。再次感谢您。
  • 我的实际任务比我在问题上想象的要复杂,有条件显示第一项,而不是基于索引。在单击标签时,我正在调用命令,并将标签索引传递给该命令,以将所选值放入相关标签。无论如何,我将接受您的回答作为我提出的特定问题的解决方案。我喜欢。谢谢。
  • @Rafael 我已经对我的答案进行了编辑,可以帮助满足您的需求,希望我正确理解了您的情况。
【解决方案2】:

这很有趣,但以下方法解决了我的问题。

我将AllOptions 声明为List(不起作用)和ObservableCollection(也不起作用)。

我应该将我的列表声明为 array

public MyCustomType[] AllOptions { get; }

我的标签开始正常显示,一个接一个地设置。

在处理它的值时,如果我得到空值,这意味着我们已经到达填充选项的末尾。

【讨论】:

  • 奇怪的是,由于您正在尝试访问它们,因此查看索引是数组工作的原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-11-25
  • 2014-04-15
  • 1970-01-01
  • 1970-01-01
  • 2022-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多