MVVM light listview selecteditem - wpf

How can I get the selecteditem from my listview in mvvm light wpf?
I have a collection and created a selected item property but I cant get the binding right for the selected item.
This is my viewmodel:
ObservableCollection<DTO.Dossier.Dossier> _dossiers;
public ObservableCollection<DTO.Dossier.Dossier> Dossiers
{
get { return _dossiers; }
set
{
_dossiers = value;
RaisePropertyChanged("Dossiers");
}
}
private DTO.Dossier.Dossier _selectedDossier;
public DTO.Dossier.Dossier SelectedDossier
{
get { return _selectedDossier; }
set
{
if (_selectedDossier != value)
_selectedDossier = value;
RaisePropertyChanged("SelectedDossier");
}
}
And this is the xaml for the listview:
<ListView ItemsSource="{Binding Dossiers}" Margin="0,5,0,0" Name="LstDossiers" SelectedItem="{Binding SelectedDossier, Mode=OneWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding SelectDossierCommand}"
CommandParameter="{Binding SelectedDossier,
ElementName=LstDossiers}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View>
<GridView>
<GridViewColumn Header="Id"
DisplayMemberBinding="{Binding Id}" />
<GridViewColumn Header="Omschrijving"
DisplayMemberBinding="{Binding Omschrijving}" />
</GridView>
</ListView.View>
</ListView>
The command is working but the binding to the SelectedDossier isn't.

You have to use mode TwoWay in your binding:
<ListView ItemsSource="{Binding Dossiers}" Margin="0,5,0,0" Name="LstDossiers" SelectedItem="{Binding SelectedDossier, Mode=TwoWay}">

Related

ListView isn't working properly with ObservableCollection

Here's the code I'm working with. In xaml I've expanded the ListView like this:
<ListView x:Name="lv" ItemsSource="{Binding}">
<ListView.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding Edit}" CommandParameter="{Binding SelectedItem, ElementName=lv}"/>
<KeyBinding Key="Return" Command="{Binding Edit}" CommandParameter="{Binding SelectedItem, ElementName=lv}"/>
</ListView.InputBindings>
</ListView>
and implemented INotifyPropertyChanged in Master class to see updates in ListView when I edit an item. In Person class I've added one more Command
public Command Edit { get; set; }
intialized it in constructior:
Edit = new Command(CanClick, EditItem);
and implemented those callbacks like this:
bool CanClick(object arg) => Count > 0;
void EditItem(object obj) {
if(obj != null{
var item = obj as Master;
item.FirstName = "Edited";
item.LastName = "Edited";
SetItem(IndexOf(item), item);
}
}
When I select an item and hit Return it updates the collection BUT I don't see any change in ListView. If I double click on an item, it neither updates the collection nor the ListView!
Another question is why do I have to set a name for the ListView to use in nested InputBindings like this ElementName=lv? Can I get rid of that?
EDIT
If I expand the ListView further like this:
<ListView x:Name="lv" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" Width="200"
DisplayMemberBinding="{Binding FirstName}"/>
<GridViewColumn Header="Last Name" Width="200"
DisplayMemberBinding="{Binding LastName}" />
</GridView>
</ListView.View>
<ListView.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick" Command="{Binding Edit}" CommandParameter="{Binding SelectedItem, ElementName=lv}"/>
<KeyBinding Key="Return" Command="{Binding Edit}" CommandParameter="{Binding SelectedItem, ElementName=lv}"/>
</ListView.InputBindings>
</ListView>
ListView reflects the update I make through void EditItem(object obj) BUT MouseBinding doesn't work in this way either. Why would one bind individual property like this for a collection?
There is no reason to call SetItem to update an item.
Setting the properties is enough provided that the Master class implements INotifyPropertyChanged correctly.
When it comes to handling double-clicks, you could add a reference to System.Windows.Interactivity and use an EventTrigger:
<ListView x:Name="lv" ItemsSource="{Binding}" xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding Edit}" CommandParameter="{Binding SelectedItem, ElementName=lv}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" Width="200" DisplayMemberBinding="{Binding FirstName}"/>
<GridViewColumn Header="Last Name" Width="200" DisplayMemberBinding="{Binding LastName}" />
</GridView>
</ListView.View>
</ListView>

WPF - Different SelectedValues in different GridViewColumns?

