web-dev-qa-db-fra.com

Comment masquer les colonnes wpf datagrid en fonction d'une propriété

J'ai l'exemple de programme WPF suivant:

Xaml:

<Window x:Class="AncestorArie.MainWindow"
        xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVis" />
    </Window.Resources>
    <Grid>
        <DataGrid AutoGenerateColumns="False" Name="Blumen" 
                  ItemsSource="{Binding Leaves}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Color}" 
                                    Header="Farbe" Width="160" />
                <DataGridTextColumn Binding="{Binding Size}" 
                                    Header="Größe" Width="60"
                                    Visibility="{Binding Path=DataContext.Flag, 
                                                RelativeSource={RelativeSource Findancestor, 
                                                AncestorType={x:Type Window}}, 
                                                Converter={StaticResource BoolToVis}}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Code derrière:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Flowers rose = new Flowers();
        rose.Leaves = new ObservableCollection<Leaf>();

        rose.Flag = false;

        Leaf L1 = new Leaf();
        L1.Color = "rot";
        L1.Size = 3;
        rose.Leaves.Add(L1);

        Leaf L2 = new Leaf();
        L2.Color = "gelb";
        L2.Size = 2;
        rose.Leaves.Add(L2);

        this.DataContext = rose;            
    }
}

Et les classes modèles sont:

public class Leaf
{
    public string Color { get; set; }
    public int Size { get; set; }
}

public class Flowers
{
    public bool Flag { get; set; }
    public ObservableCollection<Leaf> Leaves { get; set; }
}

Comme vous pouvez le constater, je souhaite masquer la deuxième colonne de la grille de données, si la propriété Flag est définie sur false. Mais ça ne marche pas. J'obtiens l'erreur de liaison suivante dans la fenêtre de sortie de Visual Studio:

Erreur System.Windows.Data: 4: Impossible de trouver la source pour la liaison avec la référence 'RelativeSource FindAncestor, AncestorType =' System.Windows.Window ', AncestorLevel =' 1 ''. BindingExpression: Path = DataContext.Flag; DataItem = null; l'élément cible est 'DataGridTextColumn' (HashCode = 44856655); propriété cible est 'Visibility' (type 'Visibility')

Quel est le problème dans mon code concernant l'attribut Visibility?

18
Hulda

Une colonne dans une grille de données est un objet abstrait qui n'apparaît pas dans l'arborescence visuelle. Par conséquent, vous ne pouvez pas utiliser RelativeSource- binding, ElementName ne fonctionnera pas non plus, car il ne trouvera pas de FrameworkContentElement déterminant, vous êtes donc dans une sorte de lien.

Une des méthodes possibles consiste à utiliser Source et x:Reference . Pour cela, vous devrez nommer votre fenêtre et déplacer la colonne vers ses ressources pour éviter une erreur de dépendance cyclique:

<Window Name="_window" ...>
    <Window.Resources>
        <DataGridTextColumn x:Key="ThatPeskyColumn"
                            Binding="{Binding Size}"
                            Visibility="{Binding DataContext.Flag, Source={x:Reference _window}, Converter={StaticResource BoolToVis}}"/>
    </Window.Resources>
    <!-- ... -->
        <DataGrid AutoGenerateColumns="False" Name="Blumen" 
                  ItemsSource="{Binding Leaves}">
            <DataGrid.Columns>
                <StaticResource ResourceKey="ThatPeskyColumn"/>
                <!-- ... -->

Très amusant.

47
H.B.

Visibility sur DataGridTextColumn n'est pas un DependencyProperty et ne peut pas être lié à la donnée. Utilisez un DataGridTemplateColumn et liez la visibilité des contrôles dans le modèle.

Edit: En fait, cette déclaration s’applique uniquement à Silverlight. Voir cette autre question SO pour plus de détails.

Comment lier DataGridColumn.Visibility?

J'ai demandé quelle était la meilleure façon de savoir si une propriété est une dépendance ici.

Comment puis-je déterminer plus facilement si une propriété est une propriété de dépendance?

4
Scott Munro

Je préférerais une approche plus élégante qui implique l’utilisation d’un Freezable.

<Window.Resources>

    <DiscreteObjectKeyFrame x:Key="FlagKey" Value="{Binding Flag}"/>

</Window.Resources>


<DataGridTextColumn ... Visibility="{Binding Value, Source={StaticResource FlagKey}, ...}" />
4
AnjumSKhan

Solution proposée par H.B. est vraiment bon et a le véritable esprit WPF MVVM. Utilisez-le si possible.

Dans mon cas particulier, quelque chose a mal tourné alors je suis sorti avec une méthode différente, mon projet n'étant pas un MVVM strict, je peux donc utiliser une solution codée.

Dans CustomView.xaml, nom attribué à la colonne:

<DataGrid>
    <DataGrid.Columns>
        <DataGridTemplateColumn x:Name="MachinesColumn" ... />
        ...

Dans CustomView.xaml.cs, nous avons une propriété simple qui modifie directement la visibilité de la colonne:

public Visibility MachinesColumnVisible
{
    get { return MachinesColumn.Visibility; }
    set
    {
        if (value == MachinesColumn.Visibility)
            return;
        MachinesColumn.Visibility = value;
    }
}
0
Anton Purin