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