Style TreeviewItem layout (MVVM) - c#

I have a TreeView to which I bind a ObservableCollection where TreeView inherits TreeViewItem.
I want to style the header of the tree view to have a image in front of each header. I setted the header to the ItemContainerStyle but it did not chnage its layout. However it works for the ContextMenu.
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="ToolTip" Value="{Binding ID, Mode=TwoWay}"/>
<Setter Property="Header">
<Setter.Value>
<StackPanel Orientation="Horizontal">
<Image Source="Images/Icons/Plus-48.png" Height="10" Width="10" />
<TextBlock Text="{Binding MachinePartName}" Margin="0,0,4,0" />
</StackPanel>
</Setter.Value>
</Setter>
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu>
<MenuItem Header="Add" Command="{Binding AddMachinePart_Command}"/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>

You need to use HeaderTemplate instead:
<Setter Property="Header"
Value="{Binding }" />
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="Images/Icons/Plus-48.png"
Height="10"
Width="10" />
<TextBlock Text="{Binding MachinePartName}"
Margin="0,0,4,0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
Don't forget to bind Header property.

Related

How to show a value which is not bound by the CategoryPath or ValuePath inside the Telerik's RadCartesianChart's Tooltip?

I'm working with a telerik RadCartesianChart. And I'm supposed to show a tooltip which conveys the information about the series inide the chart (such as the date, the value, the title of the series). I was able to show the date and value which were already bound in the CategoryPath and the ValuePath of the chart respectively. But I have no clue how to show the title of the series which belongs to the same data source but not bound by either the CategoryPath or the ValuePath.
Below is what I have done so far.
<telerik:RadCartesianChart x:Name="chart" Margin="0,10,0,36" Width="auto" Grid.RowSpan="2">
<telerik:RadCartesianChart.Behaviors>
<telerik:ChartTooltipBehavior HorizontalOffset="-11" VerticalOffset="-50" />
</telerik:RadCartesianChart.Behaviors>
<telerik:RadCartesianChart.TooltipTemplate>
<DataTemplate>
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1" Padding="5" CornerRadius="3">
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Category}" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Value, StringFormat=\{0:N2\}}" />
</StackPanel>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</telerik:RadCartesianChart.TooltipTemplate>
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:DateTimeCategoricalAxis
x:Name="datetimeAxis"
LabelFitMode="MultiLine"
LabelFormat="{Binding Tab.CurrentPoC.LabelFormat}"
LabelInterval="1"
LabelOffset="0"
LabelRotationAngle="270"
LabelStyle="{DynamicResource LabelStyle}"
LastLabelVisibility="Visible"
LineDashArray="1 1"
LineStroke="{DynamicResource CouleurTexte}"
LineThickness="1"
MajorTickInterval="1"
MajorTickLength="1"
PlotMode="OnTicks"
SmartLabelsMode="SmartStep"
TickThickness="5"
ZIndex="0" Height="5" />
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis Foreground="White" LastLabelVisibility="Visible" HorizontalLocation="Right"/>
</telerik:RadCartesianChart.VerticalAxis>
<telerik:RadCartesianChart.Grid>
<telerik:CartesianChartGrid MajorLinesVisibility="Y" />
</telerik:RadCartesianChart.Grid>
<telerik:RadCartesianChart.Resources>
<Style x:Key="AxisLineStyle" TargetType="{x:Type telerik:LinearAxis}" >
<Setter Property="Foreground" Value="{Binding ColorName, Mode=TwoWay, Converter={StaticResource NVarToBrushConverter}}"/>
<Setter Property="Background" Value="{Binding ColorName, Mode=TwoWay, Converter={StaticResource NVarToBrushConverter}}"/>
</Style>
<DataTemplate x:Key="ellipseTemplate">
<Ellipse Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}"/>
</DataTemplate>
<DataTemplate x:Key="rectangleTemplate">
<Rectangle Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>
<DataTemplate x:Key="triangleTemplate">
<Polygon Points="10,5 5,10 15,10 10,3" Stroke="GreenYellow" StrokeThickness="2" Fill="{Binding Converter={StaticResource PaletteConverter}}"/>
</DataTemplate>
<!--<DataTemplate x:Key="+Template">
<Rectangle Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>
<DataTemplate x:Key="xTemplate">
<Rectangle Height="10" Width="10" Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>-->
<Style TargetType="telerik:LineSeries" BasedOn="{StaticResource LineSeriesStyle}">
<Setter Property="LegendSettings" Value="{Binding Converter={StaticResource ChartViewLegendSettingsValueConverter}}"/>
<Setter Property="ShowLabels" Value="False"/>
<Setter Property="Stroke" Value="{Binding ColorName, Mode=TwoWay, Converter={StaticResource NVarToBrushConverter}}"/>
<Setter Property="VerticalAxis">
<Setter.Value>
<telerik:LinearAxis ElementBrush="{Binding Tab.CurrentPoC.LineSeriesColor}" HorizontalLocation="Left"/>
</Setter.Value>
</Setter>
<Setter Property="PointTemplateSelector" Value="{StaticResource templateSelector}"/>
</Style>
<Style TargetType="telerik:BarSeries" BasedOn="{StaticResource BarSeriesStyle}">
<Setter Property="CombineMode" Value="Stack"/>
<Setter Property="LegendSettings" Value="{Binding Converter={StaticResource ChartViewLegendSettingsValueConverter}}"/>
<Setter Property="ShowLabels" Value="False"/>
<Setter Property="VerticalAxis">
<Setter.Value>
<telerik:LinearAxis ElementBrush="Gray" HorizontalLocation="Right"/>
</Setter.Value>
</Setter>
<Setter Property="PointTemplate">
<Setter.Value>
<DataTemplate>
<Rectangle Fill="{Binding Converter={StaticResource PaletteConverter}}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="telerik:PointSeries" BasedOn="{StaticResource PointSeriesStyle}">
<Setter Property="LegendSettings" Value="{Binding Converter={StaticResource ChartViewLegendSettingsValueConverter}}"/>
<Setter Property="ShowLabels" Value="False"/>
<Setter Property="Width" Value="15"/>
<Setter Property="Height" Value="15"/>
<Setter Property="VerticalAxis">
<Setter.Value>
<telerik:LinearAxis ElementBrush="{Binding Tab.CurrentPoC.PointSeriesColor}" HorizontalLocation="Left" />
<!--Style="{DynamicResource AxisLineStyle}"-->
</Setter.Value>
</Setter>
<Setter Property="PointTemplateSelector" Value="{StaticResource templateSelector}"/>
</Style>
</telerik:RadCartesianChart.Resources>
<telerik:RadCartesianChart.SeriesProvider>
<telerik:ChartSeriesProvider Source="{Binding Tab.CurrentPoC.GraphsToDisplay, Mode=TwoWay}">
<telerik:ChartSeriesProvider.SeriesDescriptors>
<telerik:CategoricalSeriesDescriptor x:Name="CatSeries" CategoryPath="TimeStampX" ValuePath="ValueY" ItemsSourcePath="Data" TypePath="SerieType"/>
</telerik:ChartSeriesProvider.SeriesDescriptors>
</telerik:ChartSeriesProvider>
</telerik:RadCartesianChart.SeriesProvider>
</telerik:RadCartesianChart>
To achieve your requirement, you can use the Presenter property of the DataPoint object.
The DataPoint object is the data context passed to the TooltipTemplate.
The Presenter is a property of DataPoint which holds a reference to the series object that hosts the concrete data point.
<telerik:RadCartesianChart.TooltipTemplate>
<DataTemplate>
<TextBlock Text="{Binding Presenter.DataContext.MySeriesNameProperty}" />
</DataTemplate>
</telerik:RadCartesianChart.TooltipTemplate>
You can read a bit more about the DataPoint class in the RadChartView documentation.
I got it working by adding a new property called LegendName to the data source object. And changed the binding path like this <TextBlock Text="{Binding Path=DataItem.LegendName}"/>. Not sure whether this is the proper way but it's working as intended.

