#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. Мне нравится, как работает второй, кажется, он лучше работает в моей голове.