listview - 当 ListView 在 UWP 中不包含带有 MVVM 的项目时显示消息

标签 listview winrt-xaml win-universal-app windows-10-universal

这是我的第一个 MVVM 项目,我需要编写的用于在 View 中操作控件的代码似乎过于复杂。

我发现很难完全理解 MVVM 并决定什么时候可以把东西放在代码后面。

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

我不能使用这个解决方案,因为 UWP 不支持 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>

查看型号:

公共(public)类 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);

}

单例:

公共(public)类 EventCatalogSingleton
{
私有(private)静态 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);
        }

}

}

经办人:

公共(public)类事件处理程序
{
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";
    }        
}

}

它包含很多代码,我知道 - 不知道要省略什么。
我包含了当我在 ListView 中选择一个项目时启用删除按钮的代码 - 这工作正常。

为什么我删除 ListView 中的所有项目后 View 中的文本 block 不显示?为了更改 View 中控件的外观和其他内容,我真的有必要在 View 模型中拥有属性和 ICommands 吗?

最佳答案

很有趣,但 Daren May 和我刚刚在 Microsoft Virtual Academy 上专门教授了一门免费类(class)。这对你来说可能是一个很好的资源。看视频#2 @ 13 分钟。

https://mva.microsoft.com/en-US/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>

有道理?但愿如此。

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



祝你好运!

关于listview - 当 ListView 在 UWP 中不包含带有 MVVM 的项目时显示消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35368143/

相关文章:

user-controls - 如何在 HeaderTemplate WinRT XAML 中绑定(bind)用户控件的 DependencyProperty?

Android ListView 问题。不会显示添加的 View

android - Android 中 ListView 的 setBackgroundDrawable

c# - 使用 WebView 全屏制作 XAML 控件

c# - 创建具有约束比例的可调整大小的按钮网格控件的最佳方法(Silverlight。XAML,WinRT)

c# - 如何从 IRandomAccessStream 获取 IBuffer

javascript - GridLayout ListView 的渲染非常慢 - WinJS

android - OnItemCLickListener 在 ListView 中不起作用

c# - 为什么 XAML 不等同于 AddHandler?

windows-runtime - .winmd 文件与平台无关吗?