将转换器与 Label 的可见性 Xamarin 表单一起使用时如何将默认值设置为 false

Posted

技术标签:

【中文标题】将转换器与 Label 的可见性 Xamarin 表单一起使用时如何将默认值设置为 false【英文标题】:How to set default value to false when using converter with Label's visibility Xamarin forms 【发布时间】:2021-11-14 23:26:46 【问题描述】:

我正在使用带有LabelIsVisible 属性的转换器。

<Label IsVisible="Binding products, Converter=StaticResource EmptyCollectionToBoolConverter" Text="No data found">  

如果products 为空EmptyCollectionToBoolConverter 返回true 否则false。首次加载屏幕时,“未找到数据”消息显示几秒钟,然后数据正在加载。

我想修复它,只有当products 为空时才需要显示标签。我该怎么做?

【问题讨论】:

【参考方案1】:

您可以在后面的代码中覆盖IsVisible 值。

<Label x:Name="MyLabel" IsVisible="Binding products, Converter=StaticResource EmptyCollectionToBoolConverter" Text="No data found">

后面的代码

// probably ctor
MyLabel.IsVisible = false;

第二个选项可以是使用DataTrigger

<Label Text="No data found" IsVisible="false">
    <Label.Triggers>
        <DataTrigger TargetType="Label" Binding="Binding products, Converter=StaticResource EmptyCollectionToBoolConverter" Value="True">
            <Setter Property="IsVisible" Value="True" />
        </DataTrigger>
    </Label.Triggers>
</Label>

【讨论】:

嗨,我试过了,两种解决方案都不起作用..【参考方案2】:

如果您使用的是 CollectionView,则可以使用 EmptyView ,当集合为空时,它将显示您在该 XAML 中放入的任何内容。

或者你可以实现bindablelayout,它也实现了emptyViewTemplate。

否则您将不得不创建另一个绑定或另一个转换器。

类似 public bool MyBindingget=&gt; myList!=null | myList.Count != | isLoadingFlag 的东西。但是如果你修改你的集合,你将不得不调用 propertychanged 事件

【讨论】:

不使用collectionview.. 当您的应用程序启动时,通常集合将为空。这就是为什么您会在几分之一秒内显示标签。为了防止这种情况,您必须先加载集合。或者,您可以使用绑定到 bool 属性,如果集合为空且未加载数据,则该属性返回 true 类似 public bool MyBindingget=&gt; myList!=null | myList.Count != | isLoadingFlag 的东西。但是如果你修改你的集合,你将不得不调用 propertychanged 事件【参考方案3】:

我不确定这是否是您的问题,但我会检查几件事:

    您可以不在 XAML 中设置绑定,而是在加载数据后的代码中设置。 您可能需要将 BindingContext 设置为 products(如果尚未这样做的话)。 另外,最好将标签的绑定路径设置为集合的Count 属性。 最后,在 XAML 中将 IsVisible 设置为 false(默认)。此硬代码将被加载数据时设置的绑定覆盖。

无论如何,我制定了一个完成这项工作的最小完整工作示例。

它的基本工作方式如下:应用程序启动并没有显示任何内容......然后继续加载数据。加载数据时出现标签,显示集合中的项目数。 工具栏中还有两个按钮:添加项目删除项目。如果您删除所有项目,则会出现No data found 标签。

查看代码中的 cmets

Page1.xaml.cs

using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace scrollviewPrompt

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Page1 : ContentPage
    
        // products is an observable collection so that 
        // it notifies when it changes.
        public ObservableCollection<string> products  get; set; 

        public Page1()
        
            InitializeComponent();
        

        protected override async void OnAppearing()
        
            // Initialize your products collection
            products = new ObservableCollection<string>();

            // Set binding context of the whole Page1 
            // to your products collection
            BindingContext = products;

            // Load data asynchronously.
            // At this point the data is already bound to 
            // our collection, so when data is loaded 
            // "No data found" label will dissapear.
            await LoadDataAsync();

            base.OnAppearing();

        


        private async Task LoadDataAsync()
        

            await Task.Delay(4000);

            products.Add("Toks");

            noDataLabel.SetBinding(Label.IsVisibleProperty, new Binding()
            
                Path="Count",
                Converter = new EmptyCollectionToBoolConverter()
            );

        


        // Add items to collection.
        private void AddClicked(object sender, EventArgs e)
        
            products.Add("locs");
        

        // If collection not empty, remove first item.
        private void RemoveClicked(object sender, EventArgs e)
        
            if (products.Count>0)
                products.RemoveAt(0);
        
    

    public class EmptyCollectionToBoolConverter : IValueConverter
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        
            var count = (int)value;

            return count==0;

        

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        
            throw new NotImplementedException();
        
    


    public class Not_EmptyCollectionToBoolConverter : IValueConverter
    
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        
            var count = (int)value;

            return count > 0;

        

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        
            throw new NotImplementedException();
        
    


Page1.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:scrollviewPrompt"
             x:Class="scrollviewPrompt.Page1">
    
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:EmptyCollectionToBoolConverter x:Key="EmptyCollectionToBoolConverter"/>
            <local:Not_EmptyCollectionToBoolConverter x:Key="Not_EmptyCollectionToBoolConverter"/>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="Add Item"
                     Clicked="AddClicked"/>
        <ToolbarItem Text="Remove Item"
                     Clicked="RemoveClicked"/>
    </ContentPage.ToolbarItems>
    
    <ContentPage.Content>
        
        
        
        <StackLayout>
            <!--No data found is bound to Count property of BindingContext (products). 
                when products change, Count changes and IsVisible is updated.-->
            <Label x:Name="noDataLabel" 
                   Text="No data found"
                   IsVisible="false"
                   VerticalOptions="CenterAndExpand" 
                   HorizontalOptions="CenterAndExpand" />
            <Label Text="Binding Path=Count, StringFormat='0 items'"
                   IsVisible="Binding Path=Count, Converter=StaticResource Not_EmptyCollectionToBoolConverter"
                   VerticalOptions="CenterAndExpand" 
                   HorizontalOptions="CenterAndExpand" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

【讨论】:

【参考方案4】:

考虑使用binding fallbacks,它允许您在未设置绑定上下文或绑定目标为空时指定“默认”值。

<Label IsVisible="Binding products, Converter=StaticResource EmptyCollectionToBoolConverter, FallbackValue='False', TargetNullValue='False'" Text="No data found">  

您可能不需要两者,但它将确保始终隐藏标签,直到可以解析绑定上下文 (ViewModel) 并且绑定目标 (products) 不为空,因此转换器可以正确评估是否显示标签。

【讨论】:

以上是关于将转换器与 Label 的可见性 Xamarin 表单一起使用时如何将默认值设置为 false的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin 表单:如何处理 flowlistview 所选项目的可见性?

Xamarin:Java 绑定项目 - 无法更改本地界面的可见性

使用转换器的DataGridColumn可见性

Xamarin在ListView中使用StackLayout可见性形成跨平台问题

WPF 可见性折叠保留空间

将 XAML 中的可见性绑定到可见性属性