Laden...

DataGrixTextColumn Binding für Header und ItemSource an unterschiedliche Quellen

Erstellt von Volki vor 3 Jahren Letzter Beitrag vor 3 Jahren 892 Views
V
Volki Themenstarter:in
3 Beiträge seit 2020
vor 3 Jahren
DataGrixTextColumn Binding für Header und ItemSource an unterschiedliche Quellen

Hallo,
ich starte gerade mit WPF und MVVM. Nun habe ich das Problem, dass ich gerne den Header und die Visibility einer DataGridTextColumn an mein ViewModel hängen möchte. Das Datagrid ist in einem Usercontrol, welches zur Laufzeit in der eigentlichen View eingebunden wird. Dieses Usercontrol übernimmt damit den Datacontext der eigentlichen View. Die ItemSource des Datagrid ist an ein Dataview aus dem VM gebunden. Bis hierhin läuft alles gut. Nun sollen Sichtbarkeit und Header einer Spalte an eine andere Eigenschaft des VM der View gebunden werden, was leider nicht mehr geht, da die Itemssource des Datagrid ja bereits an die Dataview gebunden ist und die benötigte Eigenschaft kein Bestandteil des Dataview ist.
Ich habe mittlerweile sehr viel Zeit damit verbracht zu googeln und zu probieren, ohne eine Lösung zu finden, daher wende ich mich jetzt an euch
Hier noch ein paar Snippets:

Das UserControl hat keinen eigenen DataContex, da es den aus der MainWindowView übernimmt. Ich habe im Binding des Headers schon alle möglichen Quellen probiert, aber keine hat funktioniert.

Datagrid im Usercontrol DetailsView (die letzten Zeilen sind da wohl relevant):


<DataGrid Name="DgrInput" 
                              HorizontalAlignment="Stretch"
                              AutoGenerateColumns = "false" 
                              CanUserAddRows ="False"
                              MaxHeight="500" 
                              ItemsSource="{Binding DvInput}"
                              FrozenColumnCount="2">
                        <DataGrid.Columns>
                            <DataGridTextColumn Width="Auto"   
                                                Binding="{Binding Nummer}"
                                                IsReadOnly="True"
                                                Header="MG" />
                            <DataGridTextColumn Width="Auto"
                                                Binding="{Binding Element}"
                                                IsReadOnly="True"
                                                Header="Element" />
                            <DataGridTextColumn Width="Auto"
                                                Binding="{Binding Klartext}"
                                                IsReadOnly="True"
                                                Header="Klartext" />
                            <DataGridCheckBoxColumn Width="Auto"
                                                    Binding="{Binding noTest, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                                                    IsReadOnly="False"
                                                    IsThreeState="False"
                                                    Header="N. Prüfbar">
                                <DataGridCheckBoxColumn.CellStyle>
                                    <Style TargetType="{x:Type DataGridCell}">
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding noTest, UpdateSourceTrigger=PropertyChanged}" Value="true">
                                                <Setter Property="Background" Value="Red"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                        <Setter Property="Template">
                                            <Setter.Value>
                                                <ControlTemplate TargetType="{x:Type DataGridCell}">
                                                    <Grid Background="{TemplateBinding Background}">
                                                        <ContentPresenter VerticalAlignment="Center" />
                                                    </Grid>
                                                </ControlTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </Style>
                                </DataGridCheckBoxColumn.CellStyle>
                            </DataGridCheckBoxColumn>
                            <DataGridTextColumn Width="Auto"   
                                                Binding="{Binding Typ}"
                                                IsReadOnly="True"
                                                Header="Typ" />
                            <DataGridTextColumn Width="Auto"
                                                Binding="{Binding Q1}"
                                                IsReadOnly="True"
                                                Header="{Binding Q1Header}"/>
                            <DataGridTextColumn Width="Auto"
                                                Binding="{Binding Q2}"
                                                IsReadOnly="True"
                                                Header="{Binding Path=DataContext.Q2Header, RelativeSource={RelativeSource Findancestor, AncestorType={x:Type V:MainWindowView}}}"
                                                Visibility="{Binding Q2Visibility}"/>

Die benötige Eigenschaft aus dem MainViewModel:


        public string Q2Header
        {
            get
            {
                switch (PMode)
                {
                    case 2: return "2. Halbj.";
                    default: return "Q2";
                }
            }
        }

Das betreffende DataView aus dem MainViewModel:


public DataView DvInput
        {
            get { return _DvInput; }
            set
            {
                _DvInput = value;
                OnPropertyChanged("DvInput");
                OnPropertyChanged("Q1Header");
                OnPropertyChanged("Q2Header");
                OnPropertyChanged("BQ1Header");
                OnPropertyChanged("BQ2Header");
                OnPropertyChanged("Q2Visibility");
                OnPropertyChanged("Q3Visibility");
            }
        }

MainWindowView:


