[英]Hide ListView when no results in ItemsSource
我正在使用Visual Studio 2015和MVVM Light Toolkit來構建WPF應用程序。 當用戶單擊DataGrid
的員工時,我們將顯示記錄的詳細信息以允許進行編輯。 此詳細信息區域包含兩個選項卡:“人口統計”和“測試”。 “測試”選項卡顯示此人的測試的ListView
。
結構如下:
MainWindow.xaml :
<DataTemplate x:Key="EmployeeSearchTemplate">
<view:EmployeeSearchView />
</DataTemplate>
<ContentControl ContentTemplate="{StaticResource EmployeeSearchTemplate}" />
EmployeeSearchView.xaml :
<UserControl.DataContext>
<viewModel:EmployeeSearchViewModel />
</UserControl.DataContext>
<ContentControl Content="{Binding SelectedEmployee}"
ContentTemplate="{StaticResource EmployeeViewTemplate}" .../>
當用戶選擇“測試”選項卡時,我們將搜索數據庫並返回該員工的測試(如果有)。
EmployeeView.xaml :
<DataTemplate x:Key="TestsViewTemplate">
<views:TestsView />
</DataTemplate>
<TabControl SelectedIndex="{Binding SelectedTabIndex}">
<TabItem>
<!-- Demographic details of record here -->
</TabItem>
<TabItem>
<!-- Employee test info here. When user selects this tab, search db
and return tests for this employee, if any -->
<ContentControl Content="{Binding TestsVm}"
ContentTemplate="{StaticResource TestsViewTemplate}" />
</TabItem>
</TabControl>
這是EmployeeViewModel.cs
的構造函數和一些屬性:
private TestsViewModel _testsVm;
private int _selectedTabIndex;
public EmployeeViewModel ()
{
// Other initialization code...
_selectedTabIndex = 0;
this.PropertyChanged += (o, e) =>
{
if (e.PropertyName == nameof(SelectedTabIndex))
{
// If tab 1 selected, the person is on the Tests tab
// Perform search and populate the TestsVM object's Tests
// by executing the RelayCommand on it
if (SelectedTabIndex.Equals(1))
{
TestsVm = new TestsViewModel
{
SelectedEmployeeId = EmployeeId
};
TestsVm.SearchTestsRelayCommand.Execute(null);
}
}
};
}
public TestsViewModel TestsVm
{
get { return _testsVm; }
set
{
if (Equals(value, _testsVm)) return;
_testsVm = value;
RaisePropertyChanged();
}
}
public int SelectedTabIndex
{
get { return _selectedTabIndex; }
set
{
if (value == _selectedTabIndex) return;
_selectedTabIndex = value;
RaisePropertyChanged();
}
}
這是TestsView.xaml
的ListView
:
<ListView ItemsSource="{Binding Tests}"
Visibility="{Binding HasTests,
Converter={helpers:BooleanToVisibilityConverter WhenTrue=Visible,
WhenFalse=Hidden}}">
<ListView.View>
<GridView>
<!-- GridView columns here -->
</GridView>
</ListView.View>
</ListView>
這是來自TestsViewModel.cs
的代碼:
private ObservableCollection<TestViewModel> _tests;
private int _selectedEmployeeId;
private bool _hasTests;
public TestsViewModel()
{
SearchTestsRelayCommand = new RelayCommand(CallSearchTestsAsync);
this.PropertyChanged += (o, e) =>
{
if (e.PropertyName == nameof(Tests))
{
HasTests = !Tests.Count.Equals(0);
}
};
}
public RelayCommand SearchTestsRelayCommand { get; private set; }
private async void CallSearchTestsAsync()
{
await SearchTestsAsync(SelectedEmployeeId);
}
private async Task SearchTestsAsync(int employeeId)
{
ITestDataService dataService = new TestDataService();
try
{
Tests = await dataService.SearchTestsAsync(employeeId);
}
finally
{
HasTests = !Tests.Count.Equals(0);
}
}
public ObservableCollection<TestViewModel> Tests
{
get { return _tests; }
set
{
if (Equals(value, _tests)) return;
_tests = value;
RaisePropertyChanged();
}
}
public bool HasTests
{
get { return _hasTests; }
set
{
if (value == _hasTests) return;
_hasTests = value;
RaisePropertyChanged();
}
}
public int SelectedEmployeeId
{
get { return _selectedEmployeeId; }
set
{
if (value == _selectedEmployeeId) return;
_selectedEmployeeId = value;
RaisePropertyChanged();
}
}
HasTests
屬性不會更改,因此在ListView
為空時不會隱藏它。 請注意,我還嘗試了以下方法以查看ListView
可見性,並指出其自身的HasItems
無濟於事:
Visibility="{Binding HasItems,
RelativeSource={RelativeSource Self},
Converter={helpers:BooleanToVisibilityConverter WhenTrue=Visible,
WhenFalse=Hidden}}"
我已經在其他地方成功使用了相同的BooleanToVisibilityConverter
,所以這與我的代碼有關。 我願意接受您的建議。 謝謝。
更新 :這是TestView.xaml的XAML:
<UserControl x:Class="DrugComp.Views.TestsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="clr-namespace:DrugComp.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:viewModel="clr-namespace:DrugComp.ViewModel"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
d:DesignHeight="300"
d:DesignWidth="300"
mc:Ignorable="d">
<UserControl.Resources />
<Grid Width="Auto"
Height="700"
Margin="5,7,5,5"
HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Grid.ColumnSpan="2"
HorizontalAlignment="Left"
Style="{StaticResource Instruction}"
Text="{Binding Instructions}" />
<ListView Grid.Row="1"
Grid.ColumnSpan="2"
Width="Auto"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top"
AlternationCount="2"
ItemContainerStyle="{DynamicResource CustomListViewItemStyle}"
ItemsSource="{Binding Tests}"
SelectedItem="{Binding SelectedTest}">
<ListView.Style>
<Style TargetType="{x:Type ListView}">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<!-- If you want to save the place in the layout, use
Hidden instead of Collapsed -->
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Style>
<ListView.View>
<GridView>
<GridViewColumn Width="50"
DisplayMemberBinding="{Binding TestId}"
Header="Test ID" />
<GridViewColumn Width="90"
DisplayMemberBinding="{Binding EmployeeId}"
Header="Employee ID" />
<GridViewColumn Width="90"
DisplayMemberBinding="{Binding OrderedDate,
StringFormat='MM/dd/yyyy'}"
Header="Ordered Date" />
<GridViewColumn Width="119"
DisplayMemberBinding="{Binding ValidReasonForTest.Description}"
Header="Reason" />
<GridViewColumn Width="129"
DisplayMemberBinding="{Binding OrderedByWhom}"
Header="Ordered By" />
<GridViewColumn Width="90"
DisplayMemberBinding="{Binding ScheduledDate,
StringFormat='MM/dd/yyyy'}"
Header="Scheduled Date" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
正如喬所說,您沒有收到通知。 而且,如果您出於某種原因而不是隱藏此ListView
,還需要HasTests
,他的答案將有所幫助。 但這不是XAML視圖中執行此操作的方法。
更新:
<!-- In the view's Resources -->
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
<!-- ... -->
<ListView
Visibility="{Binding HasItems,
RelativeSource={RelativeSource Self},
Converter=BooleanToVisibility}" />
(第二種)最干凈,最簡單,最簡單的方法是使用樣式中的觸發器,如下所示:
<ListView>
<ListView.View>
<GridView>
<!-- GridView columns here -->
</GridView>
</ListView.View>
<ListView.Style>
<Style
TargetType="{x:Type ListView}"
BasedOn="{StaticResource {x:Type ListView}}">
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<!-- If you want to save the place in the layout, use
Hidden instead of Collapsed -->
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
只是請注意,您不能像這樣設置XAML中的Visibility
屬性,因為這是一個“本地”值,它將取代Style
所做的任何事情:
<ListView Visibility="Visible" ...>
當您想為控件的特定實例覆蓋樣式時,這是理想的行為,但是在編寫觸發器時,這會給您帶來很多麻煩。
在這種特定情況下,我無法想象您會這樣做的任何原因,但這是XAML中帶有樣式和觸發器的普遍“陷阱”。 如果要為將由觸發器驅動的屬性設置特定的初始值,則可以在Style
的未觸發的Setter
中進行設置:
<Style
TargetType="{x:Type ListView}"
BasedOn="{StaticResource {x:Type ListView}}">
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<Trigger Property="HasItems" Value="False">
<!-- If you want to save the place in the layout, use
Hidden instead of Collapsed -->
<Setter Property="Visibility" Value="Collapsed" />
</Trigger>
</Style.Triggers>
</Style>
然后,這都是一種樣式或另一種樣式,觸發器將起作用。
ItemsControl
任何后代都將支持HasItems
屬性 : ListBox
, ComboBox
, MenuItem
,即可為其命名。 幾乎所有旨在呈現動態項目集合的本機WPF控件 (像DevExpress這樣的第三方控件供應商通常都會忽略這一點,並使用他們自己的,通常考慮不周的類層次結構)。 之所以會這樣,是因為它總是存在的,非常易於使用,並且物品的來源無關緊要。 無論您做什么將物品放入該物品中,它都會在沒有物品的情況下隱藏起來。
您的代碼來更新HasTests:
this.PropertyChanged += (o, e) =>
{
if (e.PropertyName == nameof(Tests))
{
HasTests = !Tests.Count.Equals(0);
}
};
僅在更改整個屬性“測試”(即,將其分配給新的ObservableCollection)時才會觸發。 大概您不是在執行此操作,而是使用“清除”,“添加”或“刪除”來更改測試的內容。
結果,您的HasTests永遠不會得到更新。 還嘗試更新Tests.CollectionChange事件以捕獲添加/刪除。
編輯:像這樣
this.PropertyChanged += (o, e) =>
{
if (e.PropertyName == nameof(Tests))
{
HasTests = !Tests.Count.Equals(0);
//also update when collection changes:
Tests.CollectionChanged += (o2, e2) =>
{
HasTests = !Tests.Count.Equals(0);
};
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.