How to "Fill" a GridViewColumn with ComboBox (WPF)? - c#

I am looking for a way to "completely fill" a GridViewColumn with a combo box. I am able to create a cell template with ComboBox and it is working fine. But the width and height of ComboBox is not aligned with the GridViewColumn.
Even if I try to set the same height/width GridViewColumn hides some part of the comboBox.
There must be some setting or style to instruct WPF to fill the ComboBox completely in the available space of GridViewColumn
This is my XAML.
<Window x:Class="WPFStarter.ComboInsideListView.ComboBoxInsideListViewUsingObject"
x:Name="userControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ComboBoxInsideListViewUsingObject" Height="300" Width="400">
<Grid>
<ListView x:Name="listView" ItemsSource="{Binding ElementName=userControl,
Path=DataContext.Items}" SelectedItem="{Binding ElementName=userControl, Path=DataContext.SelectedItem, Mode=TwoWay}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name" DisplayMemberBinding="{Binding Path=First}"/>
<GridViewColumn Header="Gender">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ComboBox x:Name="cmb_Gender" Width="75" SelectedValue="{Binding Path=Gender}"
ItemsSource="{Binding ElementName=userControl, Path=DataContext.Genders}" GotFocus="ComboBox_GotFocus" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>

Include the following style into the ListViews-resources. Then you can set the HorizontalAlignment-property of the ComboBox to HorizontalAlignment="Stretch" and it will do as you wish:
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.Resources>

Have you tried this:
<ComboBox x:Name="cmb_Gender" Width="75" SelectedValue="{Binding Path=Gender}"
ItemsSource="{Binding ElementName=userControl, Path=DataContext.Genders}"
GotFocus="ComboBox_GotFocus"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

Related

XAML binding behaviour on ListView inside ListView data binding

I have a class
Class Test
{
string name {get;set;}
List<string> marks {get; set;}
}
Trying to bind data of ObservableCollection to XAML
<ListView x:Name="list1" HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding}" Width="790">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView >
<GridViewColumn Header="Name" HeaderTemplate="{StaticResource myHeaderTemplate}" HeaderContainerStyle="{StaticResource myHeaderStyle}" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="xyt" Text="{Binding name}" TextAlignment="Center" FontFamily="Arial" FontSize="14">
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Marks" HeaderTemplate="{StaticResource myHeaderTemplate}" HeaderContainerStyle="{StaticResource myHeaderStyle}" Width="500">
<GridViewColumn.CellTemplate>
<DataTemplate>
**<ListView x:Name="list2" ItemsSource="{Binding marks}">
<DataTemplate>
<TextBlock x:Name="marki" Text="{Binding}" TextAlignment="Center" FontFamily="Arial" FontSize="16" Margin="10" MouseLeftButtonDown="TextBlock_MouseLeftButtonDown">
</TextBlock>
</DataTemplate>
</ListView>**
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
But I get error in binding "operation-is-not-valid-while-itemssource-is-in-use-access"
When I remove DataTemplate from list2, it shows properly with data binding, with name and corresponding listview of marks.
<ListView x:Name="list1" HorizontalAlignment="Left" VerticalAlignment="Top" ItemsSource="{Binding}" Width="790">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView >
<GridViewColumn Header="Name" HeaderTemplate="{StaticResource myHeaderTemplate}" HeaderContainerStyle="{StaticResource myHeaderStyle}" Width="150">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="xyt" Text="{Binding name}" TextAlignment="Center" FontFamily="Arial" FontSize="14">
</TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Marks" HeaderTemplate="{StaticResource myHeaderTemplate}" HeaderContainerStyle="{StaticResource myHeaderStyle}" Width="500">
<GridViewColumn.CellTemplate>
<DataTemplate>
**<ListView x:Name="list2" ItemsSource="{Binding marks}">
</ListView>**
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
I am assigning datasource as
list1.ItemsSource = observablecollection<Test>;
I tried adding giving Path, relativesource, but still facing error.
I am confused why putting TextBlock causing error?
you are missing <ListView.ItemTemplate> tag around DataTemplate:
<ListView x:Name="list2" ItemsSource="{Binding marks}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="marki" Text="{Binding}" TextAlignment="Center" FontFamily="Arial" FontSize="16" Margin="10" MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"/>
</DataTemplate>
<ListView.ItemTemplate>
</ListView>
markup
<ListView>
<DataTemplate>
</DataTemplate>
</ListView>
is equivalent to
<ListView>
<ListView.Items>
<DataTemplate>
</DataTemplate>
<ListView.Items>
</ListView>
and Items usage conflicts with setting ItemsSource.
<ListView.Items> can be omitted because Items property is chosen as ContentProperty for ListView.

