template wpf listview

template - wpf listview grouping



WPF ListView: detecta cuando se hace clic en el elemento seleccionado (4)

Estas son todas excelentes sugerencias, pero si fuera usted, lo haría en su modelo de vista. Dentro de su modelo de vista, puede crear un comando de retransmisión que luego puede vincular al evento de clic en su plantilla de elemento. Para determinar si se seleccionó el mismo elemento, puede almacenar una referencia al elemento seleccionado en su modelo de vista. Me gusta usar MVVM Light para manejar el enlace. Esto hace que su proyecto sea mucho más fácil de modificar en el futuro, y le permite configurar el enlace en Blend.

Cuando todo está dicho y hecho, su XAML se verá como lo sugirió Sergey. Evitaría usar el código en tu vista. Voy a evitar escribir código en esta respuesta, porque hay un montón de ejemplos por ahí.

Aquí hay una: cómo usar RelayCommand con el marco de MVVM Light

Si necesita un ejemplo, por favor comenten, y agregaré uno.

~ Saludos

Dije que no iba a dar un ejemplo, pero lo estoy haciendo. Aqui tienes.

1) En su proyecto, agregue MVVM Light Libraries solamente.

2) Crea una clase para tu vista. En general, tiene un modelo de vista para cada vista (ver: MainWindow.xaml && viewModel: MainWindowViewModel.cs)

3) Aquí está el código para el modelo de vista muy, muy, muy básico:

Todo el espacio de nombres incluido (si aparecen aquí, supongo que ya has agregado la referencia. MVVM Light está en 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;

Ahora agregue una clase pública básica:

/// <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; } }

Ahora crea tu 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); } } }

En su modelo de vista, agregue un comando de retransmisión. Tenga en cuenta que hice este asincrónico y lo hice pasar un parámetro.

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); }

En el código que está detrás de su vista, cree una propiedad para su modelo de vista y establezca el contexto de datos para su vista en el modelo de vista (tenga en cuenta que hay otras maneras de hacerlo, pero estoy tratando de hacer de este un simple ejemplo).

public partial class MainWindow : Window { public MainWindowViewModel MyViewModel { get; set; } public MainWindow() { InitializeComponent(); MyViewModel = new MainWindowViewModel(); this.DataContext = MyViewModel; } }

En su XAML, necesita agregar algunos espacios de nombres a la parte superior de su código

<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">

Agregué "i" y "Custom".

Aquí está el ListView:

<ListView Grid.Row="0" Grid.Column="0" HorizontalContentAlignment="Stretch" ItemsSource="{Binding ModelsCollection}" ItemTemplate="{DynamicResource BasicModelDataTemplate}"> </ListView>

Aquí está el ItemTemplate para ListView:

<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>

Ejecute su aplicación y revise la ventana de salida. Puede usar un convertidor para manejar el estilo del elemento seleccionado.

Esto puede parecer realmente complicado, pero hace la vida mucho más fácil en el futuro cuando necesita separar su vista de su ViewModel (por ejemplo, desarrollar un ViewModel para múltiples plataformas). Además, hace que trabajar en Blend 10x sea más fácil. Una vez que desarrolle su ViewModel, puede entregarlo a un diseñador que puede hacer que se vea muy artístico :). MVVM Light agrega algunas funcionalidades para que Blend reconozca su ViewModel. En su mayor parte, puede hacer prácticamente todo lo que desee en ViewModel para afectar la vista.

Si alguien lee esto, espero que encuentre esto útil. Si tiene preguntas, hágamelo saber. Usé MVVM Light en este ejemplo, pero podrías hacer esto sin MVVM Light.

~ Saludos

Estoy usando un control ListView de WPF que muestra una lista de elementos de datos.

<ListView ItemsSource={Binding MyItems}> <ListView.View> <GridView> <!-- declare a GridViewColumn for each property --> </GridView> </ListView.View> </ListView>

Intento obtener un comportamiento similar al evento ListView.SelectionChanged , solo quiero también detectar si se hace clic en el elemento seleccionado actualmente. El evento SelectionChanged no se activa si se vuelve a hacer clic en el mismo elemento (obviamente).

¿Cuál sería la mejor (más limpia) forma de abordar esto?


Puede manejar el evento PreviewMouseLeftButtonUp de ListView. La razón para no manejar el evento PreviewMouseLeftButtonDown es que, en el momento en que maneja el evento, el SelectedItem de ListView aún puede ser nulo.

XAML:

<ListView ... PreviewMouseLeftButtonUp="listView_Click"> ...

Código detrás:

private void listView_Click(object sender, RoutedEventArgs e) { var item = (sender as ListView).SelectedItem; if (item != null) { ... } }


Puede manejar hacer clic en un elemento de vista de lista como este:

<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"> ...


Use la propiedad ListView.ItemContainerStyle para darle a su ListViewItems un EventSetter que manejará el evento PreviewMouseLeftButtonDown. Luego, en el controlador, verifique si el elemento en el que se hizo clic está seleccionado.

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>

Código detrás:

private void ListViewItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var item = sender as ListViewItem; if (item != null && item.IsSelected) { //Do your stuff } }