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

问题描述:

这是我的第一个MVVM项目,我需要编写的代码在视图中操纵控件似乎太复杂了。当ListView在UWP中不包含带有MVVM的项目时显示消息

我发现很难完全理解MVVM并决定何时可以将代码放在代码后面。

基本上我的问题是,我想显示一条消息告诉用户,当它绑定到ObservableCollection不包含项目时,该列表视图是空的。当时的想法是在视图一个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> 

视图模型:

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

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 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中的所有项目后,TextBlock在视图中不显示?我真的有必要在视图模型中使用属性和ICommands来改变视图中控件的外观和其他事物吗?

+0

你有没有实现INotifyPropertyChanged正确? – Stamos

够搞笑的,但达仁可能和我刚刚教了一个免费的小提示在微软虚拟学院专门讨论这个问题。它可能是一个很好的资源给你。观看视频#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:这回答您的问题的确切标题。希望能帮助到你。

祝你好运!

我已经成功添加知名度绑定在一个StackPanel矿山的这样

型号项目CS

Visibility showPanel = Visibility.Collapsed; 
    public Visibility ShowPanel 
    { 
     get 
     { 
      return showPanel; 
     } 

     set 
     { 
      showPanel = value; 
      NotifyPropertyChanged("ShowPanel"); 
     } 
    } 

XAML

<StackPanel Height="220" Orientation="Vertical" Visibility="{Binding ShowPanel}"> 

还有一些可以显示多种方式消息,例如

  1. 你可以把一个TextBlock与结合是一个错误“”,当其空加你的错误

  2. 从模型

    await Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async() => 
         { 
          MessageDialog dialog = new MessageDialog(error); 
          await dialog.ShowAsync(); 
         }); 
    

一中创建一个DialogMessage,要尽量保持视图和视图模型之间的清晰分离。因此,尽量不要包含UI特定类型,如VisibilityMessageDialog。您可以为MessageDialog创建一个界面,负责显示对话框,然后将其传递给您的视图模型。

其次,你应该准备写自己的价值转换器(BooleanToVisibilityConverter),像下面这样:

public sealed class BooleanToVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, 
     Type targetType, object parameter, string language) 
    { 
     bool isVisible = (bool)value; 
     return isVisible ? Visibility.Visible : Visibility.Collapsed; 
    } 

    public object ConvertBack(object value, 
      Type targetType, object parameter, string language) 
    { 
     return (Visibility)value == Visibility.Visible; 
    } 
} 

,并用它在你看来像这样:

<Page 
    xmlns:converters="using:MyApp.Whatever"> 
    <Page.Resources> 
     <converters:BooleanToVisibilityConverter x:Key="converter"/> 
    </Page.Resources> 
    <TextBlock 
    Visibility="{Binding HasNoItems, Mode=TwoWay, 
     Converter={StaticResource converter}}"> 
    </TextBlock> 
</Page> 

,并在你的VM:

public bool HasNoItems 
{ 
    get { return this.hasNoItems; } 
    set { this.hasNoItems = value; OnPropertyChanged(); } 
}