DataBinding: Disable ComboBox Item - wpf

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

Related

WPF: programmatically opening context menu loses data context

I would like to reuse the context menu of a ListViewItem by adding a toggle button within the item itself which opens it.
The context menu itself works correctly,
however when I open it through the toggle button (simply setting its property IsOpen to True) the commands inside don't work anymore.
It seems the context menu does not have the DataContext anymore.
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem
Header="Restore"
Command="{Binding RestoreCommand}" />
<MenuItem
Header="Delete"
Command="{Binding DeleteCommand}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<!-- My columns here -->
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ToggleButton IsChecked="{Binding Path=ContextMenu.IsOpen, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
Any suggestions?
Thanks
The issue is that the context menu opened indirectly in this way does not have a DataContext.
In order to "assign" it one, you should use the property PlacementTarget to indicate on which control it is bound to.
To achieve this task you can either create a custom behavior, or, if you prefer a purely xaml solution:
<!-- xmlns:b="http://schemas.microsoft.com/xaml/behaviors" -->
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<ToggleButton
x:Name="MoreActionsButton"
IsChecked="{Binding ContextMenu.IsOpen, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Mode=OneWayToSource}">
<b:Interaction.Triggers>
<b:EventTrigger EventName="Checked">
<b:ChangePropertyAction
TargetObject="{Binding ContextMenu, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}"
PropertyName="PlacementTarget"
Value="{Binding ElementName=MoreActionsButton}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ToggleButton>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>

set Combobox ItemsSource BindingContext to ViewModel

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.

Disable ListView selection and hover

Usually I can disable ListView selection doing like this thread suggests - or something similar where you set the ItemContainerStyle.
However I have this ListView that is defined like this:
<ScrollViewer>
<ListView ItemsSource="{Binding List, Mode=OneWay}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumnHeader Style="{StaticResource header}"/>
<GridViewColumn.CellTemplate>
<DataTemplate>
<!-- Some data -->
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridViewColumn>
...
</GridView>
</ListView.View>
</ListView>
</ScrollViewer>
And if I try to specify the ItemContainerStyle - the data in the list just disappears.
Giving the above ListView, how would I proceed just to removed the selection?
Can you try this ItemContainerStyle? This basically will not pick up any input events.
<ListView ItemsSource="{Binding List, Mode=OneWay}">
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListViewItem}}">
<Setter Property="IsHitTestVisible" Value="False"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>

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.

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.

Resources