Silverlight Tips – Binding DataGridColumn properties

Jan Holan       23. 1. 2012       Silverlight, XML       5985 zobrazení

Jaký je problém v následujícím příkladu XAML kódu Silverlight aplikace?

<UserControl x:Class="SilverlightApplication.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
    xmlns:local="clr-namespace:SilverlightApplication"
    xmlns:viewModels="clr-namespace:SilverlightApplication.ViewModels"
    mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <viewModels:MainViewModel x:Key="ViewModel" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" Background="White" DataContext="{Binding Source={StaticResource ViewModel}}">
        <sdk:DataGrid AutoGenerateColumns="False" ItemsSource="{Binding List}">
            <sdk:DataGrid.Columns>
                <sdk:DataGridTextColumn Binding="{Binding StringValue}" Header="{Binding HeaderText, Source={StaticResource ViewModel}}" Width="110" />
            </sdk:DataGrid.Columns>
        </sdk:DataGrid>
    </Grid>
</UserControl>

Hlavní okno této Silverlight aplikace obsahuje control DataGrid s jedním sloupcem. Pro nastavení textu nadpisu tohoto sloupce (vlastnost Header) je použit data binding, (jeho výraz se odkazuje na vlastnost HeaderText objektu MainViewModel). V Silverlight ale nejsou (na rozdíl od WPF) vlastnosti ve třídě DataGridColumn implementovány jako DependencyProperty, a tak nelze použít data binding pro nastavení jejich hodnot.

Asi nejlepší řešení toho problému, je vytvořit třídu, kde budou attached vlastnosti, které budou nastavovat původní vlastnosti sloupce datagridu. Třídu nazveme DataGridColumnBindingHelper a naimplementujeme do ní vlastnosti Header, Visibility a IsReadOnly (předpokládám, že ostatní vlastnosti původního DataGridColumn nebudou potřeba nastavovat pomoci binding). Kód třídy je následující:

/// <summary>
/// Helper class to set DataGridColumn properties via binding.
/// </summary>
public class DataGridColumnBindingHelper
{
    /// <summary>
    /// Header DependencyProperty
    /// </summary>
    public static readonly DependencyProperty HeaderProperty = DependencyProperty.RegisterAttached("Header", typeof(object), typeof(DataGridColumnBindingHelper), new PropertyMetadata(null, OnHeaderPropertyChanged));

    /// <summary>
    /// Header Property getter
    /// </summary>
    public static object GetHeader(DependencyObject source)
    {
        return (object)source.GetValue(DataGridColumnBindingHelper.HeaderProperty);
    }

    /// <summary>
    /// Header Property setter
    /// </summary>
    public static void SetHeader(DependencyObject target, object value)
    {
        target.SetValue(DataGridColumnBindingHelper.HeaderProperty, value);
    }

    private static void OnHeaderPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var column = d as DataGridColumn;
        if (column == null)
        {
            return;
        }

        column.Header = e.NewValue;
    }

    /// <summary>
    /// Visibility DependencyProperty
    /// </summary>
    public static readonly DependencyProperty VisibilityProperty = DependencyProperty.RegisterAttached("Visibility", typeof(Visibility), typeof(DataGridColumnBindingHelper), new PropertyMetadata(Visibility.Visible, OnVisibilityPropertyChanged));

    /// <summary>
    /// Visibility Property getter
    /// </summary>
    public static Visibility GetVisibility(DependencyObject source)
    {
        return (Visibility)source.GetValue(DataGridColumnBindingHelper.VisibilityProperty);
    }

    /// <summary>
    /// Visibility Property setter
    /// </summary>
    public static void SetVisibility(DependencyObject target, Visibility value)
    {
        target.SetValue(DataGridColumnBindingHelper.VisibilityProperty, value);
    }

    private static void OnVisibilityPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var column = d as DataGridColumn;
        if (column == null)
        {
            return;
        }

        column.Visibility = (Visibility)e.NewValue;
    }

    /// <summary>
    /// IsReadOnly DependencyProperty
    /// </summary>
    public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.RegisterAttached("IsReadOnly", typeof(bool), typeof(DataGridColumnBindingHelper), new PropertyMetadata(false, OnIsReadOnlyPropertyChanged));

    /// <summary>
    /// IsReadOnly Property getter
    /// </summary>
    public static bool GetIsReadOnly(DependencyObject source)
    {
        return (bool)source.GetValue(DataGridColumnBindingHelper.IsReadOnlyProperty);
    }

    /// <summary>
    /// IsReadOnly Property setter
    /// </summary>
    public static void SetIsReadOnly(DependencyObject target, Visibility value)
    {
        target.SetValue(DataGridColumnBindingHelper.IsReadOnlyProperty, value);
    }

    private static void OnIsReadOnlyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var column = d as DataGridColumn;
        if (column == null)
        {
            return;
        }

        column.IsReadOnly = Convert.ToBoolean(e.NewValue);
    }
}

Celou třídu je také možné stáhnout zde. Její použití bude následující:

<sdk:DataGridTextColumn Binding="{Binding StringValue}" local:DataGridColumnBindingHelper.Header="{Binding HeaderText, Source={StaticResource ViewModel}}" Width="110" />

A nyní je už správně text sloupce načten z našeho ViewModelu.

Pozor ale při tvorbě binding výrazů pro nastavení těchto námi definovaných vlastností sloupců DataGridu. Protože sloupce DataGridu nepřebírají DataContext od DataGridu (a také nejsou součástí visual tree), nelze na nich použít RelativeSource-binding a ElementName-binding (*) (toto platí pro Silverlight i WPF).

Pokud potřebujeme text hlavičky sloupce nastavit z nějakého Resource pro lokalizaci, tak nám tento problém nevadí, musíme s tím ale počítat pokud se potřebujeme odkázat například při použití MVVM na vlastnost ViewModelu (nejčastěji pro nastavení textu nebo Visibility sloupce). V uvedeném příkladu se na ViewModel proto odkazuje pomoci definovaného StaticResource.

Více jak řešit binding na sloupcích datagridu je možné najít zde, zde nebo zde.


(*) ElementName-binding  vrací chybu “Cannot find governing FrameworkElement or FrameworkContentElement for target element”.

 

hodnocení článku

0 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback