it-swarm.com.ru

Как скрыть столбцы таблицы данных 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; }
}

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

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

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

18
Hulda

Столбец в сетке данных - это абстрактный объект, который не отображается в визуальном дереве, поэтому вы не можете использовать RelativeSource-привязку, 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"/>
                <!-- ... -->

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

47
H.B.

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

Правка: На самом деле, это утверждение относится только к Silverlight. Посмотрите этот другой SO вопрос для получения дополнительной информации.

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

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

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

4
Scott Munro

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

<Window.Resources>

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

</Window.Resources>


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

Решение, предложенное 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;
    }
}
0
Anton Purin