Wpf TreeView With CheckBox

I need to add "Select All" to my wpf application ,
I've tried to do a simple binding but it doesn't work .
Can Someone Please advise , performing a simple binding
or other strait forward solution ?
Here's my treeview xaml :
<TreeView Name="CurrentTreeView" Margin="5" BorderBrush="Transparent" BorderThickness="0"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsSelected" Value="{Binding IsSelected}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
<Setter Property="HeaderTemplate" >
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox
Focusable="False"
Checked="CheckedItemCurreuntSession"
Unchecked="UnCheckedItemCurreuntSession"
Name="treeChk"
Tag="{Binding Path=ChName}"
Style="{StaticResource CheckBoxStyle1}"
IsChecked="{Binding Path=IsChecked}"
VerticalAlignment="Center"/>
<TextBlock VerticalAlignment="Center" Text="{Binding}"
Margin="5"
TextOptions.TextFormattingMode="Display"
TextOptions.TextHintingMode="Auto"
/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
<Setter Property="SelectionMode" Value="Multiple"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Margin" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<CheckBox Focusable="False" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent} }">
<ContentPresenter/>
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>

Unable to resize StackPanel when IDataErrorInfo is triggered

When a TextBox element has an error The custom adorner doesn't resize the StackPanel the Textbox control lies in:
Using DockPanel.Bottom causes the adorner to overlap on the Textbox below.
The code I shamelessly lifted off http://hirenkhirsaria.blogspot.ie/2013/05/wpf-input-validation-using-mvvm.html:
<ControlTemplate.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
</ControlTemplate.Resources>
<DockPanel LastChildFill="true">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding ElementName=customAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" />
</Border>
<AdornedElementPlaceholder Name="customAdorner">
<Border BorderBrush="#DC000C" BorderThickness="1.3" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
Sure, I could use Z Index but I don't like it.
Is there a way to cause the StackPanel to resize on error?
I was thinking of adding a ContentTemplate after each Textbox control:
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
<StackPanel>
<TextBox/>
<ContentTemplate/>
</StackPanel>
The ContentTemplate generates an error info DataTemplate which I believe should cause the StackPanel to resize.
But I can't figure out how the binding to (Validation.Errors)[0].ErrorContent} should be done.
My terrible attempt:
<UserControl.Resources>
<DataTemplate x:Key="errorinfo">
<TextBlock>Hello World</TextBlock>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<StackPanel>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
</StackPanel>
<ContentControl >
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=name, Path=(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ElementName=name, Path=(Validation.Errors)[0].ErrorContent}"> </TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</StackPanel>
I can't reuse the datatemplate though!
My question is similar to: WPF- Validation -The validation error message goes behind the other controls because of AdornerDecorator
I just want a different solution.
Any ideas? Thanks
Adorner layers sit separate from the main rendering layers in WPF. A good way to think of an Adorner is simply as a graphical overlay layer which encompasses the shape of the Control it's element tags surround (similar to the behaviour of a Border for example).
You don't need a separate AdornerDecorator for every Control. This means the ideal solution would be to add the AdornerDecorator at the highest level possible such as your Window so that you are always guaranteed an Adorner scope.
I can't believe it! Figured it out myself :D
<UserControl.Resources>
<Style x:Key="textblockErrorTooltip" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Margin" Value="10 0 10 0" />
</Style>
<DataTemplate x:Key="errortemplate">
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding Path=(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
<Style x:Key="ContentControlErrorTemplate" TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{x:Null}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.HasError)}" Value="True">
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<Border Height="Auto" Margin="5,0,0,0" Background="#DC000C" CornerRadius="3" DockPanel.Dock="Right">
<TextBlock Style="{StaticResource textblockErrorTooltip}" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=Children[1].(Validation.Errors)[0].ErrorContent}"></TextBlock>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Grid.Row="4">
<Label Padding="0,0,20,0">Name:</Label>
<TextBox Padding="0,0,10,0" Width="150" x:Name="name" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
<ContentControl Style="{StaticResource ContentControlErrorTemplate}">
</ContentControl>
</StackPanel>
If you have ideas to improve it please let me know. I'm not sure how efficient it is but it works.

