none
DataGridCell Binding klappt nicht wie gewünscht RRS feed

  • Frage

  • Hallo zusammen,

    ich möchte die Zellen meines DataGrids mit einem Style belegen. Es klappt mit einer Eigenschaft, nicht aber mit einer Collection.

    XAML:

    <Window.Resources> <Style x:Key="CenterCellStyle" TargetType="{x:Type DataGridCell}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type DataGridCell}"> <Border BorderThickness="1" BorderBrush="Black"> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20" FontWeight="ExtraBold" Text="{Binding }" /> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid ShowGridLines="False"> <DataGrid Name="Z" AutoGenerateColumns="False" GridLinesVisibility="None"> <DataGrid.Columns> <DataGridTextColumn Header="1" Binding="{Binding Zahl1}"
    CellStyle="{StaticResource CenterCellStyle}"/> <DataGridTextColumn Header="2" Binding="{Binding Zahl2}" /> </DataGrid.Columns>

    </DataGrid> </Grid>

    Meine Klasse

        public class Zahlen
        {
            private int _zahl1;
            private int _zahl2;
    
            public int Zahl1
            {
                get { return _zahl1; }
                set { _zahl1 = value; }
            }
    
            public int Zahl2
            {
                get { return _zahl2; }
                set { _zahl2 = value; }
            }
    
    
            private int[] _reihe = new int[2];
    
            public int[] Reihe
            {
                get { return _reihe; }
                set
                {
                    _reihe[0] = _zahl1;
                    _reihe[1] = _zahl2;
    
                }
            }
    }
    
    
        public class AlleZahlen 
        {
    
            public void Add(Zahlen z)
            {
                alles.Add(z);
            }
    
    public IList<Zahlen> alleZahlen = new List<Zahlen>();
    
        }


    Und zum Füllen des Grid:

            public void FillGrid()
            {
                int[] t1 = { 1, 2};
                int[] t2 = { 5, 9};
    
                Zahlen z1 = new Zahlen(t1);
                Zahlen z2 = new Zahlen(t2);
     
                AlleZahlen a = new AlleZahlen();
    
                a.Add(z1);
                a.Add(z2);
    
                Z.ItemsSource = a.alleZahlen;
            }

    Alles gut ohne CellBinding, aber mit gibt es Probleme. Was mache ich falsch?

    Bin für jeden Hinweis dankbar.

    Viele Grüße,

    Walter

    Mittwoch, 4. Januar 2017 14:48

Antworten

  • Hallo Walter,

    jetzt verstehe ich was du meinst. Mit dem Relativen Binding funktioniert das zwar, an deiner Stelle würde ich es jedoch trotzdem anders machen.

    Denn wenn du ein UserControl oder CustomControl dafür anlegst, kannst du dieses an beliebiger Stelle wiederverwenden. Dieses kannst du dann ggf. noch immer in dem relativ generischen Template verwenden.

    Bindings sind was tolles, aber alle relativen Bindings können zu einem echten Problem werden, wenn sich etwas an der Struktur ändert. Daher verwende ich sie auch nur dann, wenn Quelle und Ziel nur wenige Zeilen aus einander sind und wirklich zusammen gehören. Das könnte bei einem wo anders Deklarierten Style/Template schon schwierig werden.


    Viele Grüße, Tom Lambert - MVP, MCC und MSP
    Wozu Antworten markieren und Posts bewerten? Klicke hier
    Nützliche Links: .NET Quellcode | C#/VB.NET Konverter | GitHub Forum Samples | Account bestätigen (Verify Your Account)
    Ich: Webseite | Facebook | Twitter | Code Snippets | GitHub

    • Als Antwort markiert CSharp_Dev_Do Donnerstag, 5. Januar 2017 08:21
    Mittwoch, 4. Januar 2017 23:07
    Moderator
  • Hallo Tom,

    nochmals Danke für deine schnelle Reaktion. Und Sorry, offenbar scheine ich heute keine Vernünftige Kommunikation hinzubekommen.

    Es soll Spalte1 = Zahl1, Spalte2 = Zahl2 sein.

    Zu deinen Hinweisen:

    1. ToString überschreiben kenne ich aus anderen Situationen und ist hilfreich, wenn nur eine Rückgabe benötigt wird. Ich bräuchte die für jede Eigenschaft, daher leider nicht hilfreich.

    2. Das mit den Convertern wird mir mit Sicherheit irgendwann auf die Füße fallen wenn es um Validierung geht. Hier hilft mir das leider nicht weiter. Aber das wird mein nächstes Thema.

    3. Jede Eigenschaft im Style einzeln zu binden wird funktionieren, aber genau das wollte ich zwingend vermeiden. Der Style soll austauschbar und egal wo einsetzbar sein.

    Aber ich habe eine Lösung gefunden. Genau die, welche ich gesucht habe.

     
    <TextBlock Text="{Binding RelativeSource=
    {RelativeSource TemplatedParent}, Path=Content.Text}"/>

    Das Template des DataGridCell.Content ist ja ein TextBlock und kennt den original Text (ItemSource). Der TextBlock im Template eben nicht. Von daher wird der Content des TextBlocks an den Content des Templates gebunden, und siehe da, alles ist gut.  

    Tja, dass mit dem Binding in WPF ist schon so ne Sache für sich, aber so langsam blicke ich durch. Harte Schule mit endlos vielen Samples und gefühlt Millionen von Möglichkeiten. Ich liebe WPF, manchmal ;-)

    Trotzdem vielen Dank für die Zeit, die du investiert hast und nochmal Sorry für die etwas umständliche Erklärung der Situation.

    Viele Grüße und noch einen schönen Abend,

    Walter   

    • Als Antwort markiert CSharp_Dev_Do Mittwoch, 4. Januar 2017 18:30
    Mittwoch, 4. Januar 2017 18:30

