如何设置绑定&使用WinRT XAML Toolkit动态排列系列图表的动态值?

时间:2013-07-12 07:51:49

标签: windows-8 charts windows-runtime winrt-xaml winrt-xaml-toolkit

更新1

我发现在setter中的绑定在WinRT中不起作用。所以我从这个CodeProject article.

得到了一个帮助类

所以我的绑定会是这样的。

应该工作,但不适合我。

<Setter Property="helper:SetterValueBindingHelper.PropertyBinding">
    <Setter.Value>
        <helper:SetterValueBindingHelper
        Type="WinRTXamlToolkit.Controls.DataVisualization.Charting.LineDataPoint, WinRTXamlToolkit.Controls.DataVisualization, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
        Property="Background"
        Binding="{Binding Color}"/>
    </Setter.Value>
</Setter>

由于WinRT限制而无法正常工作

<Setter Property="Background" Value="{Binding Color}"/>

我收到ArgumentException - Unable to access DependencyProperty "Background" on type "LineDataPoint".我的代码出了什么问题?

[ContentProperty(Name = "Values")]
public class SetterValueBindingHelper
{
    /// <summary>
    /// Optional type parameter used to specify the type of an attached
    /// DependencyProperty as an assembly-qualified name, full name, or
    /// short name.
    /// </summary>
    [SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods",
        Justification = "Unambiguous in XAML.")]
    public string Type { get; set; }

    /// <summary>
    /// Property name for the normal/attached DependencyProperty on which
    /// to set the Binding.
    /// </summary>
    public string Property { get; set; }

    /// <summary>
    /// Binding to set on the specified property.
    /// </summary>
    public Binding Binding { get; set; }

    /// <summary>
    /// Collection of SetterValueBindingHelper instances to apply to the
    /// target element.
    /// </summary>
    /// <remarks>
    /// Used when multiple Bindings need to be applied to the same element.
    /// </remarks>
    public Collection<SetterValueBindingHelper> Values
    {
        get
        {
            // Defer creating collection until needed
            if (null == _values)
            {
                _values = new Collection<SetterValueBindingHelper>();
            }
            return _values;
        }
    }

    private Collection<SetterValueBindingHelper> _values;

    /// <summary>
    /// Gets the value of the PropertyBinding attached DependencyProperty.
    /// </summary>
    /// <param name="element">Element for which to get the property.</param>
    /// <returns>Value of PropertyBinding attached DependencyProperty.</returns>
    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
        Justification = "SetBinding is only available on FrameworkElement.")]
    public static SetterValueBindingHelper GetPropertyBinding(FrameworkElement element)
    {
        if (null == element)
        {
            throw new ArgumentNullException("element");
        }
        return (SetterValueBindingHelper)element.GetValue(PropertyBindingProperty);
    }

    /// <summary>
    /// Sets the value of the PropertyBinding attached DependencyProperty.
    /// </summary>
    /// <param name="element">Element on which to set the property.</param>
    /// <param name="value">Value forPropertyBinding attached DependencyProperty.</param>
    [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters",
        Justification = "SetBinding is only available on FrameworkElement.")]
    public static void SetPropertyBinding(FrameworkElement element, SetterValueBindingHelper value)
    {
        if (null == element)
        {
            throw new ArgumentNullException("element");
        }
        element.SetValue(PropertyBindingProperty, value);
    }

    /// <summary>
    /// PropertyBinding attached DependencyProperty.
    /// </summary>
    public static readonly DependencyProperty PropertyBindingProperty =
        DependencyProperty.RegisterAttached(
            "PropertyBinding",
            typeof(SetterValueBindingHelper),
            typeof(SetterValueBindingHelper),
            new PropertyMetadata(null, OnPropertyBindingPropertyChanged));

    /// <summary>
    /// Change handler for the PropertyBinding attached DependencyProperty.
    /// </summary>
    /// <param name="d">Object on which the property was changed.</param>
    /// <param name="e">Property change arguments.</param>
    private static void OnPropertyBindingPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Get/validate parameters
        var element = (FrameworkElement)d;
        var item = (SetterValueBindingHelper)(e.NewValue);

        if ((null == item.Values) || (0 == item.Values.Count))
        {
            // No children; apply the relevant binding
            ApplyBinding(element, item);
        }
        else
        {
            // Apply the bindings of each child
            foreach (var child in item.Values)
            {
                if ((null != item.Property) || (null != item.Binding))
                {
                    throw new ArgumentException(
                        "A SetterValueBindingHelper with Values may not have its Property or Binding set.");
                }
                if (0 != child.Values.Count)
                {
                    throw new ArgumentException(
                        "Values of a SetterValueBindingHelper may not have Values themselves.");
                }
                ApplyBinding(element, child);
            }
        }
    }

    /// <summary>
    /// Applies the Binding represented by the SetterValueBindingHelper.
    /// </summary>
    /// <param name="element">Element to apply the Binding to.</param>
    /// <param name="item">SetterValueBindingHelper representing the Binding.</param>
    private static void ApplyBinding(FrameworkElement element, SetterValueBindingHelper item)
    {
        if ((null == item.Property) || (null == item.Binding))
        {
            throw new ArgumentException(
                "SetterValueBindingHelper's Property and Binding must both be set to non-null values.");
        }

        // Get the type on which to set the Binding
        Type type = null;
        TypeInfo typeInfo = null;
        if (null == item.Type)
        {
            // No type specified; setting for the specified element
            type = element.GetType();
            typeInfo = type.GetTypeInfo();
        }
        else
        {
            // Try to get the type from the type system
            type = System.Type.GetType(item.Type);
            if (null == type)
            {
                // Search for the type in the list of assemblies
                foreach (var assembly in AssembliesToSearch)
                {
                    // Match on short or full name
                    typeInfo = assembly.DefinedTypes
                        .Where(t => (t.FullName == item.Type) || (t.Name == item.Type))
                        .FirstOrDefault();
                    if (null != typeInfo)
                    {
                        // Found; done searching
                        break;
                    }
                }
                if (null == typeInfo)
                {
                    // Unable to find the requested type anywhere
                    throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                                "Unable to access type \"{0}\". Try using an assembly qualified type name.",
                                                                item.Type));
                }
            }
            else
            {
                typeInfo = type.GetTypeInfo();
            }
        }

        // Get the DependencyProperty for which to set the Binding
        DependencyProperty property = null;
        var field = typeInfo.GetDeclaredProperty(item.Property + "Property"); // type.GetRuntimeField(item.Property + "Property");
        if (null != field)
        {
            property = field.GetValue(null) as DependencyProperty;
        }
        if (null == property)
        {
            // Unable to find the requsted property
            throw new ArgumentException(string.Format(CultureInfo.CurrentCulture,
                                                        "Unable to access DependencyProperty \"{0}\" on type \"{1}\".",
                                                        item.Property, type.Name));
        }

        // Set the specified Binding on the specified property
        element.SetBinding(property, item.Binding);
    }

    /// <summary>
    /// Returns a stream of assemblies to search for the provided type name.
    /// </summary>
    private static IEnumerable<Assembly> AssembliesToSearch
    {
        get
        {
            // Start with the System.Windows assembly (home of all core controls)
            yield return typeof(Control).GetTypeInfo().Assembly;
        }
    }
}