Filtering a ComboBox with a GroupStyle

I have a Telerik ComboBox which has a GroupStyle applied to it. I want to have it so that when the items are filtered, the group items disappear if they have no children items, and it continues up the hierarchy.
So, this is the initial setup:
Current:
Desired:
For reference:
GroupItem Style
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander Header="{Binding Path=Name}">
<ItemsPresenter Margin="20,0,0,0" />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger
Binding="{Binding Path=Name}"
Value="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
RadComboBox
<telerik:RadComboBox
Grid.Column="1"
DisplayMemberPath="Name"
IsEditable="True"
IsFilteringEnabled="True"
ItemsSource="{Binding Path=Analyzers}"
KeyboardNavigation.TabNavigation="Local"
OpenDropDownOnFocus="True"
SelectedItem="{Binding Path=Analyzer, Mode=OneWayToSource}"
SelectedValue="{Binding Path=AnalyzerId, Converter={utilities:NullToZeroValueConverter}}"
SelectedValuePath="Id"
Style="{StaticResource ResourceKey=RadComboBoxStyle.CanDisable}"
TabIndex="2">
<telerik:RadComboBox.ItemContainerStyle>
<Style
BasedOn="{StaticResource ResourceKey=RadComboBoxItemStyle}"
TargetType="telerik:RadComboBoxItem">
<Setter Property="ToolTip" Value="{Binding Path=Description}" />
</Style>
</telerik:RadComboBox.ItemContainerStyle>
<telerik:RadComboBox.GroupStyle>
<GroupStyle />
</telerik:RadComboBox.GroupStyle>
</telerik:RadComboBox>
I found the following (related) example on the Telerik forums.
Example

