ComboBox with two columns in popup - wpf

I need to create a custom control containing a combobox whose popup will have the Name propeprty of the bound objects aligned to the left, and the CreatedDate property of the bound objects aligned to the right in each pop up item. Also the Name and the CreatedDate must not overlap. The Name of the object is of variable length
I tried solving this problem using a DataTemplate in the Combobox.ItemTemplate, inside the data template I have a grid with two columns aligned appropriately. The Grid's horizontal alignment is set to Stretch but for some reason the Grid doesn't fill out the available space in the popup. Does anyone know how to get around this and why it happens? I am using WPF 3.5.
<UserControl.Resources>
<CollectionViewSource x:Key="cvsProcessingSessionList" Source="{Binding ProcessingSessionList, ElementName=View}"/>
<Style TargetType="{x:Type ComboBox}"
BasedOn="{StaticResource {x:Static res:ObjectResources.LEComboBoxStyle}}">
<Setter Property="Margin" Value="5,3"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<GroupBox x:Name="grbProcessingSession">
<GroupBox.Header>
<Bold>Processing Session:</Bold>
</GroupBox.Header>
<GroupBox.Content>
<ComboBox
x:Name="ccbProcessingSessionName"
ItemsSource="{Binding Source={StaticResource cvsProcessingSessionList}}"
Loaded="OnLoaded" TextSearch.TextPath="Name"
IsEditable="True" MaxDropDownHeight="500" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid Background="Pink" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" TextAlignment="Left" HorizontalAlignment="Left"
Margin="0,0,5,0" Text="{Binding Name}"/>
<TextBlock Grid.Column="1" TextAlignment="Right" HorizontalAlignment="Right"
Text="{Binding CreatedDate, StringFormat=dd/MM/yyyy}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</GroupBox.Content>
</GroupBox>

Just add this binding to your grid in yiour DataTemplate ...
Width="{Binding ActualWidth,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ComboBoxItem}},
Mode=OneTime}"
Also for better effect, apply the background color to the ComboBoxItem and not to the grid...
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Background" Value="Pink"/>
</Style>
</ComboBox.ItemContainerStyle>

Whenever I want to do the same that you are asking I add:
<ComboBox ...>
<ComboBoxItem HorizontalContentAlignment="Stretch">
</ComboBoxItem>
</ComboBox>
The thing is that I place my custom DataTemplate inside the ComboBoxItem.
Maybe you should try it...

Actually, the better way is to set HorizontalContentAlignment="Stretch" at the ComboBox level. This will work even if width of ComboBox changes (e.g. if it is in resizable container).
However, be aware that this works in WPF and Silverlight 5 but don't work in some older versions of Silverlight.

Related

XAML ViewBox forces a bad rescale on ListBoxItem MouseOver

I have the following XAML layout (ListBox where the Items are RadioButtons styled as ToggleButtons). The ListBox and the ToggleButton items scales and fills the ToggleButton items nicely to adapt to the window size. This is just as I want, but when I have the mouse over a ToggleButton in the ListBox, the style sets the Text to be bold. This is also what I want, but the problem is that it makes the button slightly bigger. When having the mouse over the ToggleButton item with the longest text the ViewBox refreshes and rescales all the ToggleButton controls. It looks like all the ToggleButtons makes a jump. How can I prevent such rescaling of the ToggleButtons still filling out the complete Grid Column and Row with the ListBox and its ToggleButton items?
<Viewbox Stretch="UniformToFill" Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch" Margin="5,0,0,15">
<Grid x:Name="LeftSide" Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<ListBox Grid.Column="0" Grid.Row="0" Grid.RowSpan="10" ItemsSource="{Binding LeftPaneViewModelInfoItems, UpdateSourceTrigger=PropertyChanged}" Background="Transparent" SelectedItem="{Binding SelectedViewModelInfoItem}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding Text}"
GroupName="DisplayPage"
IsChecked="{Binding IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Style="{StaticResource RadioButtonToggleButtonStyle}"
>
</RadioButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Viewbox>
Did not find a good solution. I ended up removing the bold setter property from the Mouse Over style.

Multi column ListView in WPF without using GridView

I'm trying to make a two-column ListView. I'd like to avoid putting a GridView inside it because the design specs I'm matching are very simplistic. I can get the exact behavior that I want with an ItemsControl:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Key}" Grid.Column="0" />
<TextBlock Text="{Binding Value}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This separates the item properties nicely between the two halves of the available space. However, a ListView with identical templates displays the properties right next to each other with no separation. Is there a way I can achieve the desired behavior in a ListView without a GridView?
For ItemsControl try setting the ItemContainerStyle of the ItemsControl to stretch the children horizontally:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="HorizontalAlignment" Value="Stretch"/>
</Style>
</ItemsControl.ItemContainerStyle>
For ListView try setting the ItemContainerStyle of the ListView to stretch the children horizontally:
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>

How to achieve the complex UI using ItemControl in silverlight