WPF ListView with CollectionViewSource not getting SelectedItem in ViewModel

I Have a ListView I am grouping using a CollectionViewSource, but I cant seem to get the selected item back into the ViewModel. What do I need to do to get the item the user selects?
SelectedItem="{Binding SelectedComparatorGroupItem}" does not appear to work when using a collectionviewSource, I tried IsSynchronizedWithCurrentItem="True" but that did not help.
<Grid>
<Grid.Resources>
<CollectionViewSource x:Key="NumberGroups"
Source="{Binding Path=ComparatorGroupItemList}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Group" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<ListView x:Name="lvNumbers"
DataContext="{StaticResource NumberGroups}"
ItemsSource="{Binding IsAsync=True}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedComparatorGroupItem}"
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True">           
     
<ListView.View>
<GridView>
<GridViewColumn Header="Number" DisplayMemberBinding="{Binding Number}"/>
<GridViewColumn Header="# Found" DisplayMemberBinding="{Binding NumberFound}"/>
</GridView>
</ListView.View>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="False">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"
Margin="3"
FontSize="18" FontWeight="Bold"
/>
<TextBlock Text="{Binding ItemCount}"
Margin="3"
FontSize="18" FontWeight="Bold"
/>
</StackPanel>
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
You set the DataContext of the ListView to your local CollectionViewSource. That means that binding SelectedItem to SelectedComparatorGroupItem is going to look for the SelectedComparatorGroupItem property on the CollectionViewSource, not your viewmodel. You should be seeing some kind of binding error in the output window from that.
Don't set the DataContext, just let it flow through naturally. All you should need to do is bind the ItemsSource to the CollectionViewSource.
I think this will do it, but I don't have VS open, or access to your ViewModel, to verify:
<ListView x:Name="lvNumbers"
ItemsSource="{Binding Source={StaticResource NumberGroups}, IsAsync=True}"
IsSynchronizedWithCurrentItem="True"
SelectedItem="{Binding SelectedComparatorGroupItem}"
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.IsVirtualizingWhenGrouping="True">
As a general rule, if you are ever setting the DataContext of something, you are not doing the way WPF wants you to do it. Usually the only place I end up setting it is when I am being lazy with a UserControl.

WPF Delete button in listview mvvm

I have a button inside a listview to delete selected item.when i click on the button RemoveSubjectCommand is not firing. if i put the button outside the listview it is working fine. hopw this is just because of nested item. how can i solve this problem?
<ListView HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" Grid.Row="2"
ItemsSource="{Binding AssignedSubjects}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Subjects" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="X" Command="{Binding RemoveSubjectCommand}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
View Model,
private ICommand removeSubjectCommand;
**
public ICommand RemoveSubjectCommand
{
get { return removeSubjectCommand ?? (removeSubjectCommand = new RelayCommand(param => this.RemoveSubject(), null)); }
}
**
private void RemoveSubject()
{ ***
}
If i put following code, it will work fine.
<ListView.InputBindings>
<KeyBinding Key="Delete" Command="{Binding RemoveSubjectCommand}" />
</ListView.InputBindings>
That is because DataContext of button is ListBoxItem DataContext. So you need to go to parent ListView DataContext.
one way to do that, is to give ListView a name, and to bind with element name
<ListView Name="lv" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" Grid.Row="2"
ItemsSource="{Binding AssignedSubjects}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</ListView.ItemContainerStyle>
<ListView.View>
<GridView>
<GridViewColumn Width="140" Header="Subjects" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Width="auto">
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Content="X" Command="{Binding ElementName=lv,Path=DataContext.RemoveSubjectCommand}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
You need to bind the Command to using FindAncestor. Otherwise, it'll try to bind to a RemoveSubjectCommand using the ListViewItem's datacontext, not the ViewModel's.
Try this:
<Button Content="X" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}, Path=DataContext.RemoveSubjectCommand}" />
if i put the button outside the listview it is working fine
Because RemoveSubjectCommand property is defined in the data context of ListView, not in the data context of item.

How to center a TextBlock within a CellTemplate in WPF?

