How to orientate chart label with WPF DataVizualization? - wpf

I have a column chart but, as you see in the screenshot, the labels are overlapping. I'd like to display them vertically or in oblique.
Here's the actual horrible result:
Here's the xaml I wrote:
<dvc:Chart Margin="4">
<dvc:ColumnSeries Title="Ticket count by department"
ItemsSource="{Binding Tickets, Converter={StaticResource GroupChartConverter}}"
IndependentValueBinding="{Binding Item1}"
DependentValueBinding="{Binding Item2}">
</dvc:ColumnSeries>
</dvc:Chart>
I found solution using template or code behind but they use so many lines of code for a not so clean result. I'm sure it's just a matter of one or two lines of code but Google is not so talkative about this...

What is wrong with using a template?
<dvc:Chart Margin="4">
<dvc:ColumnSeries Title="Ticket count by department"
ItemsSource="{Binding Tickets, Converter={StaticResource GroupChartConverter}}"
IndependentValueBinding="{Binding Item1}"
DependentValueBinding="{Binding Item2}">
<dvc:ColumnSeries.IndependentAxis>
<dvc:CategoryAxis
Orientation="X">
<dvc:CategoryAxis.AxisLabelStyle>
<Style TargetType="dvc:AxisLabel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="dvc:AxisLabel">
<TextBlock Text="{TemplateBinding FormattedContent}">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-90"/>
</TextBlock.LayoutTransform>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</dvc:CategoryAxis.AxisLabelStyle>
</dvc:CategoryAxis>
</dvc:ColumnSeries.IndependentAxis>
</dvc:ColumnSeries>
</dvc:Chart>

Related

Silverlight 3 Toolkit Chart Not all Columns show

I can't seem to find the solution to this strange problem. I have a Silverlight 3 toolkit Column chart that doesn't show all the columns. I have a data set of 10 columns and it only shows 7.
image of the graph:
<UserControl x:Class="graph.bd"
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">
<UserControl.Resources>
<Style x:Key="ColorByGradeColumn" TargetType="DVC:ColumnDataPoint">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DVC:ColumnDataPoint">
<Border Background="{Binding ColColor}"
BorderBrush="{Binding ColColor}"
BorderThickness="0.5">
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<!-- canvases and other code goes here... -->
<DVC:Chart x:Name="Graphic" Width="350" Height="250" Background="Transparent">
<DVC:Chart.Series>
<DVC:ColumnSeries Title="Fras"
IndependentValueBinding="{Binding ColName}"
DependentValueBinding="{Binding ColValue}"
DataPointStyle="{StaticResource ColorByGradeColumn}"
>
<DVC:ColumnSeries.IndependentAxis>
<DVC:CategoryAxis Orientation="X">
<DVC:CategoryAxis.AxisLabelStyle>
<Style TargetType="DVC:AxisLabel">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DVC:AxisLabel">
<Grid Width="70" ShowGridLines="True" Height="8" Background="Transparent"
HorizontalAlignment="Left" VerticalAlignment="Bottom">
<TextBlock x:Name="YAxisTitle" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}" RenderTransformOrigin="0.5,0.5" FontSize="8">
<TextBlock.RenderTransform>
<RotateTransform Angle="270" CenterX="5"/>
</TextBlock.RenderTransform>
</TextBlock>
<Grid.RenderTransform>
<RotateTransform Angle="60" ></RotateTransform>
</Grid.RenderTransform>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DVC:CategoryAxis.AxisLabelStyle>
</DVC:CategoryAxis>
</DVC:ColumnSeries.IndependentAxis>
</DVC:ColumnSeries>
</DVC:Chart.Series>
<DVC:Chart.PlotAreaStyle>
<Style TargetType="Grid">
<Setter Property="Background" Value="Black" />
</Style>
</DVC:Chart.PlotAreaStyle>
<DVC:Chart.LegendStyle>
<Style TargetType="DV:Legend">
<Setter Property="Width" Value="0"/>
<Setter Property="Height" Value="0"/>
</Style>
</DVC:Chart.LegendStyle>
<DVC:Chart.Foreground>
<SolidColorBrush Color="White"></SolidColorBrush>
</DVC:Chart.Foreground>
</DVC:Chart>
My data set is made of just 3 values: the main number which is an integer and is how high the column is, and a name for the columns which is a string and I can't show in the picture, as well as a color for the columns which binds on the style and can change on the code behind.
I also can't upgrade to silverlight 4 or higher because this page with the columns is embebed in another page which runs only on silverlight 3
EDIT: I actually have another 3 graphs in the page which work without problems, only this one is having issues. all four have the exact same code in the .xaml (obviously with different x:name) and all 4 have very similar code in the xaml.cs. Please someone help, I really need to get this issue fixed. I can provide more code if needed.
EDIT2:
I think what is happening is one of the columns is getting behind or on top of the others, but I don't understand why. None of the other graphs has this issue.
Okay, so I found out what was wrong. It turns out it was the data, one of the 10 rows that are loaded had the same value on the column that is the X axis but diffent Y value, so the chart was displaying both columns as one.
I am quite embarrassed, but I hope this will help someone out one day.

