开发者

Silverlight databind int to lookless control not working

I am working a very simple lookless control, and I can't seem to get one of the template bindings to work. In the control I have two Dependency Properties, the one that is a string works, and the one that is an int does not.

The csharp code looks like this:

using System;
using System.Windows;
using System.Windows.Controls;

namespace ControlDemo
{
    public class TextControlLookless : Control
    {
        #region Title

        public static readonly DependencyProperty ChartTitleProperty =
            DependencyProperty.Register("ChartTitle", typeof(string), typeof(TextControlLookless),
            null);


        public String ChartTitle
        {
            get { return (string)GetValue(ChartTitleProperty); }
            set
            {
                SetValue(ChartTitleProperty, value);
            }
        }

        #endregion

        #region Value

        public static readonly DependencyProperty ChartValueProperty =
            DependencyProperty.Register("ChartValue", typeof(int), typeof(TextControlLookless),
            null);


        public int ChartValue
        {
            get { return (int)GetValue(ChartValueProperty); }
            set
            {
                SetValue(ChartValueProperty, value);
            }
        }

        #endregion

        #region ctor

        public TextControlLookless()
        {
            this.DefaultStyleKey = typeof(TextControlLookless);
        }

        #endregion

    }
}

And the xaml for the control looks like this:

<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ControlDemo">

<Style TargetType="local:TextControlLookless">
    <Setter Property="ChartTitle" Value="Set Title" />
    <Setter Property="ChartValue" Value="1" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:TextControlLookless">
                <Grid x:Name="Root">
                    <Border BorderBrush="Black" BorderThickness="2">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition />
                            </Grid.RowDefinitions>
                            <TextBlock Text="{TemplateBinding ChartTitle}" />
                            <TextBlock Text="{TemplateBinding ChartValue}" Grid.Row="1" />
                        </Grid>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

When I put this on a page, I can s开发者_开发百科ee the ChartTitle (either Set Title, or whatever I set it to), but the ChartValue never shows up. If I change its type to a string, it does show up, so I must be missing something.


The problem is that TemplateBinding is a far more primitive operation than Binding. Binding is an actual class and includes some helpful features including the implicit conversion of strings back and forth between other data types.

TemplateBinding is purely a markup instruction and crucially in your case does not do type conversion for you. Hence the dependency property being bound to a Text property of a TextBlock must be a string.

You have two choices:-

One choice is instead using TemplateBinding give the TextBlock a name and assign its Text in the ChartValue property changed call back:-

    #region Value

    public static readonly DependencyProperty ChartValueProperty =
        DependencyProperty.Register("ChartValue", typeof(int), typeof(TextControlLookless),
        new PropertyMetadata(0, OnChartValuePropertyChanged));

    private static void OnChartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextControlLookless source = d as TextControlLookless;
        source.Refresh();
    }


    public int ChartValue
    {
        get { return (int)GetValue(ChartValueProperty); }
        set
        {
            SetValue(ChartValueProperty, value);
        }
    }

    #endregion

    private TextBlock txtChartValue { get; set; }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        txtChartValue = GetTemplateChild("txtChartValue") as TextBlock;
        Refresh();
    }

    private void Refresh()
    {
        if (txtChartValue != null)
        {
            txtChartValue.Text = ChartValue.ToString();
        }
    }

where the xaml looks like:-

    <TextBlock x:Name="txtChartValue" Grid.Row="1" />

The other choice is to create a private dependency property for the value with type of string:-

        #region Value

        public static readonly DependencyProperty ChartValueProperty =
            DependencyProperty.Register("ChartValue", typeof(int), typeof(TextControlLookless),
            new PropertyMetadata(0, OnChartValuePropertyChanged));

        private static void OnChartValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            d.SetValue(ChartValueStrProperty, e.NewValue.ToString());
        }

        private static readonly DependencyProperty ChartValueStrProperty =
            DependencyProperty.Register("ChartValueStr", typeof(string), typeof(TextControlLookless),
            new PropertyMetadata("0"));

        public int ChartValue
        {
            get { return (int)GetValue(ChartValueProperty); }
            set
            {
                SetValue(ChartValueProperty, value);
            }
        }

        #endregion

where the xaml looks like:-

        <TextBlock Text="{TemplateBinding ChartValueStr}" Grid.Row="1" />

Note that the ChartValueStrProperty is private and I haven't bothered creating a standard .NET property to cover it. TemplateBinding actually takes the property name you assign suffixes is with "Property" then looks for a static field on the target type.

Both approaches have their strengths and weaknesses. The first approach is the more common pattern but takes a little more code and is less flexiable (the control displaying the value must be a TextBlock). The second is more flexiable and uses less code but is somewhat unorthodox.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