Не работает Silverlight databind int к элементу управления без поиска

#silverlight #data-binding

#silverlight #привязка данных

Вопрос:

Я работаю с очень простым элементом управления без внешнего вида, и, похоже, я не могу заставить работать одну из привязок шаблона. В элементе управления у меня есть два свойства зависимости, то, которое является строкой, работает, а то, которое является int, — нет.

Код csharp выглядит следующим образом:

 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

    }
}
  

И xaml для элемента управления выглядит следующим образом:

 <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>
  

Когда я помещаю это на страницу, я вижу заголовок диаграммы (либо Set Title, либо что бы я там ни установил), но значение диаграммы никогда не отображается. Если я изменяю его тип на строку, он отображается, поэтому я, должно быть, что-то упускаю.

Ответ №1:

Проблема в том, что TemplateBinding это гораздо более примитивная операция, чем Binding . Binding это реальный класс, который включает в себя некоторые полезные функции, включая неявное преобразование строк взад и вперед между другими типами данных.

TemplateBinding это чисто инструкция разметки и, что особенно важно в вашем случае, не выполняет преобразование типов для вас. Следовательно, свойство dependency, привязанное к Text свойству TextBlock , должно быть строкой.

У вас есть два варианта:-

Один из вариантов — вместо этого использовать TemplateBinding, присвоить TextBlock имя и назначить его Text в ChartValue свойстве, измененном обратным вызовом:-

     #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();
        }
    }
  

где xaml выглядит как:-

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

Другой вариант — создать частное свойство зависимости для значения с типом 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
  

где xaml выглядит как:-

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

Обратите внимание, что ChartValueStrProperty это частное, и я не потрудился создать стандартное свойство .NET для его покрытия. TemplateBinding на самом деле принимает имя свойства, которое вы присваиваете суффиксам is с «Property», затем ищет статическое поле целевого типа.

Оба подхода имеют свои сильные и слабые стороны. Первый подход является более распространенным шаблоном, но требует немного больше кода и менее гибок (элемент управления, отображающий значение, должен быть текстовым блоком). Второй вариант более гибкий и использует меньше кода, но несколько неортодоксальный.

Комментарии:

1. Мне нравится, как работает второй, кажется, он лучше работает в моей голове.