如何让 ListView 项目的单击事件打开和关闭列表视图的项目模板中的复选框
How to have the click event of a ListView item turn on and off the checkbox in the item template for the listview
我的 UWP 应用在用户控件中带有 XAML 列表视图,如下所示。
<ListView x:Name="lvDevices"
Margin="12,8,0,0"
Grid.Row="4"
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource DeviceTemplate}"
Width="Auto"
ItemsSource="{Binding Devices}"
IsItemClickEnabled="True"
ItemClick="lvDevices_ItemClick"
d:DataContext="{d:DesignData /SampleData/DevicesVMSampleData.xaml}" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
列表视图的项目模板如下。您可以看到项目模板有一个复选框,它使用两种方式绑定到我的视图模型。
<DataTemplate x:Key="DeviceTemplate">
<Grid Margin="0" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox x:Name="chkSelected" IsChecked="{Binding Selected, Mode=TwoWay}" MinWidth="32" Grid.Column="0" Checked="chkSelected_Changed" Unchecked="chkSelected_Changed" />
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="10,0,0,0">
<TextBlock Text="{Binding DeviceName}" Style="{StaticResource TitleTextBlockStyle}" Tag="{Binding ID}" TextWrapping="Wrap" MaxWidth="500"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="User:" Margin="0,0,10,0" Style="{StaticResource CaptionTextBlockStyle}" FontWeight="Bold" />
<TextBlock Text="{Binding User}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</StackPanel>
<Button x:Name="btnInfo" Grid.Column="2" Background="Transparent" HorizontalAlignment="Right">
<Image x:Name="imgInfo" HorizontalAlignment="Right" VerticalAlignment="Center" Source="/Assets/InfoIcon-100.png" Height="50" Width="50" />
</Button>
</Grid>
</DataTemplate>
列表视图的数据上下文设置为我的视图模型。
ucDeviceInfo.DataContext = iobj_DevicesViewModel;
所以我想要的是当用户单击列表视图中的某个项目时,该项目的复选框更新为带有复选标记或删除其复选标记。我认为最好的方法是在用户单击该行时将 ViewModel 中的 'Selected' 属性 设置为 true 或 false,然后通知视图 属性 已更改. (项目列表是一个可观察的集合。)。
我尝试通过以下方式完成此操作:
在 UserControl 中 - 当用户单击一行时,我使用以下代码在基页中调用一个方法:
private void lvDevices_ItemClick(object sender, ItemClickEventArgs e)
{
StartPage lobj_ParentForm;
lobj_ParentForm = ((StartPage)((Frame)Window.Current.Content).Content);
lobj_ParentForm.SendNotifyPropertyChanged( ((Device)e.ClickedItem).ID);
}
在基本页面中,我使用以下代码在我的 ViewModel 中调用了一个方法:
public void SendNotifyPropertyChanged(int pi_DeviceID)
{
iobj_DevicesViewModel.DeviceSelectedInListView(pi_DeviceID);
}
然后在视图模型中,我为设备更新了选定的 属性 并使用以下代码调用通知 属性 已更改的函数:
public void DeviceSelectedInListView(int pi_DeviceID)
{
Device lobj_SelectedDevice;
lobj_SelectedDevice = (from lobj_Device in Devices
where lobj_Device.ID == pi_DeviceID
select lobj_Device).ToList<Device>()[0];
lobj_SelectedDevice.Selected = !lobj_SelectedDevice.Selected;
NotifyPropertyChanged("Devices");
SelectionsChanged();
}
public void SelectionsChanged()
{
NotifyPropertyChanged("SelectedDeviceCount");
}
挑战在于,当我这样做并调用 notify 属性 changed 方法时,我刚刚单击的列表视图中项目的复选框没有更新。知道当用户单击列表视图中的一行时如何让复选框正确更新吗?
Link 说明此问题的示例项目是
Example Code
至于你的代码 - 你几乎已经做对了。您的集合引用 Devices
不会更改,因此绑定不会更新整个集合,您也不会 add/remove 元素,因此 ObservableCollection 可能已经更新。在这种情况下,您需要调用 属性 changed on item's class。为此,只需在设备 class:
上实施 INotifyPropertyChanged
public class Device : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private bool selected;
public bool Selected
{
get { return selected; }
set { selected = value; RaiseProperty(nameof(Selected)); }
}
// rest of the class
在此之后,您也不需要每次在项目内部发生变化时调用 NotifyPropertyChanged("Devices");
,绑定将完成这项工作。因为你有 ObservableCollection 我认为你根本不需要调用它。
The modified sample you have shared.
我不太清楚您为什么不使用默认的 ListView 复选框。如果您将选择模式设置为 Multiple 那么您将在每个项目上看到一个复选框。如果您想处理更多操作,您可以订阅 SelectionChanged 事件。带有标准复选框的示例 ListView:
<ListView Name="myList" SelectionChanged="myList_SelectionChanged" SelectionMode="Multiple">
<ListView.Items>
<TextBlock Text="First item"/>
<TextBlock Text="Second item"/>
<TextBlock Text="Third item"/>
<TextBlock Text="Fifth item"/>
</ListView.Items>
</ListView>
在你的代码中,我很难说出什么问题,因为我看不到你的项目 class,我不知道你是否 属性 Selected,它是否实现了 INotifyPropertyChanged 和更多小东西。
我的 UWP 应用在用户控件中带有 XAML 列表视图,如下所示。
<ListView x:Name="lvDevices"
Margin="12,8,0,0"
Grid.Row="4"
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource DeviceTemplate}"
Width="Auto"
ItemsSource="{Binding Devices}"
IsItemClickEnabled="True"
ItemClick="lvDevices_ItemClick"
d:DataContext="{d:DesignData /SampleData/DevicesVMSampleData.xaml}" >
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
列表视图的项目模板如下。您可以看到项目模板有一个复选框,它使用两种方式绑定到我的视图模型。
<DataTemplate x:Key="DeviceTemplate">
<Grid Margin="0" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox x:Name="chkSelected" IsChecked="{Binding Selected, Mode=TwoWay}" MinWidth="32" Grid.Column="0" Checked="chkSelected_Changed" Unchecked="chkSelected_Changed" />
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="10,0,0,0">
<TextBlock Text="{Binding DeviceName}" Style="{StaticResource TitleTextBlockStyle}" Tag="{Binding ID}" TextWrapping="Wrap" MaxWidth="500"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="User:" Margin="0,0,10,0" Style="{StaticResource CaptionTextBlockStyle}" FontWeight="Bold" />
<TextBlock Text="{Binding User}" Style="{StaticResource CaptionTextBlockStyle}" TextWrapping="NoWrap"/>
</StackPanel>
</StackPanel>
<Button x:Name="btnInfo" Grid.Column="2" Background="Transparent" HorizontalAlignment="Right">
<Image x:Name="imgInfo" HorizontalAlignment="Right" VerticalAlignment="Center" Source="/Assets/InfoIcon-100.png" Height="50" Width="50" />
</Button>
</Grid>
</DataTemplate>
列表视图的数据上下文设置为我的视图模型。
ucDeviceInfo.DataContext = iobj_DevicesViewModel;
所以我想要的是当用户单击列表视图中的某个项目时,该项目的复选框更新为带有复选标记或删除其复选标记。我认为最好的方法是在用户单击该行时将 ViewModel 中的 'Selected' 属性 设置为 true 或 false,然后通知视图 属性 已更改. (项目列表是一个可观察的集合。)。
我尝试通过以下方式完成此操作:
在 UserControl 中 - 当用户单击一行时,我使用以下代码在基页中调用一个方法:
private void lvDevices_ItemClick(object sender, ItemClickEventArgs e)
{
StartPage lobj_ParentForm;
lobj_ParentForm = ((StartPage)((Frame)Window.Current.Content).Content);
lobj_ParentForm.SendNotifyPropertyChanged( ((Device)e.ClickedItem).ID);
}
在基本页面中,我使用以下代码在我的 ViewModel 中调用了一个方法:
public void SendNotifyPropertyChanged(int pi_DeviceID)
{
iobj_DevicesViewModel.DeviceSelectedInListView(pi_DeviceID);
}
然后在视图模型中,我为设备更新了选定的 属性 并使用以下代码调用通知 属性 已更改的函数:
public void DeviceSelectedInListView(int pi_DeviceID)
{
Device lobj_SelectedDevice;
lobj_SelectedDevice = (from lobj_Device in Devices
where lobj_Device.ID == pi_DeviceID
select lobj_Device).ToList<Device>()[0];
lobj_SelectedDevice.Selected = !lobj_SelectedDevice.Selected;
NotifyPropertyChanged("Devices");
SelectionsChanged();
}
public void SelectionsChanged()
{
NotifyPropertyChanged("SelectedDeviceCount");
}
挑战在于,当我这样做并调用 notify 属性 changed 方法时,我刚刚单击的列表视图中项目的复选框没有更新。知道当用户单击列表视图中的一行时如何让复选框正确更新吗?
Link 说明此问题的示例项目是 Example Code
至于你的代码 - 你几乎已经做对了。您的集合引用 Devices
不会更改,因此绑定不会更新整个集合,您也不会 add/remove 元素,因此 ObservableCollection 可能已经更新。在这种情况下,您需要调用 属性 changed on item's class。为此,只需在设备 class:
public class Device : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaiseProperty(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
private bool selected;
public bool Selected
{
get { return selected; }
set { selected = value; RaiseProperty(nameof(Selected)); }
}
// rest of the class
在此之后,您也不需要每次在项目内部发生变化时调用 NotifyPropertyChanged("Devices");
,绑定将完成这项工作。因为你有 ObservableCollection 我认为你根本不需要调用它。
The modified sample you have shared.
我不太清楚您为什么不使用默认的 ListView 复选框。如果您将选择模式设置为 Multiple 那么您将在每个项目上看到一个复选框。如果您想处理更多操作,您可以订阅 SelectionChanged 事件。带有标准复选框的示例 ListView:
<ListView Name="myList" SelectionChanged="myList_SelectionChanged" SelectionMode="Multiple">
<ListView.Items>
<TextBlock Text="First item"/>
<TextBlock Text="Second item"/>
<TextBlock Text="Third item"/>
<TextBlock Text="Fifth item"/>
</ListView.Items>
</ListView>
在你的代码中,我很难说出什么问题,因为我看不到你的项目 class,我不知道你是否 属性 Selected,它是否实现了 INotifyPropertyChanged 和更多小东西。