XAML ViewBox forces a bad rescale on ListBoxItem MouseOver - wpf

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.

Related

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

Change DataTemplate style in ListBoxItem if the item is selected

I have a listbox with an expander inside the ItemTemplate. I managed to bind the expander's IsExpanded property to the ListBoxItem's IsSelected property ok. Now I want to apply a style to the ListBoxItem's content also bound to the IsSelected property.
<ListBox.ItemTemplate>
<DataTemplate>
<Border Name="myBorder">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Description}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Date:"/>
<TextBlock Text="{Binding Date}"/>
</StackPanel>
<dx:DXExpander Name="expanderDetails"
IsExpanded="{Binding Mode=TwoWay, Path=IsSelected,
RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Count:"/>
<TextBlock Text="{Binding Count}"/>
</StackPanel>
</dx:DXExpander>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
What I want to do is somehow set the style of the "myBorder" Border to "NotSelectedBorderStyle" for unselected ListBoxItems, and to "SelectedBorderStyle" for the SelectedItem (ListBox with single selection).
FYI, the styles define background, border and that kind of stuff, just to make the clear which item is selected, nothing fancy in these styles.
I tried the accepted answer here but if I completely switch styles I loose the nice expanding animation my DXExpander has.
I guess there must be some solution using triggers, but I can't just hit the right spot.
Finally I got it, I'm posting it here in the hope that this will save someone else time and pain :-P
This code does some additional things: the EventSetter and the corresponding Handler method are there to capture clicks to the elements inside the DataTemplate, in order to select the ListBoxItem which contains the element (if you don't you might type text inside an item, while a different one is selected).
The inner Border ("myBorder") is just a container for the stackpanels, I had to wrap everything inside another border ("backgroundBorder") which gets the style changed when the ListBoxItem gets selected.
<Style x:Key="FocusedContainer" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="LightGray"/>
<EventSetter Event="GotKeyboardFocus" Handler="OnListBoxItemContainerFocused" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="backgroundBorder" Width="Auto" Style="{StaticResource NotSelectedBorderStyle}">
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.ContentTemplate>
<DataTemplate>
<Border Name="myBorder">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Description}" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Date:"/>
<TextBlock Text="{Binding Date}"/>
</StackPanel>
<dx:DXExpander Name="expanderDetails"
IsExpanded="{Binding Mode=TwoWay, Path=IsSelected,
RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Count:"/>
<TextBlock Text="{Binding Count}"/>
</StackPanel>
</dx:DXExpander>
</StackPanel>
</Border>
</DataTemplate>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="backgroundBorder" Property="Style" Value="{StaticResource SelectedBorderStyle}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then I set the ItemContainerStyle in my ListBox to the above style:
<ListBox Background="#7FFFFFFF" HorizontalContentAlignment="Stretch"
ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True"
ItemContainerStyle="{StaticResource FocusedContainer}"/>
To finish, the code behind for the GotKeyBoardFocus handler:
private void OnListBoxItemContainerFocused(object sender, RoutedEventArgs e)
{
(sender as ListBoxItem).IsSelected = true;
}
A mess in code, but pretty neat in the UI. Hope this helps someone!

ComboBox with two columns in popup

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.

Automatic Scrolling in a Silverlight List Box with Custom Template

I have ListBox with custom template, how do programmatically scroll it down to bottom?
Automatic Scrolling in a Silverlight List Box describes method of scrolling to bottom of ListBox. Unfortunately this method does not work with ListBox with custom style template.
Have anyone success to scroll ListBox with custom style?
Problem code:
<Grid.Resources>
<Style x:Key="HorizontalWrapListBox" TargetType="ListBox">
<Style.Setters>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<toolkit:WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
</Grid.Resources>
<ListBox x:Name="MyListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}"
Style="{StaticResource HorizontalWrapListBox}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="78">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap"
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap"
Margin="12,-6,12,0"
Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You need to keep correct naming of your template parts and this could just start working. The ScrollViewer should be named x:Name="ScrollViewer". Check
ListBox Styles and Templates,
Customizing the Appearance of an Existing Control by Using a ControlTemplate,
TemplatePartAttribute

Silverlight 3: ListBox DataTemplate HorizontalAlignment