WPF/Designer: ItemContainerStyle RadioButton as ToggleButton. Works when in runtime but fails in designer

I have a ItemsControl with an ItemContainerStyle based on ToggleButton.
This works just fine at runetime, but it casts an error in the designer. (So I have to comment it out if i want to use the designer)
I populate this with code behind. Using RadioButtons.
InvalidOperationException: A style intended for type 'RadioButton' cannot be applied to type 'ContentPresenter'.
Iv lived with this for along time now, but its time to see if there is a solution!
Any ideas how to work around this?
<ItemsControl x:Name="BrushButtons"
Grid.Row="1"
Grid.Column="3"
VerticalAlignment="Bottom">
<ItemsPanelTemplate>
<StackPanel VerticalAlignment="Bottom" Orientation="Vertical" />
</ItemsPanelTemplate>
<ItemsControl.ItemContainerStyle>
<Style BasedOn="{StaticResource {x:Type ToggleButton}}" TargetType="{x:Type RadioButton}">
<Setter Property="LayoutTransform">
<Setter.Value>
<RotateTransform Angle="-90" />
</Setter.Value>
</Setter>
<Setter Property="Width" Value="70" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
Kind Regards.

Bind header textblock isEnabled to parent Groupbox isEnabled

Referencing to this question: WPF Databinding: How do I access the "parent" data context?
I wanna do something similiar, but for the header of a Groupbox (because the header does not concern with the Box is being disabled and thus is always black while the rest is light gray. This looks a bit strange to me if all the content of the box is gray, the above is gray, but the box title itself stays black.
So I tried to use the approach mentioned in the linked question by flq to simply bind the isEnabled property of the header textblock to the isEnabled property of the groupbox but it seems that my binding at some point fails and I don't know where and why exactly.
heres my current code:
<GroupBox Header="Change Steps" Grid.Row="2" Grid.ColumnSpan="3" Name="gbChangeSteps">
<GroupBox.Style>
<Style TargetType="GroupBox">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" FontWeight="Bold" Height="19" Foreground="Black" IsEnabled="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GroupBox}}, Path=isEnabled}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupBox.Style>
<!-- ... (some non relevant Content)-->
</GroupBox>
after additional research I found the post Disable groupBox including the groupBox name in WPF
that lead me, in combination with Properties->Create Databinding->Binding type->UIElement to the solution that fixed both problems, the one this question was about and the original one that lead to entire restyling, which was that letters like the small g got messed up in the header.
This is the code that fixed the issue:
<GroupBox.Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" FontWeight="Bold" Height="19" IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UIElement}}}">
<TextBlock.Style>
<Style>
<Style.Triggers>
<Trigger Property="Control.IsEnabled" Value="False">
<Setter Property="Control.Foreground" Value ="#FF6D6D6D" />
</Trigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupBox.Style>