<Fluent:RibbonWindow x:Class="Prueflistentool.View.MainWindowView"
                     Name="Window"       
                     xmlns:Fluent="urn:fluent-ribbon"
                     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:local="clr-namespace:Prueflistentool.View"
                     xmlns:model="clr-namespace:Prueflistentool.Model"
                     xmlns:viewmodel="clr-namespace:Prueflistentool.ViewModel"
                     xmlns:main="clr-namespace:Prueflistentool"
                     xmlns:uc="clr-namespace:Prueflistentool.UserContol"
                     mc:Ignorable="d"
                     Margin="0 3 0 0" 
                     Height="856.4" 
                     Width="1411.6"
                     WindowStartupLocation="CenterScreen" 
                     WindowState="Maximized"
                     Title="Prüflistentool"
                     FontSize="16"
                     Unloaded="AppClose"
                     Icon="/Prueflistentool;component/Prüfer.ico">
    <Fluent:RibbonWindow.DataContext>
        <viewmodel:MainWindowViewModel/>
    </Fluent:RibbonWindow.DataContext>
    <DockPanel>

<-- Hier habe ich unwichtiges gekürzt -->

        <Grid DockPanel.Dock="Top">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid.Resources>
                <DataTemplate x:Key="GrdKundenView" DataType="{x:Type viewmodel:MainWindowViewModel}">
                    <uc:DataGridKunden/>
                </DataTemplate>
                <DataTemplate x:Key="DetailsView" DataType="{x:Type viewmodel:MainWindowViewModel}">
                    <uc:DetailsView/>
                </DataTemplate>
                <DataTemplate x:Key="TestView" DataType="{x:Type viewmodel:MainWindowViewModel}">
                    <uc:DetailsView/>
                </DataTemplate>
            </Grid.Resources>
            <ContentControl Content="{Binding}">
                <ContentControl.Style>
                    <Style TargetType="{x:Type ContentControl}">
                        <Setter Property="ContentTemplate" Value="{StaticResource GrdKundenView}"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding StartArt}" Value="0">
                                <Setter Property="ContentTemplate" Value="{StaticResource GrdKundenView}"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding StartArt}" Value="1">
                                <Setter Property="ContentTemplate" Value="{StaticResource DetailsView}"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding StartArt}" Value="2">
                                <Setter Property="ContentTemplate" Value="{StaticResource TestView}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentControl.Style>
            </ContentControl>            
        </Grid>
    </DockPanel>
</Fluent:RibbonWindow>

Folgender Fehler kommt in der Ausgabe:

Fehlermeldung:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=DataContext.Q2Header; DataItem=null; target element is 'DataGridTextColumn' (HashCode=20529935); target property is 'Header' (type 'Object')

Ich hoffe das reicht aus um mir einen Tipp zu geben.
Vielen Dank im voraus.

Hinweis von Abt vor 3 Jahren

Bitte in Zukunft selbst die richtigen Editor Tags verwenden.
[Hinweis] Wie poste ich richtig?

W
955 Beiträge seit 2010
vor 3 Jahren

RelativeSource muß natürlich für den Header UND der Visibility verwendet werden.

V
Volki Themenstarter:in
3 Beiträge seit 2020
vor 3 Jahren

Ja, das ist klar. Hätte ich auch gemacht, wenn es beim Header funktioniert hätte, aber auch da ging es nicht.

W
955 Beiträge seit 2010
vor 3 Jahren

Ach so, Header ist nicht im Visual Tree. Dann vllt ein HeaderTemplate?. Antwort auf so

V
Volki Themenstarter:in
3 Beiträge seit 2020
vor 3 Jahren

Ok. Ih habe das über einen Bindingproxy (Freezable) gelöst. Geht Easy und funktioniert einwandfrei. Habe zwar nicht ganz verstanden, wie das geht, aber es geht.
Für die mit dem Gleichen Problem:

Eine neue Klasse erstellen (z. B. BindingProxy):


public class BindingProxy : Freezable
    {
        #region Overrides of Freezable

        protected override Freezable CreateInstanceCore()
        {
            return new BindingProxy();
        }

        #endregion

        public object Data
        {
            get { return GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }

Und in der XAML in den Resources deklarieren:


<-- Ausgeblendet-->
    <UserControl.Resources>
        <main:BindingProxy x:Key="bproxy" Data="{Binding}"/>
    </UserControl.Resources>
<-- Ausgeblendet-->

Und in den Elementen verwenden:


<DataGridTextColumn Width="Auto" Binding="{Binding Q1}" IsReadOnly="True" Header="{Binding Data.Q1Header, Source={StaticResource bproxy}}"/>
<DataGridTextColumn Width="Auto" Binding="{Binding Q2}" IsReadOnly="True" Header="{Binding Data.Q2Header, Source={StaticResource bproxy}}" Visibility="{Binding Data.Q2Visibility, Source={StaticResource bproxy}}"/>
<-- Ausgeblendet-->

Soweit ich das nachvollziehen kann, übernimmt der Bindingproxy hierbei jeweils den DataContext des Übergeordneten Fensters.

Vielleicht hilft es wem.