set Combobox ItemsSource BindingContext to ViewModel - wpf

I have a ListView, in which I placed some ComboBoxes as following :
<ListView x:Name="ListViewCategories" SelectedItem="{Binding SelectedCategory}" ItemsSource="{Binding ListCategoryPart}" SelectionChanged="ListViewCategories_SelectionChanged">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Header ="{x:Static p:Resources.Machine}" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding ListCutMachines}"
SelectedValuePath="ID"
SelectedValue="{Binding DefaultCutMachine, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Name" Width="100"
/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
DefaultCutMachine is part of my object CategoryPart(Items listed in ListView).
But what I would like is take the Combobox ItemsSource not from my objects, but from my ViewModel.
How can I bind all my Items Comboboxes ItemsSource not from the Items, but from my ViewModel?(I read about "BindingContext", but don't find how to do it on a ComboBox ItemsSource)

Essentially, you want to create a binding that has a RelativeSource with the proper DataContext of your ViewModel.
Here is an example:
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListView}}, Path=DataContext.ListCutMachines}"
I hope this helps.

Related

DataBinding: Disable ComboBox Item

I'm trying to apply this solution to my case. Only difference is that my ComboBox is taking its items from an enum list.
I always got a binding expression error to the property "IsProgrammabile" in the ComboBox style.
My code:
<ListView ItemsSource="{Binding SchedaSelezionata.ListaIngressi}" SelectionMode="Single">
<ListView.View>
<GridView>
<GridViewColumn Header="NR." DisplayMemberBinding="{Binding Numero}" />
<GridViewColumn Header="FUNCTION" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={helpers:EnumBindingSource {x:Type models:INGRESSI}}}" SelectedItem="{Binding Funzione}"
ToolTip="{Binding Descrizione}" IsEnabled="{Binding ConfigurabileDaUtente}" Width="150" >
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="IsEnabled" Value="{Binding Path=IsProgrammabile, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Note that the "IsProgrammabile" property belongs to same object as the other properties (Numero, Funzione, Descrizione, ConfigurabileDaUtente).
Setting the AncestorType to GridView or ListView doesn't help.
Can you provide the solution and explain me what I do not understand in this context?
Thanks in advance
The ComboBox itself has no property named IsProgrammabile but its DataContext may have so you should add "DataContext." to the binding path:
<Setter Property="IsEnabled" Value="{Binding Path=DataContext.IsProgrammabile,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}}"/>

How to bind button inside listview

I cant bind button inside listview to the GoToTask property, every other binding, include second button in the grid is work well.
<Grid>
<ListView ItemsSource="{Binding Projects}" SelectedItem="{Binding SelectedProject, Mode=TwoWay}" Grid.Row="1">
<ListView.Resources>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Visibility" Value="Collapsed"/>
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Go">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="Go" Command="{Binding Path=GoToTasks, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<Button Height="20" Width="50" HorizontalAlignment="Right" Command="{Binding GoToTasks}" Content="Go"/>
</Grid>
Everything is inside UserControl.
What is wrong?
GridViewColumn is not part of VisualTree and therefore you are not allowed to use FindAncestor.
Similar here. Try ElementName, as far as I remember it uses LogicalTree.

Data Binding or DataContext issue when binding a ListView from multiple sources

I cant quite figure out how to bind my list view to both properties in my ViewModel and a list in my view model.
Is it possible to override the ListViews ItemsSource and bind a Checkbox within the ListView straight to the parent ViewModel?
Something like this...
<ListView ItemsSource="{Binding Path=SomeListInViewModel}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<DockPanel>
<CheckBox
IsEnabled="{Binding SomePropertyInViewModel}"
IsChecked="{Binding SomePropertyInsideListObj, Mode=TwoWay}" />
</DockPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
there are two possible ways:
1) name the ListView
<ListView x:Name="MyListView" ItemsSource="{Binding Path=SomeListInViewModel}">
and then use the ElementName property on the binding
IsEnabled="{Binding ElementName=MyListView, Path=Whatever}"
2) use RelativeSource in the binding
IsEnabled="{Binding Path=Whatever, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}"
in both cases, if your view model is set as the DataContext of the ListView, the path would look something like DataContext.SomePropertyInViewModel.

