2

這是我的第一個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

回答

10

夠搞笑的,但達仁可能和我剛剛教了一個免費的小提示在微軟虛擬學院專門討論這個問題。它可能是一個很好的資源給你。觀看視頻#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:這回答您的問題的確切標題。希望能幫助到你。

祝你好運!

0

我已經成功添加知名度綁定在一個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(); 
         }); 
    
0

一中創建一個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(); } 
} 
相關問題