WPF: How to show column value for a Chart.ColumnSeries? - wpf

I'm using the WPF Toolkit for a .Net 4.0 application written in C#. I have a Chart containing a Column Series bound to a dictionary. The chart works fine but I'd like to show the actual value of each column, either in a textbox below each column, in the middle of each column, or on top of each column. I've been searching for a while and haven't been able to find any information on this. I set up a style for the chart as well as the ColumnSeries, but have not made any progress yet. Any suggestions?
My Chart xaml is:
xmlns:DV="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
xmlns:DVC="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
...
<Page.Resources>
<Style x:Key="MyChart" TargetType="DVC:Chart">
<Setter Property="PlotAreaStyle">
<Setter.Value>
<Style TargetType="Grid">
<Setter Property="Background" Value="#FF2D2D30" />
</Style>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="NoLegend" TargetType="DV:Legend">
<Setter Property="Visibility" Value="Hidden" />
<Setter Property="Width" Value="0" />
</Style>
<Style x:Key="ColumnSeriesStyle" TargetType="{x:Type DVC:ColumnSeries}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DVC:ColumnSeries}">
<Canvas x:Name="PlotArea" Visibility="Visible">
<TextBox Text="{Binding Path=Value.Value}" IsReadOnly="True"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
...
<DVC:Chart Name="TempChart" Style="{StaticResource MyChart}" LegendStyle="{StaticResource NoLegend}">
<DVC:Chart.Series>
<DVC:ColumnSeries IndependentValueBinding="{Binding Path=Value.Value}"
DepdendentValueBinding="{Binding Path=Value.Value}"
ToolTip="{Binding Path=Value.Value}"
Style="{StaticResource ColumnSeriesStyle}">
<DVC:ColumnSeries.DependentRangeAxis>
<DVC:LinearAxis x:Name="TempYAxis"
</DVC:ColumnSeries.DependentRangeAxis>
</DVC:Chart.Series>
</DVC:Chart>

I managed to style my ColumnSeries with this:
<Style x:Key="ColumnSeriesStyle" TargetType="{x:Type DVC:ColumnSeries}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DVC:ColumnSeries}">
<Canvas x:Name="PlotArea" Visibility="Visible">
<!-- Actual Values -->
<ListBox x:Name="ActualValueListBox" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch"
Background="{StaticResource WindowBackground}" Foreground="#FFBB702F" BorderBrush="#FF2D2D30" ItemsSource="{Binding}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Center" FontSize="12"
Foreground="{StaticResource ValueForeground}" Background="{StaticResource ValueBackground}" Width="40"
Text="{Binding Path=Value.Value}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="1" Height="20"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DVC:ColumnSeries}}, Path=ActualWidth}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

WPF DataGridTemplateColumn background color not changing on datagrid row selected

I have below WPF Toolkit DataGrid. I have created a custom column using DataGridTemplateColumn which contains a toggle button (without text).
When datagrid row is selected, toggle button background color is correctly changed with the same color as row selection but the cell's background is not changing the color, it remains white. Why?
This is the appearance of the DataGridTemplateColumn column before and after row selection.
Before:
After:
Here the code:
<UserControl.Resources>
<ResourceDictionary>
<!-- Body content datagrid cell vertical centering -->
<Style x:Key="Body_Content_DataGrid_Centering" TargetType="{x:Type dg:DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dg:DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>
<!-- Other Stuff -->
<dg:DataGrid x:Name="MyDg"
ItemsSource="{Binding Path=ListOfItems}"
Margin="3 5 5 5"
AutoGenerateColumns="False"
CanUserAddRows="False" CanUserResizeRows="False"
SelectionMode="Single"
SelectedItem="{Binding Path=MySelectedItem}"
ColumnWidth="*"
AlternationCount="2"
Focusable="False" SelectionUnit="FullRow"
CellStyle="{StaticResource Body_Content_DataGrid_Centering}">
<dg:DataGrid.Columns>
<dg:DataGridTemplateColumn Header="Selection" Width="Auto" CanUserResize="False">
<dg:DataGridTemplateColumn.CellStyle>
<Style TargetType="dg:DataGridCell">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</dg:DataGridTemplateColumn.CellStyle>
<dg:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ToggleButton Content="" IsChecked="{Binding Path=IsSelected}">
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<StackPanel Orientation="Horizontal">
<Image MaxWidth="32" MaxHeight="32">
<Image.Style>
<Style>
<Setter Property="Image.Source" Value="/My.Graphics;component/PNG/Unchecked.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ToggleButton}}}" Value="True">
<Setter Property="Image.Source" Value="/My.Graphics;component/PNG/Checked.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<!-- <ContentPresenter Content="{TemplateBinding Content}" Margin="0,0,0,0" />-->
</StackPanel>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
</DataTemplate>
</dg:DataGridTemplateColumn.CellTemplate>
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
Finally, I have solved it, the problem was in the style declaration for the DataGridTemplateColumn.
Despite setting toggle button background to Transparent it was not working as Raviraj suggested.
Finally the solution was to change the piece of code regarding to the DataGridTemplateColumn:
<dg:DataGridTemplateColumn.CellStyle>
<Style TargetType="dg:DataGridCell">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</dg:DataGridTemplateColumn.CellStyle>
By this one:
<dg:DataGridTemplateColumn.CellStyle>
<Style TargetType="dg:DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type dg:DataGridCell}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</dg:DataGridTemplateColumn.CellStyle>
Doing this is working.
Below the result.
Before row selection:
After row selection:
Set the background color of your the column template to transparent.
Something like this:
<DataTemplate>
<ToggleButton Background="Transparent" Content="" IsChecked="{Binding Path=IsSelected}">

