我正在使用WPF ListView控件,它显示数据绑定项的列表.
<ListView ItemsSource={Binding MyItems}>
<ListView.View>
<GridView>
<!-- declare a GridViewColumn for each property -->
</GridView>
</ListView.View>
</ListView>
Run Code Online (Sandbox Code Playgroud)
我正在尝试获取与ListView.SelectionChanged事件类似的行为,只是我还要检测是否单击了当前选定的项目.SelectionChanged如果再次点击相同的项目(显然),则不会触发该事件.
什么是最好(最干净)的方法来解决这个问题?
Chi*_*ura 69
使用ListView.ItemContainerStyle属性为ListViewItems提供一个EventSetter,它将处理PreviewMouseLeftButtonDown事件.然后,在处理程序中,检查是否选中了单击的项目.
XAML:
<ListView ItemsSource={Binding MyItems}>
<ListView.View>
<GridView>
<!-- declare a GridViewColumn for each property -->
</GridView>
</ListView.View>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListViewItem_PreviewMouseLeftButtonDown" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
Run Code Online (Sandbox Code Playgroud)
代码隐藏:
private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var item = sender as ListViewItem;
if (item != null && item.IsSelected)
{
//Do your stuff
}
}
Run Code Online (Sandbox Code Playgroud)
lzn*_*znt 21
您可以处理ListView的PreviewMouseLeftButtonUp事件.不处理PreviewMouseLeftButtonDown事件的原因是,当您处理事件时,ListView的SelectedItem可能仍为null.
XAML:
<ListView ... PreviewMouseLeftButtonUp="listView_Click"> ...
Run Code Online (Sandbox Code Playgroud)
代码背后:
private void listView_Click(object sender, RoutedEventArgs e)
{
var item = (sender as ListView).SelectedItem;
if (item != null)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
Rog*_*ala 16
这些都是很棒的建议,但如果我是你,我会在你的视图模型中做到这一点.在视图模型中,您可以创建一个中继命令,然后可以将其绑定到项模板中的单击事件.要确定是否选择了相同的项目,您可以在视图模型中存储对所选项目的引用.我喜欢使用MVVM Light来处理绑定.这使您的项目将来更容易修改,并允许您在Blend中设置绑定.
完成所有操作后,您的XAML将看起来像谢尔盖建议的那样.我会避免在你的视图中使用后面的代码.我将避免在这个答案中编写代码,因为那里有大量的例子.
这是一个: 如何将RelayCommand与MVVM Light框架一起使用
如果您需要一个示例,请发表评论,我将添加一个.
〜干杯
我说我不会做一个例子,但我是.干得好.
1)在您的项目中,仅添加MVVM Light Libraries.
2)为您的视图创建一个类.一般来说,每个视图都有一个视图模型(视图:MainWindow.xaml && viewModel:MainWindowViewModel.cs)
3)以下是非常非常非常基本的视图模型的代码:
所有包含的命名空间(如果它们出现在这里,我假设你已经添加了对它们的引用.MVVM Light在Nuget中)
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
Run Code Online (Sandbox Code Playgroud)
现在添加一个基本的公共类:
/// <summary>
/// Very basic model for example
/// </summary>
public class BasicModel
{
public string Id { get; set; }
public string Text { get; set; }
/// <summary>
/// Constructor
/// </summary>
/// <param name="text"></param>
public BasicModel(string text)
{
this.Id = Guid.NewGuid().ToString();
this.Text = text;
}
}
Run Code Online (Sandbox Code Playgroud)
现在创建你的viewmodel:
public class MainWindowViewModel : ViewModelBase
{
public MainWindowViewModel()
{
ModelsCollection = new ObservableCollection<BasicModel>(new List<BasicModel>() {
new BasicModel("Model one")
, new BasicModel("Model two")
, new BasicModel("Model three")
});
}
private BasicModel _selectedBasicModel;
/// <summary>
/// Stores the selected mode.
/// </summary>
/// <remarks>This is just an example, may be different.</remarks>
public BasicModel SelectedBasicModel
{
get { return _selectedBasicModel; }
set { Set(() => SelectedBasicModel, ref _selectedBasicModel, value); }
}
private ObservableCollection<BasicModel> _modelsCollection;
/// <summary>
/// List to bind to
/// </summary>
public ObservableCollection<BasicModel> ModelsCollection
{
get { return _modelsCollection; }
set { Set(() => ModelsCollection, ref _modelsCollection, value); }
}
}
Run Code Online (Sandbox Code Playgroud)
在viewmodel中,添加relaycommand.请注意,我做了这个异步并让它传递参数.
private RelayCommand<string> _selectItemRelayCommand;
/// <summary>
/// Relay command associated with the selection of an item in the observablecollection
/// </summary>
public RelayCommand<string> SelectItemRelayCommand
{
get
{
if (_selectItemRelayCommand == null)
{
_selectItemRelayCommand = new RelayCommand<string>(async (id) =>
{
await selectItem(id);
});
}
return _selectItemRelayCommand;
}
set { _selectItemRelayCommand = value; }
}
/// <summary>
/// I went with async in case you sub is a long task, and you don't want to lock you UI
/// </summary>
/// <returns></returns>
private async Task<int> selectItem(string id)
{
this.SelectedBasicModel = ModelsCollection.FirstOrDefault(x => x.Id == id);
Console.WriteLine(String.Concat("You just clicked:", SelectedBasicModel.Text));
//Do async work
return await Task.FromResult(1);
}
Run Code Online (Sandbox Code Playgroud)
在您查看的代码中,为您的viewmodel创建一个属性,并将视图的datacontext设置为viewmodel(请注意,还有其他方法可以执行此操作,但我尝试将此作为一个简单的示例.)
public partial class MainWindow : Window
{
public MainWindowViewModel MyViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
MyViewModel = new MainWindowViewModel();
this.DataContext = MyViewModel;
}
}
Run Code Online (Sandbox Code Playgroud)
在您的XAML中,您需要在代码顶部添加一些名称空间
<Window x:Class="Basic_Binding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Custom="clr-namespace:GalaSoft.MvvmLight;assembly=GalaSoft.MvvmLight"
Title="MainWindow" Height="350" Width="525">
Run Code Online (Sandbox Code Playgroud)
我添加了"i"和"Custom".
这是ListView:
<ListView
Grid.Row="0"
Grid.Column="0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding ModelsCollection}"
ItemTemplate="{DynamicResource BasicModelDataTemplate}">
</ListView>
Run Code Online (Sandbox Code Playgroud)
这是ListView的ItemTemplate:
<DataTemplate x:Key="BasicModelDataTemplate">
<Grid>
<TextBlock Text="{Binding Text}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<i:InvokeCommandAction
Command="{Binding DataContext.SelectItemRelayCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding Id}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</Grid>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)
运行您的应用程序,并检查输出窗口.您可以使用转换器来处理所选项目的样式.
这可能看起来非常复杂,但是当您需要将视图与ViewModel分开时(例如,为多个平台开发ViewModel),它会使生活变得更加轻松.此外,它使Blend 10x中的工作更容易.一旦你开发了ViewModel,你就可以把它交给一个能让它看起来很有艺术气息的设计师:).MVVM Light增加了一些功能,使Blend能够识别您的ViewModel.在大多数情况下,您可以在ViewModel中执行您想要的所有操作以影响视图.
如果有人读到这个,我希望你觉得这很有帮助.如果您有任何疑问,请告诉我.我在这个例子中使用了MVVM Light,但你可以在没有MVVM Light的情况下做到这一点.
〜干杯
小智 6
您可以像这样处理单击列表视图项:
<ListView.ItemTemplate>
<DataTemplate>
<Button BorderBrush="Transparent" Background="Transparent" Focusable="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding DataContext.MyCommand, ElementName=ListViewName}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Button.Template>
<ControlTemplate>
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
...
Run Code Online (Sandbox Code Playgroud)