I have a ListBox with it's ItemTemplate bound to a DataTemplate. My problem is I cannot get the elements in the template to stretch to the full width of the ListBox.
<ListBox x:Name="listPeople" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,0,0,0" Background="{x:Null}" SelectionMode="Extended" Grid.Row="1"
ItemTemplate="{StaticResource PersonViewModel.BrowserDataTemplate}"
ItemsSource="{Binding Mode=OneWay, Path=SearchResults}" >
</ListBox>
<DataTemplate x:Key="PersonViewModel.BrowserDataTemplate">
<ListBoxItem HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,5,5,5">
<Border Opacity=".1" x:Name="itemBorder" Background="#FF000000"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
CornerRadius="5,5,5,5" MinWidth="100" Height="50"/>
</Grid>
</ListBoxItem>
</DataTemplate>
As you can see, I have added a border within the grid to indicate the width of the template. My goal is to see this border expand to the full width of the listbox. Currently its width is determined by its contents or MinWidth, which is the only thing at the moment keeping it visible at all.
I spent an hour trying to resolve this one. Very very frustrasting. You don't have to override the entire default style for the ListBoxItem. I couldn't get this to work. In the end I resolved the issue by simply overriding just the HorizontalContentAlignment property in my ListBox.ItemContainerStyle section e.g:
<ListBox x:Name="ClassList" ItemsSource="{Binding LineClasses}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
SelectionMode="Extended"
ScrollViewer.HorizontalScrollBarVisibility="Hidden" HorizontalContentAlignment="Stretch"
HorizontalAlignment="Stretch" Loaded="ClassList_Loaded"
VerticalAlignment="Stretch" Grid.Row="0">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" CornerRadius="3" Background="#FFE88D34"
BorderThickness="1" HorizontalAlignment="Stretch" >
<Grid Background="Transparent" HorizontalAlignment="Stretch" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Column="0" HorizontalAlignment="Stretch"
Margin="2"
FontSize="10"
Text="{Binding DisplayClassNm}"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
This worked a treat for me.
Myles
When creating Data Templates for ListBox, you should not incldue <ListBoxItem>. The contents of the DataTemplate will be placed inside of a generated container. You can control how that container is constructed using ItemContainerStyle.
The default control style for ListBoxItem is used to define the ItemContainerStyle by default. This style sets the ListBoxItem.HorizontalContentAlignment property to 'Left'. Notice how the ContentPresenter binds its HorizontalAlignment to this property.
You need to override the style of the ListBoxItem container that is being generated when you bind to your ListBox. This can be done by setting the ItemContainerStyle. Set the HorizontalContentAlignment property to be "Stretch".
Below is the default ListBoxItem Style. Included for reference.
<Style x:Key="ListBoxItemStyle1" TargetType="ListBoxItem">
<Setter Property="Padding" Value="3"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Grid Background="{TemplateBinding Background}">
<!-- VSM excluded for readability -->
<Rectangle x:Name="fillColor" Fill="#FFBADDE9" RadiusX="1" RadiusY="1" IsHitTestVisible="False" Opacity="0"/>
<Rectangle x:Name="fillColor2" Fill="#FFBADDE9" RadiusX="1" RadiusY="1" IsHitTestVisible="False" Opacity="0"/>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
<Rectangle x:Name="FocusVisualElement" Stroke="#FF6DBDD1" StrokeThickness="1" RadiusX="1" RadiusY="1" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here is an example of using the control templates and data templates for the listbox control. Refer to the XAML markup which streaches the border for the listbox items.
My ListBoxItem contained a CheckBox and the above solutions did not work for me (most likely due to the nature of a CheckBox, not those solutions) I was able to coerce this functionality by not binding to the "Content" property of the checkbox, but explicitely defining the XAML inline:
<CheckBox HorizontalAlignment="Stretch" IsChecked="{Binding Path=IsSelected, Mode=TwoWay}">
<TextBlock
MinWidth="130"
Margin="0,-2,0,0"
HorizontalAlignment="Stretch"
Text="{Binding Path=DisplayText}" />
</CheckBox>
The margin is needed because the TextBox text did not align with the CheckBox's checkmark. The MinWidth was also necessary.
I am working with Silverlight 5 with VS 2012. I have the same issue. I have horizontal listbox with my own custom objects as ItemsSource. I want listbox items to expand. But they are not expanding. I donot want to give any hard coded width for every listbox item. I tried all answers here but nothing works. I just gave ItemsSource ={Binding Persons} DisplayMemberPath="First Name". Thats all
Two things I noticed here, because I had the same issue and wasn't able to solve it the way you're trying.
First, you don't need to explicitly put a ListBoxItem in your DataTemplate. This is created for you automatically, so you actually have your ListBoxItem inside of the one that was created for you. I checked this out in Snoop to confirm.
Second, and I don't know exactly why, but I wasn't able to get the stretching behavior out of the alignment attributes either. I changed it to use RelativeSource binding on the Width attribute to the ActualWidth property of the containing ListBoxItem. This worked for me.
Width="{Binding RelativeSource={RelativeSource
AncestorType={x:Type ListBoxItem}}, Path=ActualWidth}"
If you need to set style properties on the ListBoxItem that is implicitly created for you, use a Style element inside of the ListBox.ItemContainerStyle element.
Hope this helps...

Resources