I have 12 Properties and I want to bind each of them to one GridViewColumn in a ListView. They contain an ID (string) and look like the following:
//DAR01
public static readonly PropertyInfo<string> DAR01Property = RegisterProperty<string>(p => p.DAR01);
/// <summary>
///Date type
/// </summary>
public string DAR01
{
get { return GetProperty( DAR01Property); }
set { SetProperty(DAR01Property, value); }
}
I also have a Key-Table in my database which contains a key and a description, which I already have in my Code-Behind:
public System.Collections.Generic.IEnumerable<AOK.NW.Beihilfe.Customizing.Schluessel> PlanungsdatenSchluessel
{
get
{
System.Collections.Generic.IEnumerable<AOK.NW.Beihilfe.Customizing.Schluessel> SchluessellistePlanungsdaten = Schluesselliste.GetSchluesselliste().Where<Schluessel>(x => x.Gruppe == "T548T");
return SchluessellistePlanungsdaten;
}
}
Basically the easiest way to explain what I want are these following ComboBoxes, but in a GridView with multiple GridViewColumns which have different Bindings:
<ComboBox Grid.Row="2" Grid.Column="1" Width="Auto"
ItemsSource="{Binding Path=PlanungsdatenSchluessel}"
DisplayMemberPath="Beschreibung"
SelectedValuePath="Id"
SelectedValue="{Binding Path=CurrentDate.DAR01}"
IsEnabled="{Binding Path=IsBearbeiten}"/>
<ComboBox Grid.Row="3" Grid.Column="1" Width="Auto"
ItemsSource="{Binding Path=PlanungsdatenSchluessel}"
DisplayMemberPath="Beschreibung"
SelectedValuePath="Id"
SelectedValue="{Binding Path=CurrentDate.DAR02}"
IsEnabled="{Binding Path=IsBearbeiten}"/>
[...]
My GridViewColumns (goes up to DAR12):
<ListView Grid.Row="0"
ItemsSource="{Binding Path=Person.Planungsdaten}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedItem}"
MaxHeight="580" Height="Auto"
Width="Auto"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Path=DAR01}">
<GridViewColumnHeader Name="DAR01" Content="Datentyp 01"/>
</GridViewColumn>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Path=DAR02}">
<GridViewColumnHeader Name="DAR02" Content="Datentyp 02"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Any ideas how I can achieve that? I am grateful for any tip!

Binding a Combobox inside a ListView

I have a combobox in a ListView that I can bind to an itemsource. When selecting a value in the combobox, my selected item is not getting set. Can someone show me why my selected item (NumberOfIterations) is not getting set? The combobox works when I move it outside the ListView, making me thinkg that I do not have the binding completely correct, but I cannot figure out what is wrong. I use the SimpleMVVMToolkit framework.
<ListView Grid.Row="1" Grid.Column="2"
ItemsSource="{Binding SequenceListItems}"
SelectedItem="{Binding SequenceListItemSelected}"
ItemContainerStyle="{StaticResource alternatingListViewItemStyle}"
AlternationCount="2">
<ListView.View>
<GridView>
<GridViewColumn Header="# of Iterations" Width="125">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<ComboBox ItemsSource="{Binding
SequenceEditorViewModel.Iterations, Source={StaticResource ViewModelLocator}}"
SelectedItem="{Binding Path=NumberOfIterations, Mode=TwoWay}" SelectedIndex="0"
FontWeight="Bold" VerticalAlignment="Center" Width="60" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
ViewModel Items...I am not using a Model at this time
// Constructor
public SequenceEditorViewModel()
{
// Populate the Iterations for displaying in the combobox in the gridview.
for (int x = 1; x <= 50; x++)
{
this.Iterations.Add(x);
}
}
//public property (Iterations is source for combobox and NumberOfIterations
//is for the selected item in the combobox)
public ObservableCollection<int> Iterations
{
get
{
return this.iterations;
}
set
{
this.iterations = value;
this.NotifyPropertyChanged(m => m.Iterations);
}
}
public int NumberOfIterations
{
get
{
return this.numberOfIterations;
}
set
{
this.numberOfIterations = value;
this.NotifyPropertyChanged(m => m.NumberOfIterations);
}
}

How to set SelectedItem in listview control?

