当ListView在UWP中不包含带有MVVM的项目时显示消息 [英] Display message when ListView contains no items with MVVM in a UWP

查看:44
本文介绍了当ListView在UWP中不包含带有MVVM的项目时显示消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的第一个MVVM项目,我需要编写一些代码以在视图中操纵控件,但看起来似乎比必须的要复杂得多.

This is my first MVVM project and the code I need to write to manipulate controls in the view somehow seems way too complicated than it has to be.

我发现很难完全理解MVVM并决定何时可以在代码中添加内容.

I'm finding it hard to fully understand MVVM and to decide when I can put stuff in code behind.

基本上我的问题是我想显示一条消息,告诉用户当绑定到的ObservableCollection不包含任何项时,listview为空.想法是在视图中有一个TextBlock,并且在没有要显示的项目时(用户创建项目之前和删除所有项目之后),仅将其可见性属性设置为 Visible .

Basically my problem is that I want to show a message telling the user that the listview is empty when the ObservableCollection it is bound to contains no items. The idea was to have a TextBlock in the view and only have its visibility property set to Visible when there are no items to display (Before user creates an item and after he deletes all items)

我不能使用此解决方案,因为UWP不支持BooleanToVisibilityConverter:使用BooleanToVisibilityConverter的WPF MVVM隐藏按钮

I cannot use this solution as UWP don't support BooleanToVisibilityConverter: WPF MVVM hiding button using BooleanToVisibilityConverter

查看:

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:EventMaker3000.View"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:ViewModel="using:EventMaker3000.ViewModel"
    xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:Core="using:Microsoft.Xaml.Interactions.Core"
    x:Class="EventMaker3000.View.EventPage"
    mc:Ignorable="d">
    <Page.BottomAppBar>
        <CommandBar>
            <CommandBar.Content>
                <Grid/>
            </CommandBar.Content>
            <AppBarButton Icon="Delete" Label="Delete" IsEnabled="{Binding DeletebuttonEnableOrNot}">
                <Interactivity:Interaction.Behaviors>
                    <Core:EventTriggerBehavior EventName="Click">
                        <Core:NavigateToPageAction/>
                        <Core:InvokeCommandAction Command="{Binding DeleteEventCommand}"/>
                    </Core:EventTriggerBehavior>
                </Interactivity:Interaction.Behaviors>
            </AppBarButton>
            <AppBarButton Icon="Add" Label="Add">
                <Interactivity:Interaction.Behaviors>
                    <Core:EventTriggerBehavior EventName="Click">
                        <Core:NavigateToPageAction TargetPage="EventMaker3000.View.CreateEventPage"/>
                    </Core:EventTriggerBehavior>
                </Interactivity:Interaction.Behaviors>
            </AppBarButton>
        </CommandBar>
    </Page.BottomAppBar>

    <Page.DataContext>
        <ViewModel:EventViewModel/>
    </Page.DataContext>

    <Grid Background="WhiteSmoke">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <!--Header-->
        <TextBlock 
            Text="Events" 
            Foreground="Black" 
            Margin="0,20,0,0" 
            Style="{ThemeResource HeaderTextBlockStyle}" 
            HorizontalAlignment="center" 
            VerticalAlignment="Center"/>

        <ListView
            ItemsSource="{Binding EventCatalogSingleton.Events, Mode=TwoWay}"
            SelectedItem="{Binding SelectedEvent, Mode=TwoWay}"
            Grid.Row="1"    
            Background="WhiteSmoke"
            Padding="0,30,0,0">
            <Interactivity:Interaction.Behaviors>
                <Core:EventTriggerBehavior EventName="SelectionChanged">
                    <Core:InvokeCommandAction Command="{Binding EnableOrNotCommand}"/>
                </Core:EventTriggerBehavior>
            </Interactivity:Interaction.Behaviors>

            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid VerticalAlignment="Center" Margin="5,0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>

                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>

                        <TextBlock Grid.Column="0"
                            Grid.Row="0"
                            Margin="5" 
                            Text="{Binding Name, Mode=TwoWay}" 
                            Style="{ThemeResource TitleTextBlockStyle}" Foreground="Black"/>
                        <TextBlock Grid.Column="1"
                            Grid.Row="1"
                            Margin="5" 
                            Text="{Binding Place, Mode=TwoWay}"
                            HorizontalAlignment="Right"
                            Style="{ThemeResource CaptionTextBlockStyle}" Foreground="Black"/>
                        <TextBlock Grid.Column="0"
                            Grid.Row="2"
                            Margin="5" 
                            Text="{Binding Description, Mode=TwoWay}"
                            Style="{ThemeResource BodyTextBlockStyle}" Foreground="Black"/>

                        <TextBlock Grid.Column="0"
                            Grid.Row="1" 
                            Margin="5" 
                            Text="{Binding DateTime, Mode=TwoWay}" 
                            Style="{ThemeResource CaptionTextBlockStyle}" Foreground="Black"/>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>

            <!--Sets each listview item to stretch-->
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
                </Style>
            </ListView.ItemContainerStyle>
        </ListView>

        <!-- TextBlock for empty list view-->

        <TextBlock 
            Grid.Row="1"
            Margin="5,5,5,5"  
            VerticalAlignment="Center"  
            HorizontalAlignment="Center"  
            Text="You have no events"  
            Style="{StaticResource BaseTextBlockStyle}"  
            Visibility="{Binding TextBlockVisibility}"/>
    </Grid>