我需要在WinRT XAML Toolkit的帮助下在图表中创建n行系列。我想使用自定义样式的线条颜色,自定义数据点样式&amp;自定义工具提示。如果我有固定数量的系列,我会这样做。

<charting:Chart x:Name="LineChart" Title="Line Chart" Margin="70,0">
    <charting:LineSeries
                Title="Population 1"
                IndependentValueBinding="{Binding Name}"
                DependentValueBinding="{Binding Value}"
                IsSelectionEnabled="True">
            <charting:LineSeries.DataPointStyle>
                <Style TargetType="charting:LineDataPoint">
                    <Setter Property="Width" Value="17" />
                    <Setter Property="Height" Value="17" />
                    <Setter Property="Background" Value="Lime"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="charting:LineDataPoint">
                                <Grid>
                                    <ToolTipService.ToolTip>
                                            <ContentControl>
                                                <TextBlock TextAlignment="Center">
                                                    <Run Text="{Binding SeriesName}" />
                                                    <LineBreak />
                                                    <Run Text="{Binding Value,Converter={StaticResource MyConverter},ConverterParameter=TEST}" />
                                                </TextBlock>
                                            </ContentControl>
                                    </ToolTipService.ToolTip>
                                    <Ellipse Fill="Lime" Stroke="Lime" StrokeThickness="3" />
                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </charting:LineSeries.DataPointStyle>
        </charting:LineSeries>
</charting:Chart>