Is there any simplier/better way to auto-size the content of one-column ListView?

Alright, sorry for my english in advance, here what I need:
I got a ListView in XAML (WPF) where there items is located and what I need is that items to have the width equal to the ListView's width.
So far, I did this:
<ListView Name="lvFiles" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Width="{Binding ElementName="lvFiles", Path=ActualWidth}">
<!-- All the controls inside I need to present an item -->
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
But as it turned out, the ListView items become clipped on the right when the vertical scrollbar appears. And it appears when the total height of all items exceeds the ListView.ActualHeight, so I needed to user bindings more complex and hence more complicated.
Also, my items, while I was spending hours to solve the problem, my items sometimes were clipped on the right with no obvious reason.
So I came up with this:
<ListView Name="lvFiles" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.View>
<GridView>
<GridViewColumn Width="{Binding ElementName=lvFiles, Path=ActualWidth}">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Decorator Width="{Binding RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=ListViewItem},
Path=ActualWidth}">
<Grid Margin="0,0,18,0">
<!-- All the controls inside... -->
</Grid>
</Decorator>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
It solved clipping problem and also it solved the problem with one-columned ListViewItem auto-size. But now it seems to be not the simpliest way. Is there any such?
You're not using a header so you can use ListView directly without using GridView. As for the width, don't adjust the content width, but adjust the ListViewItem width.
Here's an example:
<Style x:Key="singleListViewItemStyle"
BasedOn="{StaticResource {x:Type ListViewItem}}"
TargetType="{x:Type ListViewItem}">
<Setter Property="Width"
Value="{Binding Path=ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type VirtualizingStackPanel}}}" />
</Style>
If you do not have an existing style targeting ListViewItem or do not want to inherit from it, you can remove BasedOn="{StaticResource {x:Type ListViewItem}}".
AncestorType={x:Type VirtualizingStackPanel} is used because by default, that is what ListView displays its content in. If you have your own ListView theme, then see the following example:
<ListView Name="myListView"
ItemContainerStyle="{StaticResource ResourceKey=singleListViewItemStyle}"
ItemsSource="{Binding Path=MyItems}"
SelectedItem="{Binding Path=MySelectedItem, Mode=TwoWay}"
SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<!--Your favorite controls-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Here is the link for a demo project I made for you. You can also see my other controls.
I hope this helps.

How to get the selected value from a WPF ComboBox DataTemplate

I want to find out how to get the selected value from a combobox column in a listview with a gridview view or even a datagrid.
The xaml will look like this:
<ListView Name="lstPicker" ItemsSource="{Binding}" SelectionMode="Single" Margin="6" >
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView x:Name="gridParams" ColumnHeaderContainerStyle="{StaticResource DialogueGridViewColumnHeader}" >
<GridViewColumn Header="Workflow Parameters" Width="Auto" DisplayMemberBinding="{Binding WorkflowParameterName}" />
<GridViewColumn Header="Profile Parameters" Width="Auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=ProfileParametersList}" DisplayMemberPath="ProfileParameterName" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
What I want to do is to save for each workflow parameter in the list a value from the profiles parameter combobox.
The list is binded to an Observable Collection with some workflow parameters that contains another Observable Collection named ProfileParametersList that contains some parameter profiles. So for each item in the mother collection i want a detail to be picked from the child Collection and handled afterwards.
I tried to get the rows and cast them to the Class type that i use but i am unable to see what was selected in the combobox as the whole DetailsList is there. Any help is apreciated
The datagrid version can look like this:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding}" Name="dgPicker" CanUserAddRows="False" CanUserDeleteRows="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Workflow Parameters" Binding="{Binding WorkflowParameterName}" IsReadOnly="True" />
<DataGridTemplateColumn Header="Profile Parameters">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ProfileParametersList}" DisplayMemberPath="ProfileParameterName" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Create a property SelectedProfileParameter in your class WorkFlowParameter and bind it to the SelectedItem of your combobox. This should work for you then -
<DataGridTemplateColumn Header="Profile Parameters">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ProfileParametersList}" DisplayMemberPath="ProfileParameterName" SelectedItem="{Binding SelectedProfileParameter}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Resources