当 ListView 不包含 UWP 中带有 MVVM 的项目时显示消息
Display message when ListView contains no items with MVVM in a UWP
这是我的第一个 MVVM 项目,我需要编写用于在视图中操作控件的代码似乎比它必须的复杂得多。
我发现很难完全理解 MVVM 并决定何时可以将代码放在后面。
基本上我的问题是我想显示一条消息,告诉用户当列表视图绑定到的 ObservableCollection 不包含任何项目时,它是空的。这个想法是在视图中有一个 TextBlock,并且只有在没有要显示的项目时(在用户创建项目之前和删除之后)才将其可见性 属性 设置为 Visible所有项目)
我无法使用此解决方案,因为 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>
ViewModel:
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);
}
单例:
public class 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 class 事件处理器
{
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";
}
}
}
要包含的代码很多,我知道 - 不知道要省略什么。
我包含了当我在列表视图中选择了一个项目时启用删除按钮的代码 - 它工作正常。
为什么删除列表视图中的所有项目后视图中的TextBlock 不显示?我真的有必要在视图模型中拥有属性和 ICommand 以更改视图中控件的外观和其他内容吗?
我已经成功地在 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}">
还有很多方法可以显示消息,例如
您可以将一个 TextBlock 绑定到一个错误“”,当它为空时添加您的错误
从模型中创建 DialogMessage
await Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () =>
{
MessageDialog dialog = new MessageDialog(error);
await dialog.ShowAsync();
});
首先,您想尽最大努力在视图和视图模型之间保持清晰的关注点分离。因此,尽量不要包含 UI 特定类型,例如 Visibility
和 MessageDialog
。您可以为负责显示对话框的 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>
并在您的虚拟机中:
public bool HasNoItems
{
get { return this.hasNoItems; }
set { this.hasNoItems = value; OnPropertyChanged(); }
}
很有趣,但我和 Daren May 刚刚在 Microsoft Virtual Academy 上教授了一门专门针对此的免费课程。这对你来说可能是一个很好的资源。观看视频 #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.
祝你好运!
这是我的第一个 MVVM 项目,我需要编写用于在视图中操作控件的代码似乎比它必须的复杂得多。
我发现很难完全理解 MVVM 并决定何时可以将代码放在后面。
基本上我的问题是我想显示一条消息,告诉用户当列表视图绑定到的 ObservableCollection 不包含任何项目时,它是空的。这个想法是在视图中有一个 TextBlock,并且只有在没有要显示的项目时(在用户创建项目之前和删除之后)才将其可见性 属性 设置为 Visible所有项目)
我无法使用此解决方案,因为 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>
ViewModel:
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);
}
单例:
public class 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 class 事件处理器 {
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";
}
}
}
要包含的代码很多,我知道 - 不知道要省略什么。 我包含了当我在列表视图中选择了一个项目时启用删除按钮的代码 - 它工作正常。
为什么删除列表视图中的所有项目后视图中的TextBlock 不显示?我真的有必要在视图模型中拥有属性和 ICommand 以更改视图中控件的外观和其他内容吗?
我已经成功地在 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}">
还有很多方法可以显示消息,例如
您可以将一个 TextBlock 绑定到一个错误“”,当它为空时添加您的错误
从模型中创建 DialogMessage
await Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => { MessageDialog dialog = new MessageDialog(error); await dialog.ShowAsync(); });
首先,您想尽最大努力在视图和视图模型之间保持清晰的关注点分离。因此,尽量不要包含 UI 特定类型,例如 Visibility
和 MessageDialog
。您可以为负责显示对话框的 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>
并在您的虚拟机中:
public bool HasNoItems
{
get { return this.hasNoItems; }
set { this.hasNoItems = value; OnPropertyChanged(); }
}
很有趣,但我和 Daren May 刚刚在 Microsoft Virtual Academy 上教授了一门专门针对此的免费课程。这对你来说可能是一个很好的资源。观看视频 #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.
祝你好运!