If I were to say "the heck with it!", I could just give my ListView with SelectionMode="Multiple" a name, and be able to get all of the selected items very easily. But I'm trying to stick to MVVM as much as possible, and I want to somehow databind to an ObservableCollection that holds the value from the Name column for each selected item. How in the world do you do this? Single selection is simple, but the multi selection solution is not obvious to me with my current WPF / MVVM knowledge.
I read this question on SO, and while it does give me some good insight, I don't know how to add the necessary binding to a row, because I am using a ListView with a GridView as its View, not a ListBox.
Here's what my XAML basically looks like:
<ListView DockPanel.Dock="Top" ItemsSource="{Binding ClientPreview}" SelectionMode="Multiple">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Address">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Address}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
It sounds like the right thing to do is to databind each row's IsSelected property to each object stored in the ObservableCollection I'm databinding to. I just haven't figured out how to do this.
Write ItemContainerstyle on the ListView and put a Setter to do the binding to your ViewModel 'IsSelected' property
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected,Mode=OneWayToSource}"/>
Related
I'm new to MVVM. I created a TreeView with hierarchy of 3 levels: level1: Program, level2: Action, level3: Position. I also created a ListView under the TreeView (see xaml) . Right now the items of the ListView are not bound to anything (the names "Type", "Speed" are only placeholders.)
When selecting an item from level2 (Action) in the TreeView, i'd like to see it's properties (type, speed) appear on the ListView below.
Is there a way to do it through a change in the View only (xaml), without using code in the ViewModel ? maybe there's a way to use a certain binding, that can be changed when pressing on the item in the TreeView?
xaml (model):
<TreeView
Grid.Row="0"
x:Name="MainTreeView"
HorizontalAlignment="Stretch"
Margin="10"
VerticalAlignment="Stretch"
ItemsSource="{Binding Programs}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Actions}" DataType="{x:Type VM:ProgramVM}">
<Label Content="{Binding ProgramName}"/>
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Poses}" DataType="{x:Type VM:ActionVM}">
<Label Content="{Binding Actiontype}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type VM:PositionVM}">
<Label Content="{Binding PosName}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListView Grid.Row="1" Margin="10" Name="lvUsers">
<ListView.View>
<GridView>
<GridViewColumn Header="Type" Width="100" DisplayMemberBinding="{Binding Type}" />
<GridViewColumn Header="Speed" Width="100" DisplayMemberBinding="{Binding Speed}" />
</GridView>
</ListView.View>
</ListView>
This is a well known issue with the treeview in WPF. You have to create an 'is selected' property for each object in your tree so that you know what the user has chosen, then you can just show the selected object in your listview.
It's been a while since I played with a treeview, but here are some of the links that I think helped me in the past.
Data binding to SelectedItem in a WPF Treeview
WPF MVVM TreeView SelectedItem
I am trying to create a ListView with a GridView that has 2 columns: Name and Date, which are to be binded to a Person Object later on.
I want to use a DataTemplate, this template consists of a Label.
My problem is I want to use this template for both columns, but the content of the label is to be bind to a different property in each column. In short, I want to be able to bind the content of the label, in the GridViewColumn code block and not in the DataTemplate code block.
Thanks in advance for your help.
I tried it this way with empty binding in datatemplate which solved in my case..(didn't checked for object types with more than one property to be binded). This will work in the case of this question's context.
<DataTemplate x:Key="commonTemplate">
<Label Content="{Binding}" />
</DataTemplate>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Name}"
ContentTemplate="{StaticResource commonTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Date}"
ContentTemplate="{StaticResource commonTemplate}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Any better way or improvements are always welcome.. thank you
This is my simple code to do this:
<Grid>
<ListView>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Source="c:\myimage.jpg" />
<TextBlock Text="Image Name"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
But except the empty header, nothing shows up.
This is my first time using GridView. Am I missing something ?
Your ListView has no items, the CellTemplate is applied to each item in the list and if there are no items nothing will be shown. Did you perhaps mean to change the Header instead?
If you are not binding a source then it is not going to generate any rows. Show your XAML or code behind for binding a source.
You probably don't want to use CellTemplate. Here is an intro-level example of ListView: http://www.switchonthecode.com/tutorials/wpf-tutorial-using-the-listview-part-1
I've got a wpf mvvm application up and running. In one of my views I've got a listbox where one column is a combobox. I thought that I had everything working, but... I ended up here.
When I select a value in the combobox in one row, all rows are changed. I've tried a lot of things and i'm stuck.
Here's my xaml:
<ListView ItemsSource="{Binding Path=Properties.OutputGroups, Mode=TwoWay}">
<ListView.View>
<GridView >
<GridViewColumn Header="Output" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.Outputs}" SelectedValue="{Binding Path=Obj.OutputID, Mode=TwoWay}" IsSynchronizedWithCurrentItem="False" DisplayMemberPath="DisplayName" SelectedValuePath="ID" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Duration">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Obj.Duration}" BorderThickness="0" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="State" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Obj.State}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I'm not positive about this, so I apologize if this is not correct, but according to what I have read on MSDN here, I think it might have to do with the "isSynchronizedWithCurrentItem" property. Try switching this property to "true," and see if that fixes your problem.
Like I said, I'm not positive this is where the problem is, but it seems to me like you are wanting the data to be synchronized with the current item, hence why that property is throwing up a flag to me.
I really hope this helps! (And I truly apologize if it doesn't)
I have the following XAML class:
<ListView Controls:ListViewColumns.Stretch="true"
Name="myListItems" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Width="50">
<GridViewColumn.Header>
</GridViewColumn.Header>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Name="btnDelete"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Padding="0"
Margin="0"
IsEnabled="{Binding Converter={StaticResource inverseBoolConverter},
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type WO:OpCompTab}}, Path=DisableAll}"
Click="btnDelete_Click" Tag="{Binding Path=.}">
<Image Source="/Win7;component/Images/Icons/Remove.png"
Width="{StaticResource IconWidth}"
Height="{StaticResource IconHeight}" />
</Button>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
The listview gets populated by hooking an observable collection up to its ItemSource property. This generates a neat looking column of Delete buttons for each item in the observable collection.
But this presents a quandary: How do I access the "btnDelete" of an individual row of the ListView? I'd like to change its icon on a per-row basis. Is it just a matter of binding the observable collection to the cell template somehow?
Instead of hardcoding the Image.Source, bind it to a property in your row object. Another way is to create a value converter and pass in the row or some property if you can't or don't want to modify the row object to add an ImageSource property. Have the value converter return the correct image source based on the passed in property or some other logic.