[英]XAML Toggle ListViewItem visibility on click
我正在尝试根据所选的 ListViewItem 更改项目的可见性。 基本上,ListView 中的每一列在网格上都有两个项目,一个 label 和一个控件(Combobox、DatePicker、Textbox 等)。 如果选择了 ListViewItem,那么我希望该行中的所有控件都可见,否则 label 应该可见。 这是在 UserControl 上,而不是 Window,如果这有什么不同的话。
这是我的看法 model
public class DailyServiceLogsViewModel
{
public int DailyServiceLogID { get; set; }
public int EmployeePositionID { get; set; }
public PositionType SelectedEmployeePosition { get; set; }
public List<PositionType> EmployeePositionList { get; set; }
public List<EmployeeSelectionListViewModel> EmployeeList { get; set; }
public EmployeeSelectionListViewModel SelectedEmployee { get; set; }
public string EmployeeName { get; set; }
public string PositionDescription { get; set; }
public DateTime? Date { get; set; }
public string WorkArea { get; set; }
public bool SelectedLog { get; set; }
}
背后的代码
private DBContext _dbContext= new DBContext();
public ObservableCollection<DailyServiceLogsViewModel> DailyServiceLogs { get; set; }
public void OnLoad()
{
_dbContext= new DBContext();
List<EmployeeSelectionListViewModel> employeeList = _dbContext.Employees.Where(emp => emp.Active).Select(employee => new EmployeeSelectionListViewModel { EmployeeID = employee.EmployeeID, EmployeeName = employee.FirstName + " " + employee.LastName }).ToList();
DailyServiceLogs = new ObservableCollection<DailyServiceLogsViewModel>();
foreach (var serviceLog in _dbContext.DailyServiceLogs.Where(d => d.PayPeriodID == CurrentPayPeriod.PayPeriodID).OrderBy(d => d.EmployeePosition.Employee.LastName).ThenBy(d => d.EmployeePosition.Employee.FirstName))
{
DailyServiceLogs.Add(new DailyServiceLogsViewModel
{
DailyServiceLogID = serviceLog.DailyServiceLogID,
EmployeePositionID = serviceLog.EmployeePositionID,
SelectedEmployeePosition = serviceLog.EmployeePosition.PositionType,
EmployeeName = serviceLog.EmployeePosition.Employee.FirstName + " " + serviceLog.EmployeePosition.Employee.LastName,
Date = serviceLog.Date,
PositionDescription = serviceLog.EmployeePosition.PositionType.Description,
WorkArea = serviceLog.Workarea,
EmployeeList = employeeList,
SelectedEmployee = new EmployeeSelectionListViewModel { EmployeeID = serviceLog.EmployeePosition.EmployeeID, EmployeeName = serviceLog.EmployeePosition.Employee.FirstName + " " + serviceLog.EmployeePosition.Employee.LastName },
EmployeePositionList = _dbContext.PositionTypes.Where(pt => pt.Active && _payrollContext.EmployeePositions.Any(ep => ep.EmployeeID == serviceLog.EmployeePosition.EmployeeID && ep.PositionTypeID == pt.PositionTypeID)).ToList(),
SelectedLog = false
});
}
ListViewTest.DataContext = this;
ListViewTest.ItemsSource = DailyServiceLogs;
}
private void DailyServiceLog_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!(sender is ListView senderListView)) return;
if (senderListView.SelectedItem == null) return;
if (senderListView.SelectedItem.GetType() == typeof(DailyServiceLogsViewModel))
{
foreach (var log in DailyServiceLogs)
{
log.SelectedLog = log.DailyServiceLogID == ((DailyServiceLogsViewModel) senderListView.SelectedItem).DailyServiceLogID;
}
}
}
我尝试过使用 DataTriggers,但我对它们不太熟悉
<ListView Name="ListViewTest" Grid.Row="1" ItemsSource="{Binding}" SelectionChanged="DailyServiceLog_OnSelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn x:Name="clmServiceEmployeeName" Header="Employee" Width="155">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="gdEmployee" Width="{Binding ElementName=clmServiceEmployeeName, Path=Width}" Tag="{Binding DailyServiceLogID}">
<Label Content="{Binding EmployeeName}" >
<Label.Style>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.SelectedLog}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<ComboBox Tag="{Binding ElementName=gdEmployee, Path=Tag}" ItemsSource="{Binding EmployeeList}" SelectedValue="{Binding SelectedEmployee.EmployeeID}" DisplayMemberPath="EmployeeName" SelectedValuePath="EmployeeID" FlowDirection="LeftToRight" Margin="15,5" HorizontalAlignment="Stretch" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.SelectedLog}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
...
</GridView>
</ListView.View>
</ListView>
我也试过用转换器
<ListView Name="ListViewTest" Grid.Row="1" ItemsSource="{Binding}" SelectionChanged="DailyServiceLog_OnSelectionChanged">
<ListView.View>
<GridView>
<GridViewColumn x:Name="clmServiceEmployeeName" Header="Employee" Width="155">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid x:Name="gdEmployee" Width="{Binding ElementName=clmServiceEmployeeName, Path=Width}" Tag="{Binding DailyServiceLogID}">
<Grid.Resources>
<dataconverter:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/>
<dataconverter:InvertedBoolVisibilityConverter x:Key="InvertedBoolVisibilityConverter"/>
</Grid.Resources>
<Label Content="{Binding EmployeeName}" Visibility="{Binding ElementName=PayrollControl, Path=SelectedServiceLog, Converter={StaticResource InvertedBoolVisibilityConverter}}"/>
<ComboBox Tag="{Binding ElementName=gdEmployee, Path=Tag}" ItemsSource="{Binding EmployeeList}" SelectedValue="{Binding SelectedEmployee.EmployeeID}" Visibility="{Binding SelectedServiceLog, Converter={StaticResource BoolVisibilityConverter}}" DisplayMemberPath="EmployeeName" SelectedValuePath="EmployeeID" FlowDirection="LeftToRight" Margin="15,5" HorizontalAlignment="Stretch" />
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
知道如何将其发送给 function,或者是否有更好的方法来了解我想要实现的目标? 任何帮助将不胜感激。
保持SelectedLog
更新的正确方法是为 ListView 创建一个ItemContainerStyle
,并将其绑定到那里。 这才是正确的解决方案。 您需要使您的项目视图模型成为实现INotifyPropertyChanged
的实际视图模型。 事实上,更改该属性永远不会影响 UI 中的任何内容,因为 UI 不会收到更改通知。 该解决方案如下。
但是,如果视图模型不特别关心它是否被选中,我们可以删除您的 SelectionChanged 处理程序,从项目 class 中删除SelectedLog
,并在我们的触发器中直接绑定到 ListViewItem 的实际 IsSelected 属性。 请注意,您将 ComboBox 设置为在选择项目时可见,但在未选择项目时您从未隐藏它。 我已经解决了。 当我们被选中时,一个控件被隐藏,当我们未被选中时,另一个控件被隐藏。
<Label Content="{Binding EmployeeName}" >
<Label.Style>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<ComboBox Tag="{Binding ElementName=gdEmployee, Path=Tag}" ItemsSource="{Binding EmployeeList}" SelectedValue="{Binding SelectedEmployee.EmployeeID}" DisplayMemberPath="EmployeeName" SelectedValuePath="EmployeeID" FlowDirection="LeftToRight" Margin="15,5" HorizontalAlignment="Stretch" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
您应该学习如何创建和绑定视图模型属性,这就是解决方案。 首先,我们需要使“viewmodel”成为一个实际的 viewmodel:
public class DailyServiceLogsViewModel : ViewModelBase
{
public int DailyServiceLogID { get; set; }
public int EmployeePositionID { get; set; }
public PositionType SelectedEmployeePosition { get; set; }
public List<PositionType> EmployeePositionList { get; set; }
public List<EmployeeSelectionListViewModel> EmployeeList { get; set; }
public EmployeeSelectionListViewModel SelectedEmployee { get; set; }
public string EmployeeName { get; set; }
public string PositionDescription { get; set; }
public DateTime? Date { get; set; }
public string WorkArea { get; set; }
// Only properties like this will notify the UI when they update.
private bool _isSelectedLog = false;
public bool IsSelectedLog
{
get => _isSelectedLog;
set => SetProperty(ref _isSelectedLog, value);
}
}
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
public void SetProperty<T>(ref T field, T value, [CallerMemberName] string propName = null)
{
if (!Object.Equals(field, value))
{
field = value;
OnPropertyChanged(propName);
}
}
}
其次,添加一个 ItemContainerStyle,它在选择项目时设置IsSelectedLog
。 您可以删除 SelectionChanged 处理程序。
<ListView ItemsSource="{Binding Items}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelectedLog}" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn x:Name="clmServiceEmployeeName" Header="Employee" Width="155">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Tag="{Binding DailyServiceLogID}">
<Label Content="{Binding EmployeeName}" >
<Label.Style>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedLog}" Value="True">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
<ComboBox Tag="{Binding ElementName=gdEmployee, Path=Tag}" ItemsSource="{Binding EmployeeList}" SelectedValue="{Binding SelectedEmployee.EmployeeID}" DisplayMemberPath="EmployeeName" SelectedValuePath="EmployeeID" FlowDirection="LeftToRight" Margin="15,5" HorizontalAlignment="Stretch" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedLog}" Value="False">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.