Trigger command when ListBox selected item changes

I am trying to set up a sort of menu using ListBox and buttons as ListBoxItems to trigger a command when selection changes, but the result is that some times the selected ListBoxItem is changed but the command is not triggered, other times the opposite. The XAML is the following:
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:TripViewModel}">
<views:TripView />
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:AddTripViewModel}">
<views:AddTripView />
</DataTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Height"
Value="50" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border>
<Grid Background="Transparent">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding"
Value="3" />
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border BorderBrush="Transparent"
BorderThickness="0"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Setter Property="Background"
Value="DarkCyan" />
</Trigger>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Background"
Value="DarkCyan" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Window.Content>
<DockPanel Margin="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Height="Auto"
Width="Auto"
LastChildFill="True">
<!-- Left Panel -->
<Border BorderBrush="Black"
BorderThickness="0,0,1,0">
<StackPanel DockPanel.Dock="Left"
Margin="0"
Background="#555D6F">
<!-- First Row: Stacco Image -->
<Image Height="183"
Width="275"
Margin="3"
Source="/Media/stacco.png" />
<!-- Second Row: Buttons -->
<ScrollViewer CanContentScroll="True"
VerticalAlignment="Stretch"
VerticalScrollBarVisibility="Auto"
Margin="0,10,0,0">
<ListBox Name="MenuButtons"
ItemsSource="{Binding PageViewModels}"
Background="#555D6F"
IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<ItemContainerTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
Margin="0" />
</ItemContainerTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</StackPanel>
</Border>
<!-- Control Area: Different View made by controls -->
<ContentControl DockPanel.Dock="Right"
Content="{Binding CurrentPageViewModel}" />
</DockPanel>
</Window.Content>
Am I doing right trying to insert a button in the ItemContainerTemplate? Would it be better to use the code behind to trigger the selection changed?

How to use different ItemsControl.ItemContainerStyle for different ItemsPanelTemplate

I have an ItemsControl which uses different ItemsPanelTemplate based on certain condition. I want to have different ItemContainerStyle for each ItemsPanelTemplate (in fact, I want ItemsContainerStyle for only one of the templates). How can I achieve that? Here is the code I am using:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="UGridItemsPanelTemplate">
<UniformGrid Name="MyUGrid" Columns="{Binding Columns}" Rows="{Binding Rows}"/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="GridItemsPanelTemplate">
<Grid Name="MyGrid" Loaded="MyGrid_Loaded"/>
</ItemsPanelTemplate>
</UserControl.Resources>
<Grid>
<!--ItemList has 1000+ items if IsMap is FALSE; using ItemsConatinerStyle in this case slows the UI down-->
<ItemsControl Name="MyPresenter" ItemsSource="{Binding ItemList}" Tag="{Binding IsMap}">
<ItemsControl.Style>
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="ItemsPanel" Value="{StaticResource UGridItemsPanelTemplate}"/>
<Style.Triggers>
<Trigger Property="Tag" Value="TRUE">
<!--I want to use ItemContainerStyle only for this template-->
<Setter Property="ItemsPanel" Value="{StaticResource GridItemsPanelTemplate}"/>
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
<!--Use this style only if IsMap is TRUE-->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Grid.Row" Value="{Binding GridRow}"/>
<Setter Property="Grid.Column" Value="{Binding GridColumn}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="Border1" Background="{Binding BorderVisible}"
BorderThickness="1" Padding="{Binding PaddingVal}">
<Button Name="ItemButton" Content="{Binding Label}" IsEnabled="{Binding IsButtonEnabled}" CommandParameter="{Binding}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
Thanks,
RDV
I found a way, When IsMap is TRUE, set ItemsContainerStyle along with ItemsPanel. Updated code is posted below:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="UGridItemsPanelTemplate">
<UniformGrid Name="MyUGrid" Columns="{Binding Columns}" Rows="{Binding Rows}"/>
</ItemsPanelTemplate>
<ItemsPanelTemplate x:Key="GridItemsPanelTemplate">
<Grid Name="MyGrid" Loaded="MyGrid_Loaded"/>
</ItemsPanelTemplate>
<Style x:Key="ClusterGridContainerStyle">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Grid.Row" Value="{Binding UnitGridRow}"/>
<Setter Property="Grid.Column" Value="{Binding UnitGridColumn}"/>
</Style>
</UserControl.Resources>
<Grid>
<!--ItemList has 1000+ items if IsMap is FALSE-->
<ItemsControl Name="MyPresenter" ItemsSource="{Binding ItemList}" Tag="{Binding IsMap}">
<ItemsControl.Style>
<Style TargetType="{x:Type ItemsControl}">
<Setter Property="ItemsPanel" Value="{StaticResource UGridItemsPanelTemplate}"/>
<Style.Triggers>
<Trigger Property="Tag" Value="TRUE">
<!--I want to use ItemContainerStyle only for this template-->
<Setter Property="ItemsPanel" Value="{StaticResource GridItemsPanelTemplate}"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource ClusterGridContainerStyle}"/>
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.Style>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border x:Name="Border1" Background="{Binding BorderVisible}"
BorderThickness="1" Padding="{Binding PaddingVal}">
<Button Name="ItemButton" Content="{Binding Label}" IsEnabled="{Binding IsButtonEnabled}" CommandParameter="{Binding}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>

