wtorek, 5 kwietnia 2011

Silverlight Toolkit - Charting cz. 2

Wracam do tematu który poruszałem całkiem nie tak dawno a dotyczył on tworzeniu wykresów w Silverlight (wszystko co tutaj jest opisane tyczy się także WPF - przykłady są pisane przy użyciu Silverlight).
Pisałem tam o bardziej skomplikowanych rzeczach niż tylko samo stworzenie wykresu. Kolejnym etapem będzie zmiana wyglądu tooltipa któremu oprócz standardowych informacji dodamy możliwość wyświetlania na jakim polu z legendy się znajduje.






Jak widać w podstawowej wersji oprócz samego wyglądu to i same informacje które przekazuje nie przekonują do polubienia go.
Spróbujmy na początek zmienić treść podpowiedzi. W tym celu potrzebujemy zmodyfikować styl, który tworzy podpowiedź. Skąd wziąć styl, który jest domyślnie ustawiony dla wykresu? Otóż domyślne style dla każdego z wykresów znajdują się w plikach typ_wykresuDataPoint. Folder ze stylami znajduje się w miejscu gdzie zainstalowany został silverlight toolkit. W moim przypadku ścieżka do folderu to:
C:\Program Files (x86)\Microsoft SDKs\Silverlight\v4.0\Toolkit\Apr10\Source\Source code.zip\Controls.DataVisualization.Toolkit\Charting\DataPoint
Tak więc z folderu tego pobieram interesujący mnie plik stylów, czyli PieDataPoint.
Następnie tworzymy nowy słownik zasobów w projekcie (Silverlight Resource Dictionary). Wklejamy do niego następnie definicję stylu znajdującego się w pliku PieDataPoint. Po tym etapie nasz słownik powinien zawierać następujące dane:


Code:
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="charting:PieDataPoint">
        <Setter Property="Background" Value="Orange"/>
        <Setter Property="BorderBrush" Value="White"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="RatioStringFormat" Value="{}{0:p2}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="charting:PieDataPoint">
                    <Grid
                        x:Name="Root"
                        Opacity="0">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:0.1"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver">
                                    <Storyboard>
                                        <DoubleAnimation
                                            Storyboard.TargetName="MouseOverHighlight"
                                            Storyboard.TargetProperty="Opacity"
                                            To="0.6"
                                            Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="SelectionStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:0.1"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Unselected"/>
                                <VisualState x:Name="Selected">
                                    <Storyboard>
                                        <DoubleAnimation
                                            Storyboard.TargetName="SelectionHighlight"
                                            Storyboard.TargetProperty="Opacity"
                                            To="0.6"
                                            Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                            <VisualStateGroup x:Name="RevealStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:0.5"/>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Shown">
                                    <Storyboard>
                                        <DoubleAnimation
                                            Storyboard.TargetName="Root"
                                            Storyboard.TargetProperty="Opacity"
                                            To="1"
                                            Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Hidden">
                                    <Storyboard>
                                        <DoubleAnimation
                                            Storyboard.TargetName="Root"
                                            Storyboard.TargetProperty="Opacity"
                                            To="0"
                                            Duration="0"/>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <Path
                            x:Name="Slice"
                            Data="{TemplateBinding Geometry}"
                            Fill="{TemplateBinding Background}"
                            Stroke="{TemplateBinding BorderBrush}"
                            StrokeMiterLimit="1">
                            <ToolTipService.ToolTip>
                                <StackPanel>
                                    <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>
                                    <ContentControl Content="{TemplateBinding FormattedRatio}"/>
                                </StackPanel>
                            </ToolTipService.ToolTip>
                        </Path>
                        <Path
                            x:Name="SelectionHighlight"
                            Data="{TemplateBinding GeometrySelection}"
                            Fill="Red"
                            StrokeMiterLimit="1"
                            IsHitTestVisible="False"
                            Opacity="0"/>
                        <Path
                            x:Name="MouseOverHighlight"
                            Data="{TemplateBinding GeometryHighlight}"
                            Fill="White"
                            StrokeMiterLimit="1"
                            IsHitTestVisible="False"
                            Opacity="0"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Najważniejszą dla nas częścią jest ta na samym praktycznie końcu:


Code:
<ToolTipService.ToolTip>
                                <StackPanel>
                                    <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>
                                    <ContentControl Content="{TemplateBinding FormattedRatio}"/>
                                </StackPanel>
                            </ToolTipService.ToolTip>

