Visibilidad de enlace para DataGridColumn en WPF
xaml visibility (2)
¿Cómo puedo ocultar una columna en WPF DataGrid
través de un enlace?
Esto es lo que hice:
<DataGridTextColumn Header="Column header"
Binding="{Binding ColumnValue}"
Width="100"
ElementStyle="{StaticResource DataGridRightAlign}"
Visibility="{Binding MyColumnVisibility}" />
Y esto es lo que obtuve (además de la columna aún visible):
Error de System.Windows.Data: 2: no se puede encontrar FrameworkElemento o FrameworkContentElement para el elemento de destino. BindingExpression: Path = MyColumnVisibility; DataItem = null; el elemento de destino es ''DataGridTextColumn'' (HashCode = 1460142); la propiedad de destino es ''Visibilidad'' (tipo ''Visibilidad'')
No sé lo que significa gobernar. ¿Hay algún Sr. Presidente en algún lugar de mi ventana que decide qué funciona y qué no? ¿O tendría que votar por algo?
Mientras buscaba soluciones en la web, encontré una docena de páginas con un título prometedor pero con contenidos totalmente independientes o no reproducibles. Entonces esta parece ser la primera pregunta sobre el problema. ¿Alguna idea?
En primer lugar, DataGridTextColumn
o cualquier otra columna de dataGrid admitida no se encuentra en el árbol visual de DataGrid
. Por lo tanto, de manera predeterminada no hereda DataContext
de DataGrid
. Pero funciona solo para Binding
DP y para otros DP en DataGridColumn.
Dado que no se encuentran en el mismo VisualTree, cualquier intento de obtener DataContext utilizando RelativeSource
no funcionará tan bien porque DataGrid no podrá recorrer hasta DataGrid.
Sin embargo, hay dos formas de lograrlo:
Primero usando la clase Freezable
objetos Freezable
pueden heredar el DataContext incluso cuando no están en el árbol visual o lógico. Entonces, podemos aprovechar eso para nuestro uso.
Primero crea clases Freezable
de Freezable
y Data
DP que podemos usar para enlazar en XAML:
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object),
typeof(BindingProxy));
}
Ahora, agregue una instancia de este en los recursos de DataGrid para que pueda heredar el DataContext de DataGrid y luego pueda vincularlo con su Data DP:
<DataGrid>
<DataGrid.Resources>
<local:BindingProxy x:Key="proxy" Data="{Binding}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Visibility="{Binding Data.MyColumnVisibility,
Source={StaticResource proxy}}"/>
</DataGrid.Columns>
</DataGrid>
En segundo lugar , puede hacer referencia a cualquier elemento de UI en XAML utilizando ElementName
o x:Reference
. Pero ElementName
solo funciona en el mismo árbol visual, mientras que x: Reference no tiene esa restricción.
Entonces, podemos usar eso también para nuestra ventaja. Cree un FrameworkElement
ficticio en XAML con Visibility configurado para contraerse. FrameworkElement heredará DataContext de su contenedor primario que puede ser Window o UserControl.
Y puede usar eso en DataGrid:
<FrameworkElement x:Name="dummyElement" Visibility="Collapsed"/>
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Header="Test"
Binding="{Binding Name}"
Visibility="{Binding DataContext.IsEnable,
Source={x:Reference dummyElement}}"/>
</DataGrid.Columns>
</DataGrid>
<Window.Resources>
<ResourceDictionary>
<FrameworkElement x:Key="ProxyElement" DataContext="{Binding}" />
</ResourceDictionary>
</Window.Resources>
<ContentControl Content="{StaticResource ProxyElement}" Visibility="Collapsed" />
<mch:MCHDataGrid Height="350"
AutoGenerateColumns="False"
FlowDirection="LeftToRight"
ItemsSource="{Binding PayStructures}"
SelectedItem="{Binding SelectedItem}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="70"
Header="name"
IsReadOnly="True"
Visibility="{Binding DataContext.IsShowName,
Source={StaticResource ProxyElement}}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FieldName}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</mch:MCHDataGrid>
en el modelo de vista
private Visibility _isShowName;
public Visibility IsShowName
{
get { return _isShowName; }
set
{
_isShowName = value;
OnPropertyChanged();
}
}