Merge Style.Triggers with property Template in WPF

I want to set a style for my DataGrid, but I do not know where is the problem
the backgroud property does not work with its value in the presence of the Template property.
my code:
<Style x:Key="DataGridStyle1" TargetType="{x:Type DataGrid}">
<Setter Property="CellStyle" Value="{DynamicResource GridStyle1}"/>
</Style>
<Style x:Key="GridStyle1" TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="Background" Value="SeaGreen"/>
</Trigger>
</Style.Triggers>
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Name="DataGridCellBorder">
<ContentControl Content="{TemplateBinding Content}">
<ContentControl.ContentTemplate>
<DataTemplate>
<TextBlock Background="Transparent" TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Help me please.
You have explicitly set TextBlock background to Transparent, so it won't pick value from DataGridCell. You should bind with background of DataGridCell using RelativeSource like this:
<TextBlock Background="{Binding Background, RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=DataGridCell}}"
TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"
Height="auto" Width="auto" Text="{Binding Text}"/>

unable to drag Custom ScrollViewer in WrapPanel inside ItemsPanelTemplate

Unable to drag the scroll bar after implementing custom scrollviewer on listbox in a usercontrol.
its working fine for other usercontrols which has listbox.
Only difference between usercontrols is WrapPanel
<!--ListBoxItem Style-->
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
<Setter
Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border
x:Name="ItemBorder"
BorderBrush="Transparent"
Background="Transparent"
BorderThickness="1" Margin="15"
>
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<Setter
TargetName="ItemBorder"
Property="Background"
Value="{StaticResource G2Brush}"/>
<Setter
TargetName="ItemBorder"
Property="BorderBrush"
Value="{StaticResource G4Brush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--ListBox Style-->
<Style TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<ScrollViewer x:Name="ScrollViewer">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border x:Name="border" Background="Transparent" Margin="2">
<Grid Width="70" Height="70">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Border x:Name="borderImage" Background="Transparent" Grid.Row="0">
<Image Source="{Binding Path=FilePath}" />
</Border>
<TextBlock x:Name="ThumbFileName" Text="{Binding Path=FileName}" Grid.Row="1"
Style="{StaticResource ThumbFileName}" VerticalAlignment="Top" HorizontalAlignment="Left"
TextTrimming="CharacterEllipsis"
/>
</Grid>
</Border>
<DataTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="borderImage" Property="BorderBrush" Value="{StaticResource B1Brush}" />
<Setter TargetName="borderImage" Property="BorderThickness" Value="1" />
<Setter TargetName="ThumbFileName" Property="Foreground" Value="{StaticResource B1Brush}" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate >
<WrapPanel Margin="10"
Background="Red"
/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter
Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
</Style>
<Grid Background="Transparent">
<ListBox x:Name="reportListViewControl"
Background="Transparent"
Foreground="{StaticResource G4Brush}"
BorderThickness="0"
Style="{StaticResource ListBoxStyle}"
ItemContainerStyle="{StaticResource ListBoxItemStyle}"
Drop="reportListViewControl_Drop"
SelectionMode="Extended"
SelectionChanged="reportListViewControl_SelectionChanged"
AllowDrop="True">
</ListBox>
</Grid>
In your example WrapPanel takes all the space it needs to show its items. To enable scrollbars you can restrict it by the size of its parent, ListBox:
<ItemsPanelTemplate>
<WrapPanel Margin="10" Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"
Height="{Binding ActualHeight, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"/>
</ItemsPanelTemplate>
Or you can use UniformGrid and control it with Columns or Rows property.

Resources