Как установить значение по умолчанию false при использовании конвертера с формами Xamarin видимости метки

#xaml #xamarin #xamarin.forms #converters

Вопрос:

Я использую конвертер со Label IsVisible свойством.

 <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>
 

Комментарии:

1. Привет, я пробовал, оба решения не работают..

Ответ №2:

Если вы используете представление коллекции , вы можете использовать представление EmptyView, оно будет отображать все, что вы поместили в этот XAML, когда коллекция пуста.

Или вы можете реализовать bindablelayout, который также реализует emptyViewTemplate.

Или вам придется создать другую привязку или другой конвертер.

Что-то вроде public bool MyBinding{get=> myList!=null | myList.Count != | isLoadingFlag } . Но вам придется вызвать событие propertychanged, если вы измените свою коллекцию

Комментарии:

1. Не используйте collectionview..

2. Когда ваше приложение запускается, обычно коллекция будет пустой. Вот почему вы видите этикетку на долю секунды. Чтобы предотвратить это, вам придется загрузить коллекцию раньше. Или вы можете использовать привязку к свойству bool, которое возвращает значение true, если коллекция пуста и данные не загружаются

3.Что-то вроде public bool MyBinding{get=> myList!=null | myList.Count != | isLoadingFlag } . Но вам придется вызвать событие propertychanged, если вы измените свою коллекцию

Ответ №3:

Я не уверен, что это может быть вашей проблемой, но я бы проверил пару вещей:

  1. Вы можете установить привязку не в XAML, а в коде после загрузки данных.
  2. Возможно , вам потребуется установить значение BindingContext products , если это еще не сделано.
  3. Кроме того, возможно, будет лучше, если вы установите путь привязки метки в Count свойство вашей коллекции.
  4. Наконец, установите IsVisible значение false (по умолчанию) в XAML. Этот жесткий код будет переопределен привязкой, которая устанавливается при загрузке данных.

Как бы то ни было, я разработал минимальный полный рабочий образец, который выполняет эту работу.

Он работает следующим образом: приложение запускается и ничего не отображает… затем переходит к загрузке данных. Когда данные загружены, появляется метка, показывающая количество элементов в коллекции. На панели инструментов также доступны две кнопки: Добавить элемент и Удалить элемент. Если вы удалите все элементы, No data found появится надпись.

Смотрите комментарии в коде

Страница 1.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();
        }
    }

}
 

Страница 1.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:

Рассмотрите возможность использования резервных копий привязки, которые позволяют указывать значения «по умолчанию», когда либо контекст привязки не задан, либо цель привязки равна нулю.

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

Возможно, вам не понадобится и то, и другое, но это гарантирует, что метка всегда будет скрыта до тех пор, пока контекст привязки (ViewModel) не будет разрешен, а цель привязки ( products ) не будет равна нулю, чтобы преобразователь мог правильно оценить, следует ли показывать метку.