</Page>

ViewModel:

公共类EventViewModel:INotifyPropertyChanged{

public class EventViewModel : INotifyPropertyChanged {

private bool _deleteButtonEnableOrNot = false;
private ICommand _enableOrNotCommand;

//TextBlock
private string _textBlockVisibility = "Visible";
private ICommand _textBlockVisibilityCommand;


public EventCatalogSingleton EventCatalogSingleton { get; set; }
public Handler.EventHandler EventHandler { get; set; }

// Disable or enable Deletebutton
public bool DeletebuttonEnableOrNot
{
    get { return _deleteButtonEnableOrNot;}
    set
    {
        _deleteButtonEnableOrNot = value;
        OnPropertyChanged();
    }            
}

public ICommand EnableOrNotCommand
{
    get { return _enableOrNotCommand; }
    set { _enableOrNotCommand = value; }
}

// Set TextBlock visibility
public string TextBlockVisibility
{
    get { return _textBlockVisibility; }
    set
    {
        _textBlockVisibility = value;
        OnPropertyChanged();
    }
}

public ICommand TextBlockVisibilityCommand
{
    get { return _textBlockVisibilityCommand; }
    set { _textBlockVisibilityCommand = value; }
}

// Constructor
public EventViewModel()
{
    //Initializes Date and Time with some values that are bound to controls.
    DateTime dt = System.DateTime.Now;
    _date = new DateTimeOffset(dt.Year, dt.Month, dt.Day, 0, 0, 0, 0, new TimeSpan());
    _time = new TimeSpan(dt.Hour, dt.Minute, dt.Second);

    EventCatalogSingleton = EventCatalogSingleton.getInstance();
    EventHandler = new Handler.EventHandler(this);

    // Creates an instance of the RelayCommand and passes necessary method as a parameter
    _createEventCommand = new RelayCommand(EventHandler.CreateEvent);

    _deleteEventCommand = new RelayCommand(EventHandler.GetDeleteConfirmationAsync);

    _enableOrNotCommand = new RelayCommand(EventHandler.EnableOrNot);

    _textBlockVisibilityCommand = new RelayCommand(EventHandler.TextBlockVisibility);

}

单例:

公共类EventCatalogSingleton{私有静态EventCatalogSingleton _instance;

public class EventCatalogSingleton { private static EventCatalogSingleton _instance;

private EventCatalogSingleton()
{
    Events = new ObservableCollection<Event>();

    // Creates instances of events and adds it to the observable collection.
    LoadEventAsync();
}

//Checks if an instance already exists, if not it will create one. Makes sure we only have one instance
public static EventCatalogSingleton getInstance()
{
    if (_instance != null)
    {
        return _instance;
    }
    else
    {
        _instance = new EventCatalogSingleton();
        return _instance;
    }
}

// Creates the observable collection
public ObservableCollection<Event> Events { get; set; }

public void AddEvent(Event newEvent)
{
    Events.Add(newEvent);
    PersistencyService.SaveEventsAsJsonAsync(Events);
}

public void AddEvent(int id, string name, string description, string place, DateTime date)
{
    Events.Add(new Event(id, name, description, place, date));
    PersistencyService.SaveEventsAsJsonAsync(Events);
}


public void RemoveEvent(Event myEvent)
{
    Events.Remove(myEvent);
    PersistencyService.SaveEventsAsJsonAsync(Events);
}

public async void LoadEventAsync()
{

    var events = await PersistencyService.LoadEventsFromJsonAsync();
    if (events != null)
        foreach (var ev in events)
        {
            Events.Add(ev);
        }

}

}

处理程序:

公共类EventHandler{

public class EventHandler {

public EventViewModel EventViewModel { get; set; }

public EventHandler(EventViewModel eventViewModel)
{
    EventViewModel = eventViewModel;
}

public void CreateEvent()
{
    EventViewModel.EventCatalogSingleton.AddEvent(EventViewModel.Id,    EventViewModel.Name, EventViewModel.Description, EventViewModel.Place, DateTimeConverter.DateTimeOffsetAndTimeSetToDateTime(EventViewModel.Date, EventViewModel.Time));
}


private void DeleteEvent()
{
    EventViewModel.EventCatalogSingleton.Events.Remove(EventViewModel.SelectedEvent);
}

// Confirmation box that prompts user before deletion
public async void GetDeleteConfirmationAsync()
{
    MessageDialog msgbox = new MessageDialog("Are you sure you want to permenantly delete this event?", "Delete event");

    msgbox.Commands.Add(new UICommand
    {
        Label = "Yes",
        Invoked = command => DeleteEvent()
    }
    );

    msgbox.Commands.Add(new UICommand
    {
        Label = "No",
    }
    );
    msgbox.DefaultCommandIndex = 1;
    msgbox.CancelCommandIndex = 1;
    msgbox.Options = MessageDialogOptions.AcceptUserInputAfterDelay;

    await msgbox.ShowAsync();
}

public void EnableOrNot()
{
    EventViewModel.DeletebuttonEnableOrNot = EventViewModel.DeletebuttonEnableOrNot = true;
}

public void TextBlockVisibility()
{
    if (EventViewModel.EventCatalogSingleton.Events.Count < 1)
    {
        EventViewModel.TextBlockVisibility = EventViewModel.TextBlockVisibility = "Visible";
    }        
}

}

我知道要包含很多代码-不知道该删除什么.我包含了当在列表视图中选择一个项目时启用删除按钮时的代码-效果很好.

Its a lot of code to include, I know - didn't know what to leave out. I included the code for when I enable a delete-button when an item in the listview has been selected - which works fine.

为什么删除列表视图中的所有项目后,视图中的TextBlock为何不显示?我真的有必要在视图模型中具有属性和ICommands以便更改视图中的外观和控件的其他内容吗?

Why doesn't the TextBlock in view show after I delete all items in the listview? And is it really necessary for me to have properties and ICommands in the viewmodel in order to change apperance and other things of controls in the view?

推荐答案

很有趣,但是Daren May和我刚刚在Microsoft Virtual Academy上专门教授了一个免费课程.对于您来说,这可能是一个不错的资源.观看视频 #2 @ 13 分钟.

Funny enough, but Daren May and I just taught a free course specifically on this on Microsoft Virtual Academy. It might be a nice resource for you. Look in video #2 @ 13 minutes.

https://mva.microsoft.com/zh-CN/training-courses/xaml-for-windows-10-items-controls-14483

看看这种简单的方法:

使用以下代码:

class VisibleWhenZeroConverter : IValueConverter
{
    public object Convert(object v, Type t, object p, string l) =>
        Equals(0d, (double)v) ? Visibility.Visible : Visibility.Collapsed;

    public object ConvertBack(object v, Type t, object p, string l) => null;
}

此XAML:

    <StackPanel.Resources>
        <cvt:VisibleWhenZeroConverter x:Name="VisibleWhenZeroConverter" />
    </StackPanel.Resources>

    <ListView ItemsSource="{x:Bind Items}" x:Name="MyList">
        <ListView.Header>
            <TextBlock Visibility="{Binding Items.Count, ElementName=MyList, 
                       Converter={StaticResource VisibleWhenZeroConverter}}">
                <Run Text="There are no items." />
            </TextBlock>
        </ListView.Header>
    </ListView>

有道理吗?我希望是这样.

Make sense? I hope so.

PS:这回答了您问题的确切标题.希望对您有所帮助.

PS: this answers the EXACT title of your question. Hope it helps.

祝你好运!

这篇关于当ListView在UWP中不包含带有MVVM的项目时显示消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