I tried both HorizontalAlignment and TextAlignment but it has no effect.
<GridViewColumn Width="Auto" Header="Type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Type}" HorizontalAlignment="Center" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Any ideas?
EDIT:
Xaml code:
<Window x:Class="EffectsWindow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Effects Editor"
<DockPanel VerticalAlignment="Stretch">
<DockPanel.Resources>
<ListView
DockPanel.Dock="Top"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding EditorViewModel.AllEffects}">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto"
DisplayMemberBinding="{Binding Name}"
Header="Name" />
<GridViewColumn Width="Auto" Header="Type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Type}" HorizontalAlignment="Center" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<DockPanel Width="100"
Height="100"
Margin="0,0,20,20"
HorizontalAlignment="Right"
VerticalAlignment="Bottom">
<Label Margin="0,0,0,0"
Content="Data"
DockPanel.Dock="Top" />
<ListBox
VerticalAlignment="Top"/>
</DockPanel>
</DockPanel>
</Window>
did you try HorizontalContentAlignment? on the column?
-- EDIT --
turns out it's kinda hard to find the right place to put this HorizontalContentAlignment... :)
use this
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</ListView.Resources>
in the listview.
Snoop usually helps u to be on the right path. This ContentPresenter is the used by the ListViewItem, and it gets its Alignment from the ContentAlignment on the ListViewItem. u can't access the ListViewItem directly, and that's why u need that Style
and the full code:
<DockPanel VerticalAlignment="Stretch">
<ListView
DockPanel.Dock="Top"
HorizontalContentAlignment="Stretch"
x:Name="MyListView">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView >
<GridViewColumn Width="Auto"
DisplayMemberBinding="{Binding Name}"
Header="Name" />
<GridViewColumn Width="Auto" Header="Type">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Type}" HorizontalAlignment="Center" TextAlignment="Center" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<DockPanel Width="100"
Height="100"
Margin="0,0,20,20"
HorizontalAlignment="Right"
VerticalAlignment="Bottom">
<Label Margin="0,0,0,0"
Content="Data"
DockPanel.Dock="Top" />
<ListBox
VerticalAlignment="Top"/>
</DockPanel>
</DockPanel>
Unfortunatelly there is no way to adjust the horizontal alignment of TextBlocks within CellTemplate.
Because GridViewRowPresenter sets the HorizontalAlignment property of Cells to HorizontalContentAlignment of its TemplatedParent, which in this case is ListViewItem.
So you are going to have to change your ListViewItemStyle.
If you change the HorizontalContentAlignment of ListViewItem using snoop, you will see that the alignment of cell will not be affected since HorizontalContentAlignment value is set during the creating of the cells.

Datatemplates while using theme does not work - WPF

I am using the theme DarkExpression from WPF Futures.
It does not seem to work well with datatemplates.
Scenario 1:
Here is how it looks like without datatemplates:
Code:
<ListView Name="playlistListView" ItemsSource="{Binding PlaylistList}" Margin="0" SelectionChanged="DatabindedPlaylistListView_SelectionChanged" Background="{x:Null}" Opacity="0.98">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader HorizontalContentAlignment="Left" Content="Playlist" Tag="Playlist"/>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Scenario 2:
Here is how it looks like trying to use datatemplates while using the theme:
Code:
<ListView Name="playlistListView" ItemsSource="{Binding PlaylistList}" Margin="0" SelectionChanged="DatabindedPlaylistListView_SelectionChanged" Background="{x:Null}" Opacity="0.98">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<UserControls:SongDataTemplate Margin="4" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Scenario 3:
Here is how it looks like trying to use datatemplates while overriding the theme:
Code:
<UserControl.Resources>
<Style x:Key="ListViewItemStretch" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ListView Name="playlistListView" ItemContainerStyle="{StaticResource ListViewItemStretch}" ItemsSource="{Binding PlaylistList}" Margin="0" SelectionChanged="DatabindedPlaylistListView_SelectionChanged" Background="{x:Null}" Opacity="0.98">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<UserControls:SongDataTemplate Margin="4" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want to keep the theme style but I also want to use datatemplates to define how a playlist should look like. Any suggestions?
Note: In scenario 2 and 3 I had to remove
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader HorizontalContentAlignment="Left" Content="Playlist" Tag="Playlist"/>
</GridViewColumn>
</GridView>
</ListView.View>
Before the datatemplate would be used.
Edit:
The solution given below, works if the type is changed to ListBox and I am using a TextBox instead. I can't however make it work with a ListView.
You are doing it wrong.
When you want to customize ListView you need to work with the View property which is of type ViewBase. Derive a custom View from ViewBase, assign it to ListView.View and you're done.
There's an example in ViewBase Class Documentation
Try by using BasedOn
<Style BasedOn={StaticResource {x:Type ListViewItem}} x:Key="ListViewItemStretch" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Transparent" />
</Style>
does it work if you substitute
<Grid>
<UserControls:SongDataTemplate Margin="4" />
</Grid>
with a TextBox, for example?
The problem could be generated by your user control..

Categories