listview conditional grouping

In my WPF app I have a ListView of documents with grouping of sections:
myitems.Add(new Data("document_1", "section_1"));
myitems.Add(new Data("document_1", "section_2"));
myitems.Add(new Data("document_2", "one_and_only_section"));
lv.ItemsSource = myitems;
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(lv.ItemsSource);
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("document");
This results in something that roughly looks like
< document_1
section_1
section_2
< document_2
one_and_only_section
This is in theory fine, but it is very tedious to select the "one_and_only_section" item if everything is collapsed, because it needs two clicks (first on "document_2", second on "one_and_only_section"). Ideally, the document_2 shouldn't be grouped in the same way as document_1:
< document_1
section_1
section_2
document_2
So if there is just one element to a group, it shouldn't have an expander and reveal that one element. If selected it should act as if "one_and_only_section" is selected.
Is this feasible with ListView?
I was able to produce the desired output with the following XAML code:
<ListView ItemsSource="{Binding Path=ItemsView}">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<ControlTemplate.Resources>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<TextBlock Text="{Binding Path=Section}" />
</DataTemplate>
</ControlTemplate.Resources>
<Expander Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}">
<Expander.Header>
<StackPanel Margin="0,8,0,0"
HorizontalAlignment="Stretch"
Orientation="Horizontal">
<TextBlock x:Name="Title"
VerticalAlignment="Center"
FontWeight="Bold">
<Run Text="{Binding Path=Name, Mode=OneWay}" />
<Run Text=" " />
<Run Text="{Binding Path=Items.Count, Mode=OneWay}" />
</TextBlock>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<ControlTemplate.Resources>
<DataTemplate DataType="{x:Type local:ItemViewModel}">
<TextBlock Text="{Binding Path=Document}" />
</DataTemplate>
</ControlTemplate.Resources>
<ItemsPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
You might want to add some extra attention to your expander style and the datatemplates, to make it look similar.

Categories