简体   繁体   中英

How to show and hide a Text Block in Universal Windows Apps 8.1

In a Windows Universal Apps 8.1 platform targeting Windows Store 8.1 and Windows Phone 8.1 I need to hide a Text Block that says "The list is empty" when a collection bound to a ListView has some items in it and I need to show this Text Block whenever the collection is empty.

Please suggest a solution for this.

So far I've tried this but it doesn't work when there are items in the collection the element TasksEmptyMsg still shows that "The list is empty".

<Page
    x:Class="ToDoer.Pages.Task"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ToDoer.Pages"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <ListView x:Name="Tasks"
                  ItemsSource="{Binding Tasks}"
                  SelectedItem="{Binding SelectedTask,Mode=TwoWay}"
                  ItemTemplate="{StaticResource TasksItemTemplate}"
                  Padding="24,24">
            <interactivity:Interaction.Behaviors>
                <core:EventTriggerBehavior EventName="SelectionChanged">
                    <core:InvokeCommandAction Command="{Binding TaskSelectionChanged}"/>
                </core:EventTriggerBehavior>
            </interactivity:Interaction.Behaviors>
        </ListView>

        <TextBlock x:Name="TasksEmptyMsg"
                   Text="The list is empty"
                   HorizontalAlignment="Center"
                   VerticalAlignment="Center"
                   Visibility="Collapsed"
                   Style="{StaticResource GroupHeaderTextBlockStyle}">
            <interactivity:Interaction.Behaviors>
                <core:DataTriggerBehavior Binding="{Binding ElementName=Tasks,Path=Items.Count}" 
                                          Value="0">
                    <core:ChangePropertyAction TargetObject="{Binding ElementName=TasksEmptyMsg}" 
                                               PropertyName="Visibility" 
                                               Value="Visible"/>
                </core:DataTriggerBehavior>
            </interactivity:Interaction.Behaviors>
        </TextBlock>
        <!--Uncomment to see an alignment grid to help ensure your controls are
            aligned on common boundaries.  The image has a top margin of -32px to
            account for the System Tray. Set this to 0 (or remove the margin altogether)
            if the System Tray is hidden.

            Before shipping remove this XAML and the image itself.-->
        <!--<Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0" IsHitTestVisible="False" />-->
    </Grid>

    <Page.BottomAppBar>
        <CommandBar>
            <AppBarButton Icon="Add"
                          Label="add todo"
                          Command="{Binding AddTask}"/>
        </CommandBar>
    </Page.BottomAppBar>
</Page>

Works fine when there are no items in the collection.

在此处输入图片说明

Issue: Shows "The list is empty" even when it is not.

在此处输入图片说明

The ListView itself doesn't have any property informing that it's empty, nor binding to Items.Count help here, as the property change is not raise. Thankfully it's not hard to implement such mechanism and there are couple of ways to do it. Here is a one that uses Converters :

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.Resources>
        <local:BoolToVisibility x:Key="BoolToVisibility"/>
    </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="300"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

    <ListView x:Name="TheList" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Tasks}" Visibility="{Binding IsTasksEmpty, Converter={StaticResource BoolToVisibility}, ConverterParameter='INVERT'}"/>
    <TextBlock x:Name="EmptyText" Grid.Column="0" Text="List is empty" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding IsTasksEmpty, Converter={StaticResource BoolToVisibility}}"/>
        <StackPanel Grid.Column="1">
            <Button Content="Add item" Click="AddButton_Click" Margin="20"/>
            <Button Content="Delete item" Click="DelButton_Click" Margin="20"/>
        </StackPanel>
</Grid>

and code behind:

public class BoolToVisibility : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language) => (bool)value != ((string)parameter == "INVERT") ? Visibility.Visible : Visibility.Collapsed;
    public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); }
}

public sealed partial class MainPage : Page, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    public ObservableCollection<string> Tasks { get; set; } = new ObservableCollection<string>() { "Starting item" };
    public bool IsTasksEmpty => Tasks.Count < 1;

    public MainPage()
    {
        this.InitializeComponent();
        this.DataContext = this;
        Tasks.CollectionChanged += (sender, e) => RaiseProperty(nameof(IsTasksEmpty));
    }

    private void AddButton_Click(object sender, RoutedEventArgs e) => Tasks.Add("Next item");
    private void DelButton_Click(object sender, RoutedEventArgs e) => Tasks.RemoveAt(Tasks.Count - 1);
}

Here is a one for UWP that uses VisualStates and collection changed event (taking a look at your code I assume that you are using ObservableCollection for Tasks ). XAML code:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="ListStates">
            <VisualState x:Name="ListWithItems"/>
            <VisualState x:Name="ListEmpty">
                <VisualState.Setters>
                    <Setter Target="EmptyText.Visibility" Value="Visible"/>
                    <Setter Target="TheList.Visibility" Value="Collapsed"/>
                </VisualState.Setters>
                <VisualState.StateTriggers>
                    <StateTrigger IsActive="{Binding IsTasksEmpty}"/>
                </VisualState.StateTriggers>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="300"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <ListView x:Name="TheList" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding Tasks}"/>
    <TextBlock x:Name="EmptyText" Grid.Column="0" Text="List is empty" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed"/>
    <StackPanel Grid.Column="1">
        <Button Content="Add item" Click="AddButton_Click" Margin="20"/>
        <Button Content="Delete item" Click="DelButton_Click" Margin="20"/>
    </StackPanel>
</Grid>

the code behind is the same as above in solution with converter.

A working sample for UWP you will find at GitHub .

I tried to solve this in XAML but so far I wasn't able to do it, so I tried another way ie binding the Visibility property of the TextBlock by using a BooleanToVisibilityConverter.

I set up a property called AreTasksEmpty, and property notification is done through the use of MvvmLight library.

/// <summary>
/// The are tasks empty.
/// </summary>
private bool _areTasksEmpty;

/// <summary>
/// Gets or sets the are tasks empty.
/// </summary>
public bool AreTasksEmpty
{
    get
    {
        return this._areTasksEmpty;
    }
    set
    {
        this.Set(ref this._areTasksEmpty, value);
    }
}

In the method that fetches the tasks I had updated the property AreTasksEmpty's value as follows.

if (this.Tasks.Any())
{
    this.AreTasksEmpty = false;
}
else
{
    this.AreTasksEmpty = true;
}

In the XAML, I've done the binding to Visibility property as follows,

<TextBlock x:Name="TasksEmptyMsg"
           Text="The list is empty"
           HorizontalAlignment="Center"
           VerticalAlignment="Center"
           Visibility="{Binding AreTasksEmpty, Converter={StaticResource BooleanToVisibilityConverter}}"
           Style="{StaticResource GroupHeaderTextBlockStyle}">
</TextBlock>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM