I have an listview in my xaml
that i populate with items like this:
List<DataLayer.Models.Dictionary> dicts = DataLayer.Manager.getDictionaries();
if (dicts != null)
{
foreach (DataLayer.Models.Dictionary dict in dicts)
{
this.itemListView.Items.Add(dict);
}
}
My DataLayer.Models.Dictionary
object have an isSelected
property along with a Name
and a SubName
.
Name and SubName works fine in the template but how can i go about getting the item to be selected and also updated when user clicks an item?
Thanks!
Edit:
My xaml now looks like this, but the item is still not selected
<ListView
x:Name="itemListView"
TabIndex="1"
Grid.Row="1"
Margin="0,60,0,0"
Padding="0,0,0,0"
IsSwipeEnabled="False"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
SelectionChanged="itemListView_SelectionChanged_1"
SelectionMode="Multiple"
FontFamily="Global User Interface">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding Source=Selected,Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="0,0,0,0">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding SubName}" Style="{StaticResource CaptionTextStyle}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
[Edit]
Just noticed this question isn't actually tagged WPF; but I hopefully it still applies.
WPF is inherently MVVM. Directly manipulating controls in code behind is generally not a good idea. So it is advised to create a "view-friendly" model called a ViewModel; See Here. Also for bindings to be of any use, in a changing environment, you must inform of changes to properties and or collections, so that controls can be updated.
First and formost you have a collection of dictionaries, So you create this collection such that it can notify of changes; ObservableCollection can do that. As a general rule of thumb any collection used by WPF you should just use an ObservableCollection, and/or derive from it.
so here is compete working example:
Bare in mind I'm using FODY to inject my PropertyChanged raisers; See done manually
public class Dict : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public string Name { get; set; }
public string SubName { get; set; }
public bool Selected { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Dict> Dictionaries { get; set; }
public ViewModel()
{
Dictionaries = new ObservableCollection<Dict>()
{
new Dict()
{
Name = "English",
SubName = "en",
Selected = false,
},
new Dict()
{
Name = "English-British",
SubName = "en-uk",
Selected = true
},
new Dict()
{
Name = "French",
SubName = "fr",
Selected = true
}
};
Dictionaries.CollectionChanged += DictionariesCollectionChanged;
}
private void DictionariesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch(e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach(var dict in e.NewItems.Cast<Dict>())
dict.PropertyChanged += DictionaryChanged;
break;
case NotifyCollectionChangedAction.Remove:
foreach (var dict in e.OldItems.Cast<Dict>())
dict.PropertyChanged -= DictionaryChanged;
break;
}
}
private void DictionaryChanged(object sender, PropertyChangedEventArgs e)
{
Dict dictionary = (Dict)sender;
//handle a change in Dictionary
}
}
With this you can add or remove objects at any time, although here I am just initializing them in the constructor.
Then you would have this in your window or control. I've included the namespaces to make it more self-contained; but this would be for WPF namespaces.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1">
<Window.Resources>
<local:ViewModel x:Key="viewmodel"/>
</Window.Resources>
<ListView
x:Name="itemListView"
DataContext="{StaticResource ResourceKey=viewmodel}"
ItemsSource="{Binding Path=Dictionaries}"
SelectionMode="Multiple">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding Path=Selected, Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="0,0,0,0">
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding SubName}" TextWrapping="Wrap"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Window>
If you don't use ObservableCollection for your collection, then start adding elements to it after WPF has be loaded-up, it will never notify the binding manager that the ListView should be updated.
The above on start up:
you can easily see that the underlying Dictionaries collection is being changed (i.e.its not just the ListView), by overriding the returned value from selected:
public bool Selected { get { return true; } set {/* do nothing*/ }}
Which means everything is always selected, even if you try to deselect it in the view. It will always look like this:
Styling is a different issue, the list looks different if it doesn't have focus. See Here
Now reacting to selection changes could be done in the code-behind, but that would be mixing logic with view.
[Edit] updated to include ability to detect changes in any Dict (including when selected changes)
You could look into this to simplify it
Hope this helps.