I am working on creating a complex report which almost looks like shown in here image
For this I have create a collection where I will store all the descriptions and its corresponding ratings.
This collection is then I am binding to a ItemControl. The collection will be fetched from database depending on criteria's.
Now my problem is how to fragment or separate single ItemControl to look like shown in image. Should I use multiple collections which will be then bind to different ItemControl ? Can I use multiple datagrids?
I am out of ideas... Any suggestions / examples much appreciated.
Definitely do-able. Treat each block (such as Mathmatics, Arts Education etc) as an item, and you're then just dealing with an ItemsCollection. Create a style for how to present each item in that collection, and another style for how to present each property in your block (which will also feature a collection of something.
An example I have of something similar, was blocks which consisted of a heading, and a varied number of checkboxes each with a description. There could be a varying number of these blocks too.
In my view, that displayed these blocks, my xaml looked something like this:
<ScrollViewer VerticalScrollBarVisibility="Visible" MaxHeight="100">
<ItemsControl ItemsSource="{Binding FeatureFlags, Mode=TwoWay}" Style="{StaticResource FlagGroupsAndFlagsItemsControlStyle}" />
</ScrollViewer>
I then had a style for that ItemsControl defined in a resource dictionary somewhere ...
<Style x:Key="FlagGroupsAndFlagsItemsControlStyle" TargetType="ItemsControl">
<Setter Property="Width" Value="Auto" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid x:Name="FlagListGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Width="{Binding Width, ElementName=FlagListGrid, Mode=OneWay}" IsReadOnly="True" Text="{Binding Name}" />
<ListBox Grid.Row="1" Width="{Binding Width, ElementName=FlagListGrid, Mode=OneWay}" ItemsSource="{Binding Flags}" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Style="{StaticResource FlagsListBoxItemsStyle}" Background="{Binding IsOptional, Converter={StaticResource YNToOptionalBackgroundColour}}"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
And then a style for the items within that templates ListBox ...
<Style x:Key="FlagsListBoxItemsStyle" TargetType="ListBox">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<toolkit:WrapPanel Width="{Binding Width, ElementName=FlagListGrid, Mode=OneWay}" Orientation="Horizontal" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Width="20" Height="18" VerticalAlignment="Top" IsChecked="{Binding IsSelected, Mode=TwoWay}" />
<TextBlock Width="180" MinHeight="18" VerticalAlignment="Center" Text="{Binding Description}" TextWrapping="Wrap" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Unfortunately I can't show you an image of what the finished result looks like, but I hope these pointers could set you on track for your very similar problem

WPF ListBox Item collapse datatrigger not working

I have a listbox and all I want to do is collapse the listboxitem based on a boolean property of my SelectedItem.
The IsVisible property on my client Model implements the NotifyPropertyChanged event.
Overview - I have a list of clients which users can do CRUDs on. When they delete, I set a boolean property on the Model which my VM exposes to the View. This should then only hide the 'deleted' row from the list. During a flush to db I CRUD based on the mode of the model.
<ListBox Name="listClients"
Grid.Column="1" Grid.Row="1"
Margin="0" BorderThickness="0"
Height="auto"
Style="{StaticResource BumListBox}"
SelectionMode="Extended"
ItemsSource="{Binding Path=ClientList}"
SelectedItem="{Binding SelectedClient, Mode=TwoWay}"
Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" >
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ClientNo}" Foreground="White" FontSize="{StaticResource HeaderFontSize}" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Text="{Binding ClientDesc}" Foreground="White" FontSize="{StaticResource SubHeaderFontSize}" FontWeight="Light" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code behind to jippo MVVM process:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (_cvm.SelectedClient != null)
{
_cvm.SelectedClient.IsVisible = !_cvm.SelectedClient.IsVisible;
_cvm.CurrentSelectedIsVisible = _cvm.SelectedClient.IsVisible; //<- another option to bind to
}
}
I've tried the these suggestions here and here or something similar but I just can't get to hide the items.
Any help in the right direction would be great, cheers.
Edit
I've tried Blam's suggestion below like this but still unable to hide the items:
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Visibility" Value="{Binding Path=CurrentIsVisible, Converter={StaticResource b2v}}" />
</Style>
You will need to set up a converter if you are returning true/false but there is a system converter for that
Move it up to Resources
I have know I have used it this way
<ListBox x:Name="lb" ItemsSource="{Binding}" DisplayMemberPath="Text">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Visibility" Value="{Binding Path=Vis}" />
</Style>
</ListBox.Resources>
</ListBox>
This was rather frustrating and the solution so simple. My client model with IsVisible is in a dll and the NotifyPropertyChanged() changes were never built to update the reference in my project..so the binding never happened. These late nights are taking their toll.

Silverlight Textblock inside Listbox causes it to expand instead of wrapping the text

I have something like this:
<ListBox ItemsSource="{Binding List}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Property}" TextWrapping="Wrap" Grid.Column="0"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the problem I'm having is that the TextBlock will expand the Grid column (and the Listbox) when the text is too long, instead of wrapping it as expected. Maybe I don't understand the star-sizing concept of Grids completely, but the way I see it, since the column width is set to "1*" which means "the remaining space available", the Textblock should NOT try to expand beyond this width, and should wrap the text instead.
So how can I fix this problem? By the way, I need the Grid (or some other container) because there will be other components besides the Textblock. Also the ItemContainerStyle section is there so that the Listbox element occupies the whole space.
Thanks in advance!
Try to add ScrollViewer.HorizontalScrollBarVisibility="Disabled" to your ListBox.
you don't need column definitions if it will be just one, try with the following:
<ListBox ItemsSource="{Binding List}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Property}" TextWrapping="Wrap" HorizontalAlignment="Stretch"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Resources