Przed przystąpieniem do operacji uruchommy aplikację i zobaczmy czy coś się nie zmieniło:





Niestety. Jak widać cały wykres korzysta tylko z jednego koloru - pomarańczowego. Należy w takim wypadku ręcznie ustawić kolory dla danych przychodzących.
Nad tym problemem powiem - posiedziałem trochę. Na szczęście google zna odpowiedź na praktycznie każde pytanie i udało się odnaleźć rozwiązanie. 
Zanim zagooglowałem, próbowałem różnych rozwiązań. Na początek jako ofiarę wybrałem właściwość Palette. Pierwsza więc próba wyglądała następująco:


Code:
<vis:ResourceDictionaryCollection x:Key="MyPaletteColors">
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Red"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Green"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Blue"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Orange"/>
                </Style>
            </ResourceDictionary>
            <ResourceDictionary>
                <Style x:Key="DataPointStyle" TargetType="Control">
                    <Setter Property="Background" Value="Purple"/>
                </Style>
            </ResourceDictionary>
        </vis:ResourceDictionaryCollection>

Niestety po ustawieniu właściwości w wykresie nic się nie zmieniło:


Code:
<toolkit:Chart Name="chrtAverageSalaary" Title="Average Salary">
            <toolkit:PieSeries DataPointStyle="{StaticResource PieStyle}" IndependentValueBinding="{Binding ItemName}" DependentValueBinding="{Binding Value}" 
                               Palette="{StaticResource MyPalette}"/>
        </toolkit:Chart>

Wykres nadal pozostawał pomarańczowy. No nic następnie spróbowałem zbindować paletę do właściwości globalnej wykresu:


Code:
<toolkit:Chart Name="chrtAverageSalaary" Title="Average Salary"  Palette="{StaticResource MyPalette}">
            <toolkit:PieSeries DataPointStyle="{StaticResource PieStyle}" IndependentValueBinding="{Binding ItemName}" DependentValueBinding="{Binding Value}" 
                              />
        </toolkit:Chart>

Jednak i tu szczał okazał się nie trafny. Stwierdzając, że niestety na dalsze próby nie ma zbyt wiele czasu rozpocząłem poszukiwania rozwiązania mojego problemu. Po kilku minutach poszukiwać znalazłem rozwiązanie problemu, które okazało się prostsze niż myślałem.
Paleta kolorów nadal była potrzebna, jednak zamiast ustawiać styl dla DataPointStyle, należy ustawić jego wartość w palecie kolorów. Spójrzmy na przykład który obrazuje poszukiwane rozwiązanie:

Okno:


Code:
<UserControl x:Class="Charting.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit" Loaded="UserControl_Loaded"
    xmlns:vis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit">
    <Grid x:Name="LayoutRoot" Background="White" >
        <toolkit:Chart Name="chrtAverageSalaary" Title="Average Salary">
            <toolkit:PieSeries Palette="{StaticResource MyPalette}" IndependentValueBinding="{Binding ItemName}" DependentValueBinding="{Binding Value}"   />
        </toolkit:Chart>
    </Grid>
</UserControl>

Styl:


