I have a list box with an ItemContainerStyle which describes the style of each element in the listbox. Like looks something like this:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource MyStyle}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="#1f000000" Padding="16 8">
<Button Command={Binding MyCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=lists:MyControl}}}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
The thing is that, when I click this button I want to know the SelectedItem in the listbox, which is bound in my ViewModel. This selection doesnt trigger unless I select the item first.
Any Ideas?
You need to force the IsSelected with a trigger:
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
Here is a full working example:
<ListBox x:Name="ListBox" ItemsSource="{Binding SomeList}" SelectedItem="{Binding SelectedListElement, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" >
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="#1f000000" Padding="16 8">
<Button Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBox}},
Path=DataContext.Run}" CommandParameter="{Binding}" Height="30" Width="100"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Related
I have a ListBox with each ListBoxItem inside containing a label and an image (placed inside border). When I clicked on the image inside ListBoxItem, the ListBoxItem was selected. Is there any possible way to avoid ListBoxItem being selected when clicked on the image (ListBoxItem is allowed to be selected when clicking on the area other than the image).
<ListBox ItemsSource="{Binding SymbolList}" SelectedItem="{Binding SelectedSymbol}" Style="{StaticResource WishlistListBoxStyle}"
HorizontalContentAlignment="Stretch" Width="200" Padding="0">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding}" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"/>
<Border Grid.Column="1" Visibility="Visible" CornerRadius="5" Height="20" Width="20" Margin="0 0 5 0" HorizontalAlignment="Center" VerticalAlignment="Center">
<Image Height="15" HorizontalAlignment="Center" Source="../Icons/Cross.png"/>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<i:InvokeCommandAction Command="{Binding DataContext.RemoveSymbolCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}}"
CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Style x:Key="WishlistListBoxStyle" TargetType="{x:Type ListBox}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="Background" Value="#282C2F"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="WishlistBorder" Style="{DynamicResource WishlistBorderContent}">
<ContentPresenter />
</Border>
<ControlTemplate.Resources>
<Style x:Key="WishlistBorderContent" TargetType="Border">
<Setter Property="BorderThickness" Value="0 0 0 2"/>
<Setter Property="BorderBrush" Value="#50D3D3D3"/>
</Style>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="WishlistBorder" Property="BorderThickness" Value="2"/>
<Setter TargetName="WishlistBorder" Property="BorderBrush" Value="#63C5DA"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="WishlistBorder" Property="Background" Value="#50D3D3D3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
I have the following style applied to buttons in my application
<Style x:Key="ButtonPartChooserValidation" TargetType="{x:Type Button}" BasedOn="{StaticResource ControlBaseStyle}">
<Setter Property="Background" >
<Setter.Value>
<Binding Path="(Validation.Errors)" RelativeSource="{RelativeSource Self}">
<Binding.Converter>
<converters:ValidationErrorsToBackgroundColorConverter/>
</Binding.Converter>
</Binding>
</Setter.Value>
</Setter>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding (Validation.Errors).[0].ErrorContent.Value[0], RelativeSource={x:Static RelativeSource.Self}}">
</Setter>
</Trigger>
<Trigger Property="Validation.HasError" Value="False">
<Setter Property="ToolTip" Value="Acceptable value"/>
<Setter Property="Background" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
When there is a validation error the button gets a yellow background and a tooltip displays the first item in the list of errors. The yellow background is what I am trying to achieve, but I would like to display the full list of validation errors and not just the first one. I have tried the following and just gotten an empty list displayed (just the Trigger from above for brevity, names match).
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ListBox ItemsSource="{Binding (Validation.Errors).[0].ErrorContent.Value, RelativeSource={x:Static RelativeSource.Self}}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding ErrMsg}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Setter.Value>
</Setter>
</Trigger>
I would almost certainly need two ListBox elements to display each of the lists in my object, but as of now I can't even get one to work. What am I setting up wrong?
You could bind to the Validation.Errors attached property of the PlacementTarget of the Tooltip:
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip>
<ItemsControl ItemsSource="{Binding Path=PlacementTarget.(Validation.Errors), RelativeSource={RelativeSource AncestorType=ToolTip}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ToolTip>
</Setter.Value>
</Setter>
I have a datagrid which contains a template column which holds a few buttons.
I need the color of these buttons to change from black to white when the row is selected.
Although I am not sure how can I reach "DataGridRow.IsSelected" from the buttons setters.
Here is what I tried and didn't work:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}, Path=DataContext}"
Command="{Binding ViewModel.OnRemoveDirectoryClick, ElementName=Root}">
<Button.Style>
<Style>
<Setter Property="Button.Background">
<Setter.Value>
<ImageBrush ImageSource="../../Images/menu_delete.png"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="DataGridRow.IsSelected" Value="True">
<Setter Property="Button.Background">
<Setter.Value>
<ImageBrush ImageSource="../../Images/menu_delete_white.png"/>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Thanks ahead,
Yotam
Eventually I found that I needed to use DatatTrigger with a relative source to DataGridRow
<Button.Style>
<Style>
<Setter Property="Button.Background">
<Setter.Value>
<ImageBrush ImageSource="../../Images/menu_delete.png"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" Value="True">
<Setter Property="Button.Background">
<Setter.Value>
<ImageBrush ImageSource="../../Images/menu_delete_white.png"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
An additional and perhaps more elegant way I found to tackle this problem was using a template which contains rectangle with white filling which takes the button's background as the opacity mask.
<ControlTemplate x:Key="DataGridButtonTemplate" TargetType="{x:Type Button}">
<Grid Style="{x:Null}">
<Rectangle x:Name="Mask" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Opacity="{StaticResource NormalOpacity}" Style="{x:Null}"
OpacityMask="{TemplateBinding Background}" Fill="White" Visibility="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}, Converter={StaticResource BoolToVisibilityConverter}}"/>
</Grid>
</ControlTemplate>
Try putting this style as Resource
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected"
Value="True">
<Setter Property="Foreground" TargetName="YourButtonName"
Value="YourColor" />
</Trigger>
</Style.Triggers>
</Style>
Using MVVM light, I have a control template for a custom control. There are multiple instances of this control. The style is set in Generic.xaml.
<Style TargetType="{x:Type tgvw:TimeSlotRect}">
<Setter Property="DataContext" Value="{Binding TimeSlotRectViewModel, Mode=OneWay, Source={StaticResource Locator}}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type tgvw:TimeSlotRect}">
<Border Background="{TemplateBinding Background}"
Name="TimeSlotBorder"
BorderBrush="#A5BFE1"
BorderThickness="0,0.5,0,0.5" Height="30">
<Rectangle Fill="Beige" Name="Rect">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<cmd:EventToCommand Command="{Binding MouseDownCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Rectangle>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding DataContext.IsSelected}" Value="True" >
<Setter Property="Fill" Value="Black" TargetName="Rect"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The idea is that the mouse button click fires a command in the viewmodel that sets it's IsSelected property to true and then the rectangle should pick that up and change it's fill to black - but it doesn't seem to work.
If I bind the DataTrigger to the viewmodel like this:
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding TimeSlotRectViewModel.IsSelected, Source={StaticResource Locator}}" Value="True" >
<Setter Property="Fill" Value="Black" TargetName="Rect"/>
</DataTrigger>
</ControlTemplate.Triggers>
It fires and every control changes to black. Any ideas what I'm doing wrong?
I have a Radiobutton group:
<RadioButton Name="_CreateGraph" GroupName="MapOrGraph" Content="Create Graph" />
<RadioButton Name="_CreateMap" GroupName="MapOrGraph" Content="Create Map" />
How do I bind the content of a label to the selected radio button's content?
e.g. the label should say Create Graph or Create Map depending on which radio box is created?
<Label Content="{Binding SelectedValue.Content, ElementName=list}" />
<ListBox x:Name="list" SelectedIndex="1" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem" >
<RadioButton GroupName="a" Content="{TemplateBinding Content}" IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent} }" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem>Create Graph</ListBoxItem>
<ListBoxItem>Create Map</ListBoxItem>
</ListBox>
I think you can make it shorter than what I did.
If you have only two RadioButtons, this is a quick & dirty solution:
<Label>
<Label.Style>
<Style TargetType="{x:Type Label}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=_CreateGraph}" Value="True">
<Setter Property="Content" Value="{Binding Content, ElementName=_CreateGraph}" />
</DataTrigger>
<DataTrigger Binding="{Binding IsChecked, ElementName=_CreateMap}" Value="True">
<Setter Property="Content" Value="{Binding Content, ElementName=_CreateMap}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>