I want to change Button formating whenever the item in ItemsControl bool property is true. However, this formatting is not working.
.cs:
<ItemsControl ItemsSource="{Binding MyList}">
<ItemsControl.ItemContainerStyle>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Selected}" Value="True">
<Setter Property="Button.BorderBrush" Value="Blue"/>
</DataTrigger>
<DataTrigger Binding="{Binding Selected}" Value="False">
<Setter Property="Button.BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource ButtonStyle}">
<StackPanel Orientation="Horizontal">
<Image Style="{StaticResource ImageStyle}" Source="{Binding Icon}"/>
<TextBlock Style="{StaticResource BrightText}" Text="{Binding Title}"
</StackPanel>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I've tried to add TargetType of Button to Style with Setter property only BorderBrush but that didn't help either.
Related
In my WPF MVVM project I use INotifyDataErrorinfo to handle validation within a DataGrid. I can successfully style error cells in my "Operator" column thus:
<DataGridTemplateColumn Header="Operator" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Operator}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding OperatorId, Converter={StaticResource IsOperatorIdNullConverter}}" Value="False">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Salmon"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid>
<controls:AutoCompleteBox Text="{Binding Operator, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"
ItemsSource="{Binding Path=Data.OperatorNames, Source={StaticResource proxy}}"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="3"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
In my "OperatorType" column however this same technique doesn't work. Errors are being detected and the system default error styling is shown but my custom styling isn't. The code is:
<DataGridTemplateColumn Header="Operator type" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding OperatorType.OperatorTypeName}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget}">
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}" DisplayMemberPath="ErrorContent"/>
</ToolTip>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="Salmon"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid>
<controls:AutoCompleteBox ItemsSource="{Binding Path=Data.OperatorTypeNames, Source={StaticResource proxy}}"
ItemTemplate="{StaticResource AutoCompleteBoxItemOperatorTypeTemplate}"
SelectedItem="{Binding OperatorType, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
ValueMemberPath="OperatorTypeName"
IsTextCompletionEnabled="True"
FilterMode="Contains"
MinimumPrefixLength="3"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The only differences as far as I can see are that:
The Text in "Operator" is using bound to a POCO (Operator) while for "OperatorType" it is bound to a POCO property (OperatorType.OperatorTypeName)
The AutoCompleteBox declarations are slightly different
I've tried numerous settings for the ToolTip DataContext but nothing seems to work.
Question
What do I need to change to get the "OperatorType" customised error styling to work?
Well, it was a bit of a journey, but the solution was to set a DataContext on the TextBlock:
<TextBlock DataContext="{Binding OperatorType}" Text="{Binding OperatorTypeName}">
This causes the Trigger to be pointed at the OperatorType POCO whereas the Text in the box is taken from OperatorType.OperatorTypeName.
I've got a DataTemplate which looks like this
<DataTemplate DataType="{x:Type viewModel:TreeViewLeafViewModel}">
<StackPanel Orientation="Horizontal">
<Image Name="leafImage"/>
<TextBlock Name="leafTextBlockDisplayName" VerticalAlignment="Center"/>
<TextBlock Name="leafTextBlockKeyGesture" VerticalAlignment="Center"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Row, Converter={StaticResource MatchTypeConverter},
ConverterParameter={x:Type viewModel:TreeViewLeafViewModel}}" Value="True">
<Setter Property="Source" TargetName="leafImage" Value="{Binding Path=Row.Icon, Mode=OneTime}" />
<Setter Property="Text" TargetName="leafTextBlockDisplayName" Value="{Binding Path=Row.DisplayName, Mode=OneTime}" />
<Setter Property="Text" TargetName="leafTextBlockKeyGesture" Value="{Binding Path=Row.KeyGesture.KeyModifierString, Mode=OneTime}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I would like to replace the leafTextBlockKeyGesture by a TextBox if the IsEditing flag of the corresponding viewmodel is set to true. My Idea was to use a ContentControl inside the DataTemplate and change its Content depending on the IsEditing flag. I tried several solutions but I cannot find a working one.
Does anyone know how to do this?
Based on this answer you need something like this:
<StackPanel>
<StackPanel.Resources>
<DataTemplate x:Key="textbox">
<TextBox Text="edit me"/>
</DataTemplate>
<DataTemplate x:Key="textblock">
<TextBlock Text="can't edit"/>
</DataTemplate>
</StackPanel.Resources>
<CheckBox IsChecked="{Binding IsEditable}" Content="Editable"/>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource textblock}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditable}" Value="true">
<Setter Property="ContentTemplate" Value="{StaticResource textbox}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
Title says it all
<Page.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<DataTemplate x:Key="level1">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="GroupTitle" FontSize="16" FontWeight="Bold" Foreground="#FF000532" Text="{Binding name}"/>
<TextBlock x:Name="GroupDescription" Text="{Binding description}"/>
<TextBlock x:Name="Depth" Text="{Binding childDepth}"/>
<ItemsControl ItemsSource="{Binding settings}">
</ItemsControl>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="level2">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="GroupTitle" FontSize="16" FontWeight="Bold" Foreground="#FF000532" Text="{Binding name}"/>
<TextBlock x:Name="GroupDescription" Text="{Binding description}"/>
<TextBlock x:Name="Depth" Text="{Binding childDepth}"/>
<ItemsControl ItemsSource="{Binding settings}">
</ItemsControl>
<TabControl ItemsSource="{Binding groups}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding}" ContentTemplate="{StaticResource level1}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<ContentControl x:Name="SettingsDisplayer" Content="{Binding settingGroup, ElementName=page}">
<ContentControl.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
</ContentControl.Resources>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource level1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=childDepth}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource level1}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=childDepth}" Value="2">
<Setter Property="ContentTemplate" Value="{StaticResource level2}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=childDepth}" Value="3">
<Setter Property="ContentTemplate" Value="{StaticResource level3}" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=childDepth}" Value="4">
<Setter Property="ContentTemplate" Value="{StaticResource level4}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
The getter for childDepth is not even being accessed because I put a console trace in there to know when it is. The property is populated as it shows the proper amount when seen in the Depth TextBlock in the DataTemplates.
The relevant property in my class:
public int childDepth { get { Console.WriteLine(this.getDepth()); return this.getDepth(); } }
No mater what the childDepth is it alwayse skipps the triggers and just uses the level1 template.
I feel silly, So apparently binding the ContentControl's Content is not the equivalent of binding data to the ContentControl, thus I needed to target my DataTrigger Bindings more specifically at my original DP since it doesn't just take the parent containers binding.
This worked:
<DataTrigger Binding="{Binding settingGroup.childDepth, ElementName=page}" Value="1">
<Setter Property="ContentTemplate" Value="{StaticResource level1}" />
</DataTrigger>
There are two stackpanels on in the other.
So the first stackpanel is always visible and has a barcode.
I want the second stackpanel x:Name="Verborgen" with Visiblity "Collapsed" to have Visibility "Visible" when mouseOver, the now visible stackpanel needs to have z-Index 9999.
This is the dropbox link to the project:
https://www.dropbox.com/s/8w8horclhfwy4ub/Oefening2.zip
It doesn't work when I add this code to Window.Resources but this is kinda what I want:
<ControlTemplate x:Key="panelControl" TargetType="StackPanel">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Verborgen" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
This is the xaml
<Window.Resources>
<model:LocationType x:Key="LocationTypeInstance"/>
<DataTemplate x:Key="WastebinTemplate">
<ContentControl map:MapLayer.Position="{Binding GeoLocation}">
<ContentControl.Content>
<StackPanel Name="form">
<TextBlock Background="{StaticResource Blue}" Text="{Binding Barcode}"/>
<StackPanel Visibility="Collapsed" x:Name="Verborgen" Background="{StaticResource Orange}">
<Button Name="btnRemove" Content="Remove wastebin" Click="btnRemove_Click">
</Button>
<Label>Adres</Label>
<TextBox Name="txbAdres" Text="{Binding Address}"/>
<Label>Location type</Label>
<ComboBox ItemsSource="{Binding Source={StaticResource LocationTypeInstance}, Path=LocationTypes}"
DisplayMemberPath="Description" SelectedItem="{Binding LocationType}" SelectedValuePath="ID" SelectedValue="{Binding LocationType.ID}" />
<Label>Capaciteit</Label>
<Slider Minimum="0" Maximum="100" TickFrequency="10" Value="{Binding Capacity}"></Slider>
</StackPanel>
</StackPanel>
</ContentControl.Content>
</ContentControl>
</DataTemplate>
</Window.Resources>
Try this:
<Window.Resources>
<Style x:Key="Expandable" TargetType="StackPanel">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=StackPanel}, Path=IsMouseOver}" Value="True" >
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
<model:LocationType x:Key="LocationTypeInstance"/>
<DataTemplate x:Key="WastebinTemplate">
<ContentControl>
<ContentControl.Content>
<StackPanel Name="form">
<TextBlock Background="{StaticResource Blue}" Text="{Binding Barcode}"/>
<StackPanel x:Name="Verborgen" Background="{StaticResource Orange}" Style="{StaticResource Expandable}">
<Button Name="btnRemove" Content="Remove wastebin" Click="btnRemove_Click">
</Button>
<Label>Adres</Label>
<TextBox Name="txbAdres" Text="{Binding Address}"/>
<Label>Location type</Label>
<ComboBox ItemsSource="{Binding Source={StaticResource LocationTypeInstance}, Path=LocationTypes}"
DisplayMemberPath="Description" SelectedItem="{Binding LocationType}" SelectedValuePath="ID" SelectedValue="{Binding LocationType.ID}" />
<Label>Capaciteit</Label>
<Slider Minimum="0" Maximum="100" TickFrequency="10" Value="{Binding Capacity}"></Slider>
</StackPanel>
</StackPanel>
</ContentControl.Content>
</ContentControl>
</DataTemplate>
</Window.Resources>
I have the following Listbox:
<ListBox Margin="5" Grid.Column="0" Name="ListboxSelectUpdate">
<ListBox.ItemTemplate>
<DataTemplate>
<ProgressBar Visibility="Visible">
<ProgressBar.Style>
<Style TargetType="{x:Type ProgressBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding Progress}" Value="0">
<Setter Property="Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
<ProgressBar.Template>
<ControlTemplate>
<AdornedElementPlaceholder Name="adorner">
<Grid>
<TextBlock Width="70" FontStyle="Italic" FontWeight="Bold">Version:</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding Path=Version}"></TextBlock>
</Grid>
</AdornedElementPlaceholder>
</ControlTemplate>
</ProgressBar.Template>
</ProgressBar>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this Listbox I want to show different available Updates / Versions for a program.
Now I want to have a Progressbar in the Background of the ItemTemplate, which is only visible if the Progess-Property (int) is not zero. (so if the Update starts, the Progress-Property isnt zero and the Progressbar should be visible).
My Problem: I cant see anything, no Progressbar and no TexbBlocks.
Where is my misstake?
Your template is a bit wrong. You have misused AdornedElementPlaceholder element which, according to MSDN should be used only for validation templates. And you don't put things inside AdornedElementPlaceholder, it's a place where decorated control is put. If you want to stack controls on top of each other then use Grid. Try this ListBox template instead:
<ListBox Margin="5" ItemsSource="{Binding Path=MyList}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ProgressBar Minimum="0" Maximum="100" Value="{Binding Progress, Mode=OneWay}">
<ProgressBar.Style>
<Style TargetType="{x:Type ProgressBar}">
<Style.Triggers>
<DataTrigger Binding="{Binding Progress}" Value="0">
<Setter Property="Visibility" Value="Hidden"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
<StackPanel Orientation="Horizontal">
<TextBlock Width="70" FontStyle="Italic" FontWeight="Bold">Version:</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding Path=Version}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>