Code:
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    xmlns:vis="clr-namespace:System.Windows.Controls.DataVisualization;assembly=System.Windows.Controls.DataVisualization.Toolkit"
    >

    <ControlTemplate TargetType="charting:PieDataPoint" x:Key="MyPieDataPointTemplate">
        <Grid
            x:Name="Root"
            Opacity="0">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroup x:Name="CommonStates">
                    <VisualStateGroup.Transitions>
                        <VisualTransition GeneratedDuration="0:0:0.1"/>
                    </VisualStateGroup.Transitions>
                    <VisualState x:Name="Normal"/>
                    <VisualState x:Name="MouseOver">
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetName="MouseOverHighlight"
                                Storyboard.TargetProperty="Opacity"
                                To="0.6"
                                Duration="0"/>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
                <VisualStateGroup x:Name="SelectionStates">
                    <VisualStateGroup.Transitions>
                        <VisualTransition GeneratedDuration="0:0:0.1"/>
                    </VisualStateGroup.Transitions>
                    <VisualState x:Name="Unselected"/>
                    <VisualState x:Name="Selected">
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetName="SelectionHighlight"
                                Storyboard.TargetProperty="Opacity"
                                To="0.6"
                                Duration="0"/>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
                <VisualStateGroup x:Name="RevealStates">
                    <VisualStateGroup.Transitions>
                        <VisualTransition GeneratedDuration="0:0:0.5"/>
                    </VisualStateGroup.Transitions>
                    <VisualState x:Name="Shown">
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetName="Root"
                                Storyboard.TargetProperty="Opacity"
                                To="1"
                                Duration="0"/>
                        </Storyboard>
                    </VisualState>
                    <VisualState x:Name="Hidden">
                        <Storyboard>
                            <DoubleAnimation
                                Storyboard.TargetName="Root"
                                Storyboard.TargetProperty="Opacity"
                                To="0"
                                Duration="0"/>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
            <Path
                x:Name="Slice"
                Data="{TemplateBinding Geometry}"
                Fill="{TemplateBinding Background}"
                Stroke="{TemplateBinding BorderBrush}"
                StrokeMiterLimit="1">
                <ToolTipService.ToolTip>
                    <StackPanel>
                        <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>
                        <ContentControl Content="{TemplateBinding FormattedRatio}"/>
                    </StackPanel>
                </ToolTipService.ToolTip>
            </Path>
            <Path
                x:Name="SelectionHighlight"
                Data="{TemplateBinding GeometrySelection}"
                Fill="Red"
                StrokeMiterLimit="1"
                IsHitTestVisible="False"
                Opacity="0"/>
            <Path
                x:Name="MouseOverHighlight"
                Data="{TemplateBinding GeometryHighlight}"
                Fill="White"
                StrokeMiterLimit="1"
                IsHitTestVisible="False"
                Opacity="0"/>
        </Grid>
    </ControlTemplate>
    
    <vis:ResourceDictionaryCollection x:Key="MyPalette">
        <!-- Blue -->
        <ResourceDictionary>
            <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
                <GradientStop Color="#FFB9D6F7"/>
                <GradientStop Color="#FF284B70" Offset="1"/>
            </RadialGradientBrush>
            <Style x:Key="DataPointStyle" TargetType="Control">
                <Setter Property="Template" Value="{StaticResource MyPieDataPointTemplate}"/>
                <Setter Property="Background" Value="{StaticResource Background}"/>
            </Style>
        </ResourceDictionary>
        <!-- Red -->
        <ResourceDictionary>
            <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
                <GradientStop Color="#FFFBB7B5"/>
                <GradientStop Color="#FF702828" Offset="1"/>
            </RadialGradientBrush>
            <Style x:Key="DataPointStyle" TargetType="Control">
                <Setter Property="Template" Value="{StaticResource MyPieDataPointTemplate}"/>
                <Setter Property="Background" Value="{StaticResource Background}"/>
            </Style>
        </ResourceDictionary>
        <!-- Light Green -->
        <ResourceDictionary>
            <RadialGradientBrush x:Key="Background" GradientOrigin="-0.1,-0.1" Center="0.075,0.015" RadiusX="1.05" RadiusY="0.9">
                <GradientStop Color="#FFB8C0AC"/>
                <GradientStop Color="#FF5F7143" Offset="1"/>
            </RadialGradientBrush>
            <Style x:Key="DataPointStyle" TargetType="Control">
                <Setter Property="Template" Value="{StaticResource MyPieDataPointTemplate}"/>
                <Setter Property="Background" Value="{StaticResource Background}"/>
            </Style>
        </ResourceDictionary>
    </vis:ResourceDictionaryCollection>
</ResourceDictionary>

Tak więc pierwszy etap - przywrócenie kolorów mamy za sobą. Czas zabrać się za ToolTip. Aby dodać informację na temat tego na czym aktualnie stoimy wystarczy dopisać jedną linijkę:


Code:
<ToolTipService.ToolTip>
                    <ToolTip>
                        <StackPanel>
                            <ContentControl Content="{TemplateBinding FormattedDependentValue}"/>
                            <ContentControl Content="{TemplateBinding FormattedRatio}"/>
                            <ContentControl Content="{TemplateBinding FormattedIndependentValue}"/>
                        </StackPanel>
                    </ToolTip>
                </ToolTipService.ToolTip>

Uzyskany efekt będzie następujący:

Brak komentarzy:

Prześlij komentarz