Hallo,
wie ich jetzt mehrfach gelesen habe, ist es nicht so ohne weiteres möglich die Visibility einer DataGridTemplateColumn /Textcolumn zu binden. Der Grund ist wohl darin zu suchen, dass - warum auch immer - die Columns nicht im VisualTree des DataGrids liegen. Damit ist dann ganz schnell klar, warum es auf alt hergebrachte Weise nicht funktionieren kann, da in diesem Fall auch kein Zugriff auf den DataContext mittels RelativeSource möglich ist. Soweit so gut.
Ich habe mehrere Lösungsvorschläge online gefunden, die sich im Prinzip alle auf zwei Lösungsansätze stützen:
a) ein Proxy-Objekt vom Typ FrameworkElement oder ContentControl, das den DataContext einer View bereitstellt und die Column-Visibility sozusagen "fernsteuert".
b) eine Relay-Klasse, die von Freezable erbt
Beide Ansätze können z. B. hier gefunden werden:
https://stackoverflow.com/questions/22073740/binding-visibility-for-datagridcolumn-in-wpf
https://www.technical-recipes.com/2017/binding-the-visibility-of-datagridcolumn-in-wpf-mvvm/
Ich versuche gerade Methode a) nachzuprogrammieren, kann aber beim besten Willen nicht feststellen, wo ich da einen Denkfehler(?) habe.
Hier mein Code:
MainWindow
<Window x:Class="VisualTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:VisualTest.ViewModels"
xmlns:local="clr-namespace:VisualTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<vm:MainViewModel/>
</Window.DataContext>
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BtVConverter"/>
</Window.Resources>
<Grid>
<StackPanel>
<FrameworkElement x:Name="dummyElement" Visibility="Collapsed"/>
<DataGrid ItemsSource="{Binding TheSource}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Meine Objekte" Binding="{Binding Labeling}">
</DataGridTextColumn>
<!--Um diese Zeile geht es: das Binding funktioniert nicht! -->
<DataGridTextColumn Header="Meine Werte" Binding="{Binding AValue}" Visibility="{Binding DataContext.IsVisible, Source={x:Reference dummyElement}}">
<!-- Es macht hier keinen Unterschied ob ich DataContext.IsVisible habe, oder wie in einem Beispiel .IsEnable-->
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<Rectangle Fill="Red" Width="20" Height="20" Visibility="{Binding IsVisible, Converter=
{StaticResource BtVConverter}}"/>
<CheckBox x:Name="ckbToggleVisibility" Content="Sichtbarkeit an/aus" Margin="20" IsChecked="{Binding IsVisible, Mode=OneWayToSource}">
</CheckBox>
<TextBlock Margin="30" Text="{Binding IsVisible, Mode=OneWay}">
</TextBlock>
</StackPanel>
</Grid>
</Window>
Mein MainViewModel:
public class MainViewModel : NotifyPropertyChangedBase
{
public ObservableCollection<MyObject> TheSource { get; set; } = new ObservableCollection<MyObject>();
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set
{
_isVisible = value;
OnPropertyChanged(ref _isVisible, value);
}
}
public MainViewModel()
{
MyObject o1 = new MyObject()
{
Labeling = "Objekt 1",
AValue = "Value 1"
};
MyObject o2 = new MyObject()
{
Labeling = "Objekt 2",
AValue = "Value 2"
};
MyObject o3 = new MyObject()
{
Labeling = "Objekt 3",
AValue = "Value 3"
};
MyObject o4 = new MyObject()
{
Labeling = "Objekt 4",
AValue = "Value 4"
};
MyObject o5 = new MyObject()
{
Labeling = "Objekt 5",
AValue = "Value 5"
};
MyObject o6 = new MyObject()
{
Labeling = "Objekt 6",
AValue = "Value 6"
};
MyObject o7 = new MyObject()
{
Labeling = "Objekt 7",
AValue = "Value 7"
};
TheSource.Add(o1);
TheSource.Add(o2);
TheSource.Add(o3);
TheSource.Add(o4);
TheSource.Add(o5);
TheSource.Add(o6);
TheSource.Add(o7);
}
Mein Daten-Model (reiner Dummy, nur für Testzwecke)
public class MyObject
{
public string Labeling { get; set; }
public string AValue { get; set; }
}
Und nur der Vollständigkeit halber --> mein Codebehind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
Ich habe auf dem MainWindow eine Checkbox, deren IsChecked-Eigenschaft an ein Property des MainViewModels gebunden ist: IsVisible. Dieses ist vom Typ bool und soll eigentlich (bei geckeckter Checkbox) dafür sorgen, dass die Werte-Spalte im DataGrid auf "collapsed" gesetzt wird.
Unter dem DataGrid befindet sich ein rotes REctangle, das an die IsVisible-Eigenschat auf dem MainViewModel gebunden ist. Wird das Häkchen bei der Checkbox gesetzt, wird das Rectangle sichtbar.
Außerdem habe ich ein TextBlock, der an IsVisible gebunden ist, und den aktuellen Staus (true oder false) in Textform ausgibt.
Mein Problem: setze ich das Häkchen bei der Checkbox, wird zwar das Rectangle sichtbar, bzw. in der Textbox wird "true" angezeigt, die DataGridColumn bleibt aber unverändert.
An welcher Stelle in meinem Code habe ich einen Fehler?
viele Grüße
Vorph
Hallo,
im gezeigten Code hast Du für das Binding an die DataGridTextColumn
keinen Converter
gesetzt, da versuchst Du also, ein bool
an ein Element zu binden, dass eine Visibility
erwartet.
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
Danke - das war in der Tat das Problem! Ich hatte jetzt so lange schon erfolglos hin und herprobiert, ich hätte das wahrscheinlich erst in ein paar Tagen bemerkt - wenn überhaupt^^
viele Grüße
Vorph
erst in ein paar Tagen
Es muß doch irgendein Fehler kommen, wenn das Binding nicht funktioniert. Wenn etwas nicht funktioniert, kann man zielgerichtet danach suchen, siehe [Artikel] MVVM und DataBinding, Abschnitt Debugging
Weeks of programming can save you hours of planning