I have UserControl(AllCustomerView) in project and its Viewmodel as ALlCustomerViewModel consists a property as SearchText.
SearchText is selected value for TextBox inside a listview in UserControl.
SearchItem is set as customerViewmdel for SearchText.
But in listview , SearchItem is not set as selected
in AllCustomerView.xaml
<TextBlock>
<TextBox
Width="150"
Text="{Binding Path=SearchText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
</TextBox>
<Button
Command="{Binding Path=SearchCommand}"
Content=" Search ">
</Button>
</TextBlock>
<ListView
SelectedValue="{Binding Path=SearchText}"
ItemsSource="{Binding Path=AllCustomers}"
FontFamily="Tahoma"
FontSize="14"
ItemContainerStyle="{StaticResource CustomerItemStyle}"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button
Command="{Binding ElementName=Root, Path=DataContext.DeleteCommand}"
Content="x"
FontFamily="Tahoma"
FontSize="10"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button
FontFamily="Tahoma"
FontSize="10"
Content="Edit"
Command="{Binding Path=DataContext.Editcommand,ElementName=Root}"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn
Header="CustomerID"
Width="130"
DisplayMemberBinding="{Binding Path=CustomerID}"/>
<GridViewColumn
Header="Contact Name"
Width="130"
DisplayMemberBinding="{Binding Path=ContactName}"/>
<GridViewColumn
Header="Company Name"
Width="130"
DisplayMemberBinding="{Binding Path=CompanyName}"/>
<GridViewColumn
Width="130"
Header="Contact Name"
DisplayMemberBinding="{Binding Path=ContactTitle}"
/>
</GridView>
</ListView.View>
</ListView>
and its viewmodel(AllcustomerViewModel.cs)
public ICommand SearchCommand
{
get
{
if (_search == null)
_search = new Relaycommand(SearchCustomer);
return _search;
}
}
public void SearchCustomer(object o)
{
System.Windows.Forms.MessageBox.Show(SearchItem.ToString());
}
public string searchText;
public string SearchText
{
get { return searchText; }
set
{
searchText = value;
var customerExsits = AllCustomers.Where(q => q.CustomerID.Trim().Equals(searchText));
if (customerExsits.Any())
{
SearchItem = customerExsits.Single();
}
}
}
public CustomerViewModel SearchItem
{
get;
set;
}
what should i set in SelectedValue in ListView, whether to set Customerviewmodel(as SelectedItem) or to set CustomerID(as SearchText)?
You should do the following:
Use this binding in your ListView: SelectedItem="{Binding Path=SearchItem }". Don't use SelectedValue.
Implement INotifyPropertyChanged in your ViewModel and raise the PropertyChanged event in the setter of the SearchItem property. Obviously, you need to change this property from an automatic one to a classical one with a backing field:
public CustomerViewModel SearchItem
{
get { return _searchItem; }
set
{
if(value == _searchItem)
return;
_searchItem = value;
RaisePropertyChanged("SearchItem");
}
}

WPF Sortable Listview with Checkbox in MVVM pattern

I have a WPF ListView with checkbox in MVVM pattern. I need to accomplish the following two tasks.
1) Sort by any column when I click on column header. If column is already in ascending order then it should reorder in descending and vice versa.
2) SelectedTaskItem is not communicating with ViewModel when i check or uncheck a checkbox.
TaskView.xaml
<UserControl x:Class="MyProject.TaskView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="569" Width="954"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
>
<UserControl.Resources>
<DataTemplate x:Key="FirstCellCheckBox">
<CheckBox
Command="{Binding IsSelected, Mode= TwoWay}"
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type ListViewItem}}}"
CommandParameter="{Binding Path=SelectedTaskItem,
ElementName=dgTaskList, UpdateSourceTrigger=PropertyChanged}"
/>
</DataTemplate>
</UserControl.Resources>
<ListView Grid.Row="1"
Name="ListViewTask"
Margin="12,49,26,79"
ItemsSource="{Binding TaskList}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
>
<ListView.View >
<GridView x:Name="gvTaskList">
<GridViewColumn Header="Select"
CellTemplate="{StaticResource FirstCellCheckBox}"
Width="30"/>
<GridViewColumn Header="Internal File"
DisplayMemberBinding="{Binding TaskID}"
Width="100"/>
<GridViewColumn Header="TaskDescription"
DisplayMemberBinding="{Binding TaskDescription}"
Width="100" />
<GridViewColumn Header="Task Status"
DisplayMemberBinding="{Binding TaskStatus}"
Width="100" />
</GridView>
</ListView.View>
</ListView>
TaskViewModel.cs
namespace MyProject
{
public class TaskViewModel: ViewModelBase
{
ObservableCollection<TaskModel> _TaskList;
public TaskViewModel()
{
TaskDAO dal = new TaskDAO();
_TaskList= dal.GetUpFileList();
}
public ObservableCollection<TaskModel> TaskList
{
get { return _TaskList; }
set
{
if (_TaskList!= value)
{
this._TaskList= value;
this.OnPropertyChanged("TaskList");
}
}
}
private TaskModel _selectedTaskItem;
public TaskModel SelectedTaskItem
{
get { return _selectedTaskItem; }
set
{
if (value != null)
{
_selectedTaskItem= value;
OnPropertyChanged("SelectedTaskItem");
if (null != _selectedTaskItem)
{
ObservableCollection<TaskModel> oCol =
new ObservableCollection<TaskModel>();
foreach (TaskModel itm in TaskList)
{
if (itm.TaskID == _selectedTaskItem.TaskID)
{
itm.IsSelected = true;
}
oCol.Add(itm);
}
TaskList.Clear();
TaskList = oCol;
OnPropertyChanged("TaskList");
}
}
}
}
}
You are binding the CheckBox's IsChecked value to ListBoxItem.IsChecked, but I don't see anything that binds ListBoxItem.IsChecked to your ViewModel.
Try adding the following to your ListBox.Resources
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
For sorting, I'd recommend using a DataGrid instead of a ListView, since sorting is built into the DataGrid. If you don't want to do that, you'll probably have to make some custom ListViewHeaders which execute a SortCommand in your ViewModel

Resources