Динамическая настройка текста заголовка столбца Silverlight DataGrid
<my:DataGridTemplateColumn
CanUserResize="False"
Width="150"
Header="{Binding MeetingName, Source={StaticResource LocStrings}}"
SortMemberPath="MeetingName">
</my:DataGridTemplateColumn>
У меня есть столбец выше в сетке управления Silverlight. Но это дает мне ошибку XamlParser из-за того, как я пытаюсь установить свойство Header. Кто-нибудь делал это раньше? Я хочу сделать это для нескольких языков.
Также мой синтаксис для привязки к ресурсу правильный, потому что я попробовал это в табличке за пределами сетки.
8 ответов
Вы не можете привязать к заголовку, потому что это не FrameworkElement. Вы можете сделать текст динамическим, изменив шаблон заголовка следующим образом:
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:dataprimitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.HeaderStyle>
<Style TargetType="dataprimitives:DataGridColumnHeader">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<TextBlock Text="{Binding MeetingName, Source={StaticResource LocStrings}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</data:DataGridTemplateColumn.HeaderStyle>
</data:DataGridTemplateColumn>
Мой обходной путь состоял в том, чтобы использовать присоединенное свойство для автоматической установки привязки:
public static class DataGridColumnHelper
{
public static readonly DependencyProperty HeaderBindingProperty = DependencyProperty.RegisterAttached(
"HeaderBinding",
typeof(object),
typeof(DataGridColumnHelper),
new PropertyMetadata(null, DataGridColumnHelper.HeaderBinding_PropertyChanged));
public static object GetHeaderBinding(DependencyObject source)
{
return (object)source.GetValue(DataGridColumnHelper.HeaderBindingProperty);
}
public static void SetHeaderBinding(DependencyObject target, object value)
{
target.SetValue(DataGridColumnHelper.HeaderBindingProperty, value);
}
private static void HeaderBinding_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataGridColumn column = d as DataGridColumn;
if (column == null) { return; }
column.Header = e.NewValue;
}
}
Затем в XAML:
<data:DataGridTextColumn util:DataGridColumnHelper.HeaderBinding="{Binding MeetingName, Source={StaticResource LocStrings}}" />
Чтобы сохранить визуальный стиль от исходного заголовка, используйте ContentTemplate вместо Template:
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="<image url goes here>"/>
</DataTemplate>
</Setter.Value>
Найден интересный обходной путь, который также работает с http://wpflocalizeaddin.codeplex.com/:
Создано Slyi
Он использует IValueConverter
:
public class BindingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType().Name == "Binding")
{
ContentControl cc = new ContentControl();
cc.SetBinding(ContentControl.ContentProperty, value as Binding);
return cc;
}
else return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
И стиль для DataGridColumnHeader
<UserControl.Resources>
<local:BindingConverter x:Key="BindCon"/>
<Style x:Key="ColBinding" TargetType="dataprimitives:DataGridColumnHeader" >
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{Binding Converter={StaticResource BindCon}}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
так что вы можете сохранить ваш любимый синтаксис привязки на Header
атрибут
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<TextBox Text="binding header" x:Name="tbox" />
<data:DataGrid ItemsSource="{Binding AllPeople,Source={StaticResource folks}}" AutoGenerateColumns="False" ColumnHeaderStyle="{StaticResource ColBinding}" >
<data:DataGrid.Columns>
<data:DataGridTextColumn Binding="{Binding ID}"
Header="{Binding Text, ElementName=tbox}" />
<data:DataGridTextColumn Binding="{Binding Name}"
Header="hello" />
</data:DataGrid.Columns>
</data:DataGrid>
</StackPanel>
</Grid>
http://cid-289eaf995528b9fd.skydrive.live.com/self.aspx/Public/HeaderBinding.zip
Кажется, намного проще установить значение в коде, как упоминалось выше:
dg1.Columns[3].Header = SomeDynamicValue;
Избегает использования синтаксиса свойства Setter, который в моем случае, похоже, испортил стиль, хотя я и пытался использовать ContentTemplate, а также Template.
Одна вещь, на которой я остановился, заключалась в том, что лучше использовать dg1.Columns[3].Header
нотации, а не пытаться ссылаться на именованный столбец.
Я назвал один из моих столбцов и попытался сослаться на это в коде, но получил нулевые исключения. Использование метода Columns[index] работало хорошо, и я мог назначить заголовку текстовую строку на основе ресурсов локализации.
Обратите внимание, что в решении, предоставленном RobSiklos, Source {staticResource...} является ключом, если вы планируете передавать RelativeSource, например
Binding DataContext.SelectedHistoryTypeItem,RelativeSource={RelativeSource AncestorType=sdk:DataGrid},
это может не сработать
Почему бы просто не установить это в коде:
dg1.Columns[3].Header = SomeDynamicValue;
У меня есть какое-то решение для привязки. Поскольку вы используете DataGridTemlateColumn, создайте его подкласс и добавьте свойство типа Binding с именем, например, "HeaderBinding". Теперь вы можете привязать это свойство из XAML. Затем вы должны распространить привязку к TextBlock в DataTemplate вашего заголовка. Например, вы можете сделать это с событием OnLoaded этого TextBlock.
HeaderTextBlock.SetBinding(TextBlock.TextProperty, HeaderBinding);
Вот и все. Если у вас есть больше столбцов и вы хотите использовать только один DataTemplate, тогда это немного сложнее, но идея та же.