Как скрыть столбцы datagrid wpf в зависимости от свойства

У меня есть следующая примерная программа WPF:

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>

Код позади:

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

И классы модели:

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

Как вы можете видеть, я хочу скрыть второй столбец datagrid, если для свойства Flag установлено значение false. Но это не сработает. Я получаю следующую ошибку привязки в окне вывода Visual Studio:

Ошибка System.Windows.Data: 4: не удается найти источник для привязки с ссылка 'RelativeSource FindAncestor, AncestorType = 'System.Windows.Window', AncestorLevel = '1' '. BindingExpression: Path = DataContext.Flag; DataItem = NULL; целевой элемент "DataGridTextColumn" (HashCode = 44856655); целевое свойство "Видимость" (тип "Видимость" )

Что не так в моем коде относительно атрибута Visibility?

Ответ 1

Столбец в datagrid является абстрактным объектом, который не отображается в визуальном дереве, поэтому вы не можете использовать RelativeSource -binding, ElementName не будет работать, поскольку он не найдет управляющий элемент FrameworkContentElement, так что вы находитесь в вид привязки.

Один из способов работы - через Source и x:Reference, для этого вам нужно будет назвать ваше окно и переместить столбец в его ресурсы, чтобы избежать циклической ошибки зависимостей:

<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"/>
                <!-- ... -->

Большое удовольствие.

Ответ 2

Видимость в DataGridTextColumn не является DependencyProperty и не может быть привязана к базе данных. Используйте DataGridTemplateColumn и привяжите видимость элементов управления в шаблоне.

Изменить: На самом деле это утверждение относится только к silverlight. См. Этот другой вопрос SO для получения дополнительной информации.

Как связать DataGridColumn.Visibility?

Я спросил про самый простой способ узнать, является ли свойство зависимым здесь.

Как я могу наиболее легко определить, является ли свойство свойством зависимостей?

Ответ 3

Я бы предпочел более элегантный подход, который предполагает использование Freezable.

<Window.Resources>

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

</Window.Resources>


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

Ответ 4

Решение, предложенное H.B. действительно хорош и имеет настоящий дух WPF MVVM. Используйте его там, где это возможно.

В моем конкретном случае что-то пошло не так, поэтому я вышел другим способом, так как мой проект не является строгим MVVM, поэтому я могу использовать закодированное решение.

В имени CustomView.xaml, присвоенном столбцу:

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

В CustomView.xaml.cs у нас есть простое свойство, которое напрямую изменяет видимость столбца:

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