WPF subclass Control without adding logic, just to be able to customize style and template?

I'm searching for a good way to create style-able, reusable controls in WPF. For example, I've got a twitter feed that could look something like this (much simplified):
<ItemsControl ItemsSource={Binding tweets}>
<ItemsControl.DataTemplate>
<DataTemplate TargetType="tweet">
<StackPanel>
<Image Source="{Binding user.image}" />
<TextBlock Text="{Binding text}" />
</StackPanel>
</DataTemplate>
</ItemsControl.DataTemplate>
</ItemsControl>
To make this a reusable control, I could put this in a UserControl. But doing just that would make it impossible to change the way the image part is displayed for example.
So what I find myself doing now is creating a control for the user's image, like this:
public class UserImage : Control
{
// Empty class..
}
<Style TargetType="{x:Type UserImage}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserImage}">
<Image Source="{Binding}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
// The itemscontrol datatemplate now looks like this
<DataTemplate TargetType="tweet">
<StackPanel>
<UserImage DataContext="{Binding user.image}" />
<TextBlock Text="{Binding text}" />
</StackPanel>
</DataTemplate>
Now I could do something like this to customize the appearance of the user image:
<Style TargetType="{x:Type UserImage}" BasedOn="{StaticResource {x:Type UserImage}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type UserImage}">
<Ellipse>
<Ellipse.Fill>
<ImageBrush ImageSource="{Binding}">
</Ellipse.Fill>
</Ellipse>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Even though this works, it does feel a bit inefficient and well ... wrong to have to create an "empty" control for each and every component in the custom control. Is this the way to go, or is there a cleaner way?

WPF Bind to parent property from within nested element using style

I've been trying to build a text box with a hint that's displaying while it's empty.
I'm having trouble setting the hint text from within a style.
To be precise, this works (that is, it binds correctly):
<TextBox Tag="hint text">
<TextBox.Background>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<TextBlock Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=TextBox}}" FontStyle="Italic" Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Background>
</TextBox>
but, when I move it to the Style, it doesn't:
<Style TargetType="TextBox" x:Key="stlHintbox">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" Value="">
<Setter Property="Background">
<Setter.Value>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<TextBlock Tag="inner" Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=TextBox}}"
FontStyle="Italic" Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<TextBox Tag="hint text" Style="{StaticResource stlHintbox}" />
So what's the catch? How can I bind to ancestor property from within a style?
The problem is not with the RelativeSource but with the way you are using the VisualBrush. Recall that Styles are shared between the elements you apply them to. The reason that your example doesn't work is that, in effect you are trying to share a single textbox (the one you tagged "inner") with multiple parent textboxes.
To see why this is a problem, try a thought experiment: The inner textbox gets created once (roughly speaking, this will happen when the style is created). Which of the textboxes that the style gets applied to should be chosen as the ancestor of the inner text box when you use the RelativeSource binding?
This is why DataTemplates and ControlTemplates exist in WPF. Rather than actually instantiate visuals directly, they define a template that allow multiple copies of visuals to be created as needed.
Reativesource doesn't work as expected.
It is better to create watermark textbox using control template. But your version could work:
<Window.Resources>
<Style TargetType="TextBox" x:Key="stlHintbox">
<Style.Triggers>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Mode=Self}}" Value="">
<Setter Property="TextBox.Background">
<Setter.Value>
<VisualBrush Stretch="None" Visual="{Binding ElementName=hintText}"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<TextBox Tag="hint text" x:Name="myTextBox" Style="{StaticResource stlHintbox}" />
<Border Visibility="Hidden">
<TextBlock x:Name="hintText" Text="{Binding Tag, ElementName=myTextBox}" FontStyle="Italic" Foreground="LightGray" />
</Border>
</StackPanel>

Resources