现在这里是工具提示内容&amp;线条的颜色和数据点将是动态的,即颜色将是随机的,工具提示内容将来自绑定。现在要创建动态系列,我尝试了代码隐藏方法,但是在将代码隐藏在代码背后的工具提示内容时遇到了问题。看看我背后的代码方法。

<charting:Chart x:Name="LineChart" Title="Line Chart" Margin="70,0" />

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LineSeries line;
    GenerateColors(20); //suppose I need to create 20 line series, that is dynamic value.
    for (int i = 0; i < 20; i++)
    {
        line = new LineSeries();
        line.Title = string.Format("Line [{0}]", i.ToString());
        line.IndependentValueBinding = GetBinding("Name");
        line.DependentValueBinding = GetBinding("Value");
        line.ItemsSource = GetItems();
        line.DataPointStyle = GetDataPointStyle(i);
        this.LineChart.Series.Add(line);
    }
}

private List<NameValueItem> GetItems()
{
    List<NameValueItem> items = new List<NameValueItem>();
    items.Add(new NameValueItem { Name = "Test1", Value = _random.Next(10, 100) });
    items.Add(new NameValueItem { Name = "Test2", Value = _random.Next(10, 100) });
    items.Add(new NameValueItem { Name = "Test3", Value = _random.Next(10, 100) });
    items.Add(new NameValueItem { Name = "Test4", Value = _random.Next(10, 100) });
    items.Add(new NameValueItem { Name = "Test5", Value = _random.Next(10, 100) });

    return items;
}

private Style GetDataPointStyle(int ColorIndex)
{
    Style style = new Style();
    style.TargetType = typeof(LineDataPoint);

    style.Setters.Add(new Setter(LineDataPoint.WidthProperty, 17));
    style.Setters.Add(new Setter(LineDataPoint.HeightProperty, 17));
    style.Setters.Add(new Setter(LineDataPoint.BackgroundProperty, GetColorBrush(ColorIndex)));

    return style;
}

我还尝试在xaml中创建全局样式的数据点并绑定颜色,但是当我这样做时,线条没有颜色,只有点得到颜色。这种方法如下。

<Page.Resources>
    <converter:MyConverter x:Key="MyConverter" />
    <Style TargetType="charting:LineDataPoint" x:Key="MyDataPointStyle">
        <Setter Property="Width" Value="17" />
        <Setter Property="Height" Value="17" />
        <Setter Property="Background" Value="{Binding Color}"/>
        <!-- ABOVE BINDING IS NOT WORKING, IF I PASS HARD CODED VALUE IT'S GETTING -->
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="charting:LineDataPoint">
                    <Grid>
                        <ToolTipService.ToolTip>
                            <ContentControl>
                                <TextBlock TextAlignment="Center">
                                    <Run Text="{Binding SeriesName}" />
                                    <LineBreak />
                                    <Run Text="{Binding Value,Converter={StaticResource MyConverter},ConverterParameter=TEST}" />
                                </TextBlock>
                            </ContentControl>
                        </ToolTipService.ToolTip>
                        <Ellipse Fill="{Binding Color}" Stroke="{Binding Color}" StrokeThickness="3" />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Page.Resources>

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LineSeries line;
    GenerateColors(20); //suppose I need to create 20 line series, that is dynamic value.
    for (int i = 0; i < 20; i++)
    {
        line = new LineSeries();
        line.Title = string.Format("Line [{0}]", i.ToString());
        line.IndependentValueBinding = GetBinding("Name");
        line.DependentValueBinding = GetBinding("Value");
        line.ItemsSource = GetItems();
        //line.DataPointStyle = GetDataPointStyle(i);
        line.DataPointStyle = this.Resources["MyDataPointStyle"] as Style;
        this.LineChart.Series.Add(line);
    }
}

1 个答案:

答案 0 :(得分:0)

检查是否按照我在评论中提到的将绑定属性所有者类型更改为Control,如果它不起作用 - 请查看LineDataPoint的模板 - 它有以下部分:

<Ellipse
    Stroke="{TemplateBinding BorderBrush}"
    Fill="{TemplateBinding Background}" />

您可以将TemplateBinding更改为从您的数据获取画笔的常规Binding,它应该有效。您可能希望使用LineSeries样式执行类似的操作来为线条着色。

<Polyline
    Points="{TemplateBinding Points}"
    Stroke="{TemplateBinding Background}"
    Style="{TemplateBinding PolylineStyle}" />