Alle Antworten

  • Hallo Walter,

    was für Probleme gibt es denn? Ohne dass du exakt beschriebst was du willst und was momentan falsch ist können wir eigentlich nur raten und müssen den Code ggf. auch erst in einem Projekt testen.

    Nach einem Ausprobieren (und korrigieren der Fehler in deinem Code) würde ich sagen, dass dich Stört, dass in der ersten Spalte nur der Typname "Namespace.Zahlen" angezeigt wird.
    Das dürfte daran liegen, dass bei einem eigenen Template immer das gesamte Objekt übergeben wird, Entsprechend musst du das Binding im Template selbst anpassen:

    <ControlTemplate TargetType="{x:Type DataGridCell}">
    
        <Border BorderThickness="1" BorderBrush="Black">
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" 
                        FontSize="20" FontWeight="ExtraBold"
                        Text="{Binding Zahl1 }" />
        </Border>
    
    </ControlTemplate>


    Viele Grüße, Tom Lambert - MVP, MCC und MSP
    Wozu Antworten markieren und Posts bewerten? Klicke hier
    Nützliche Links: .NET Quellcode | C#/VB.NET Konverter | GitHub Forum Samples | Account bestätigen (Verify Your Account)
    Ich: Webseite | Facebook | Twitter | Code Snippets | GitHub

    Mittwoch, 4. Januar 2017 15:28
    Moderator
  • Hallo Tom,

    erst einmal Danke für die schnelle Antwort.  Die Lösung die du beschrieben hast, funktioniert. Aber das ist genau das Problem, es ist an eine Eigenschaft gebunden. Was ist mit den anderen? In meiner Klasse sind ca 10.

    Und ja, ich sehe Namespace.Zahlen in der ersten Spalte, da hab ich den Style drauf gelegt. In der anderen nicht, um zu verdeutlichen, das die Daten selber problemlos rüber kommen, halt nur da nicht wo das Style hinterlegt ist.

    Sorry, war wohl etwas zu undeutlich.

    Mein Prob ist also: Wie kriege ich den Style vom Binding so hin, dass es funktioniert ohne direkt an eine Eigenschaft gebunden zu werden.

    Das mit dem Border ist auch reduziert, in real ist es ein Rechteck mit Farbe, dort halt mit Textanzeige. Wollte halt nur das Wesentliche darstellen.

    Wenn du da einen Tipp für mich hast?

    Viele Grüße,

    Walter

    Mittwoch, 4. Januar 2017 15:45
  • Hallo Walter,

    wenn ich dich richtig verstehe, dann willst du in der 1. Spalte einfach alle Zahlen aus dem Array anzeigen. Da bieten sich zwei Lösungsmöglichkeiten an:

    1. Du überschreibst Zahlen.ToString, sodass dieses die Zahlenliste zurück gibt:
      public override string ToString()
      {
          return string.Join(", ", this.Reihe);
      }
      Denn Standardm'-ig wird einfach ToString aufgerufen um ein Objekt anzuzeigen. So entsteht auch die Anzeige des Klassennamens.
    2. Du benutzt einen ValueConverter. Dieser kann dann aus der gebundenen Liste/Array eine ordentlich lesbare Anzeige machen. Das geht über einen ähnlichen Weg wie unter 1.
      Siehe auch: Value conversion with IValueConverter
    3. Du nutzt zur Anzeige der Liste eine ListBox o.ä. innerhalb der Zelle. Dann musst du wiederum ein Template für dessen Childs erstellen.

    Wenn du dagegen nur ganz spezifische Eigenschaften im XAML anzeigen willst, dann musst du diese einzeln binden:

    <Border BorderThickness="1" BorderBrush="Black">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="{Binding Zahl1 }" FontSize="20" FontWeight="ExtraBold"/>
            <TextBlock Text="{Binding Zahl2 }" FontSize="20" FontWeight="ExtraBold"/>
        </StackPanel>
    </Border>


    Viele Grüße, Tom Lambert - MVP, MCC und MSP
    Wozu Antworten markieren und Posts bewerten? Klicke hier
    Nützliche Links: .NET Quellcode | C#/VB.NET Konverter | GitHub Forum Samples | Account bestätigen (Verify Your Account)
    Ich: Webseite | Facebook | Twitter | Code Snippets | GitHub

    Mittwoch, 4. Januar 2017 16:03
    Moderator
  • Hallo Tom,

    nochmals Danke für deine schnelle Reaktion. Und Sorry, offenbar scheine ich heute keine Vernünftige Kommunikation hinzubekommen.

    Es soll Spalte1 = Zahl1, Spalte2 = Zahl2 sein.

    Zu deinen Hinweisen:

    1. ToString überschreiben kenne ich aus anderen Situationen und ist hilfreich, wenn nur eine Rückgabe benötigt wird. Ich bräuchte die für jede Eigenschaft, daher leider nicht hilfreich.

    2. Das mit den Convertern wird mir mit Sicherheit irgendwann auf die Füße fallen wenn es um Validierung geht. Hier hilft mir das leider nicht weiter. Aber das wird mein nächstes Thema.

    3. Jede Eigenschaft im Style einzeln zu binden wird funktionieren, aber genau das wollte ich zwingend vermeiden. Der Style soll austauschbar und egal wo einsetzbar sein.

    Aber ich habe eine Lösung gefunden. Genau die, welche ich gesucht habe.

     
    <TextBlock Text="{Binding RelativeSource=
    {RelativeSource TemplatedParent}, Path=Content.Text}"/>

    Das Template des DataGridCell.Content ist ja ein TextBlock und kennt den original Text (ItemSource). Der TextBlock im Template eben nicht. Von daher wird der Content des TextBlocks an den Content des Templates gebunden, und siehe da, alles ist gut.  

    Tja, dass mit dem Binding in WPF ist schon so ne Sache für sich, aber so langsam blicke ich durch. Harte Schule mit endlos vielen Samples und gefühlt Millionen von Möglichkeiten. Ich liebe WPF, manchmal ;-)

    Trotzdem vielen Dank für die Zeit, die du investiert hast und nochmal Sorry für die etwas umständliche Erklärung der Situation.

    Viele Grüße und noch einen schönen Abend,

    Walter   

    • Als Antwort markiert CSharp_Dev_Do Mittwoch, 4. Januar 2017 18:30
    Mittwoch, 4. Januar 2017 18:30
  • Hallo Walter,

    jetzt verstehe ich was du meinst. Mit dem Relativen Binding funktioniert das zwar, an deiner Stelle würde ich es jedoch trotzdem anders machen.

    Denn wenn du ein UserControl oder CustomControl dafür anlegst, kannst du dieses an beliebiger Stelle wiederverwenden. Dieses kannst du dann ggf. noch immer in dem relativ generischen Template verwenden.

    Bindings sind was tolles, aber alle relativen Bindings können zu einem echten Problem werden, wenn sich etwas an der Struktur ändert. Daher verwende ich sie auch nur dann, wenn Quelle und Ziel nur wenige Zeilen aus einander sind und wirklich zusammen gehören. Das könnte bei einem wo anders Deklarierten Style/Template schon schwierig werden.


    Viele Grüße, Tom Lambert - MVP, MCC und MSP
    Wozu Antworten markieren und Posts bewerten? Klicke hier
    Nützliche Links: .NET Quellcode | C#/VB.NET Konverter | GitHub Forum Samples | Account bestätigen (Verify Your Account)
    Ich: Webseite | Facebook | Twitter | Code Snippets | GitHub

    • Als Antwort markiert CSharp_Dev_Do Donnerstag, 5. Januar 2017 08:21
    Mittwoch, 4. Januar 2017 23:07
    Moderator
  • Hallo Tom,

    danke für den Hinweis. Du hast recht. Da werde ich noch was machen müssen.

    In erster Linie ging es mir darum, dem Thema Binding etwas näher zu kommen. Ich hab nicht verstanden, warum das mit dem Binding im Style nicht so funktioniert hat wie ich es wollte.

    Die Punkte, die du angesprochen hast, werden auch noch auf mich zukommen, da alles unterm Strich hochdynamisch werden soll. Ich denke, da werden mir noch weitere Punkte um die Ohren fliegen, daher sag ich einfach mal bis Bald. 

    Viele Grüße,

    Walter

    Donnerstag, 5. Januar 2017 08:20