myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
» Regeln
» Wie poste ich richtig?
» Forum-FAQ

Mitglieder
» Liste / Suche
» Wer ist wo online?

Ressourcen
» openbook: Visual C#
» openbook: OO
» Microsoft Docs

Team
» Kontakt
» Übersicht
» Wir über uns

» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » GUI: WPF und XAML » ComboBox-Contet Textblock formatieren (Schriftfarbe setzen) plus Binding
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

ComboBox-Contet Textblock formatieren (Schriftfarbe setzen) plus Binding

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 118
Entwicklungsumgebung: Visual Studio 2013


GeneVorph ist offline

ComboBox-Contet Textblock formatieren (Schriftfarbe setzen) plus Binding

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

bei meinem Lernprojekt habe ich eine einfache Sache vor, stelle aber gerade fest, dass es scheinbar doch nicht so leicht ist.

Ich habe ein userControl, in dem sich ein TextBlock befindet. Dieser soll später im Projekt den enthaltenen Text je nach Zustand eines Propertys in verschiedenen Farben anzeigen.
Ich habe:

XML-Code:
<UserControl>
<StackPanel Orientation="Horizontal">
        <ComboBox x:Name="combo" Margin="10" MinWidth="60" VerticalAlignment="Center" ItemsSource="{Binding Source={StaticResource ItemListSortedView}}" SelectedIndex="{Binding TheIndex, Mode=TwoWay}" SelectedItem="{Binding TheValue, Mode=TwoWay}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <i:InvokeCommandAction Command="{Binding SelectionChangedCommand}"/>
                </i:EventTrigger>
                <i:EventTrigger EventName="DropDownOpened">
                    <i:InvokeCommandAction Command="{Binding SetOldValueCommand}" CommandParameter="{Binding ElementName=combo, Path=SelectedItem}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>

<!-- Hier der relevante Code-Teil -->
   <ComboBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}" Foreground="{Binding Path=TheColor}"/>
                </DataTemplate>
            </ComboBox.ItemTemplate>
<!-- bis hier -->
        </ComboBox>
        <TextBox Margin="10" MinWidth="120" Text="{Binding TheText, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
    </StackPanel>
</UserControl>

Das Property "TheColor" ist im ViewModel meines UserControls hinterlegt und hat folgenden Code:

C#-Code:
public Color TheColor
        {
            get { return _color; }
            set
            {
                _color = Color.Red;
            }
        }

Bislang wird der Code jedoch gar nicht aufgerufen, was mich gleich zu den wichtigsten Fragen bringt.

1. Zuerst hatte ich für den TextBlock

XML-Code:
<TextBlock Text="{Binding SelectedItem}" ...</TextBlock>

was aber nur zur folge hatte, dass das selektierte Item so oft angezeigt wurde, wie Elemente in der Collection waren. Mehr oder minder durch Zufall habe ich herausgefunden, das einfach {Binding} zum gewünschten Ergebnis führt. Ich verstehe das nicht - gibt es dazu eine einfache, anschauliche Erklärung?

2. Zu Testzwecken möchte ich die Textfarbe über ein Property (TheColor) setzen; später brauche ich jedoch ein DataTemplate (?), bzw. DataTriggers, weil sich die Farbgebung für den Text nach einem enum im Property richten soll (das Property TheColor wäre dann nicht vom Typ "Color", sondern ein enum). Wie müsste ich den Code dafür anlegen?

Gruß
Vorph
25.01.2020 18:04 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.384
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von GeneVorph:
weil sich die Farbgebung für den Text nach einem enum im Property richten soll

Verwende dafür einfach einen Trigger in der View.

Was willst du mit diesem Code erreichen:

C#-Code:
public Color TheColor
        {
            get { return _color; }
            set
            {
                _color = Color.Red;
            }
        }

Soll es evtl. so aussehen:

C#-Code:
public Color TheColor { get { return Color.Red; } }

Und wozu brauchst du das UserControl eigentlich? Das braucht man wirklich nur, um Steuerelemente zu erstellen, die man in anderen Projekten wiederverwenden möchte, unabhängig von irgendwelchen ViewModels. Ansonsten reicht ein Template völlig aus.
25.01.2020 19:36 Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 118
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von MrSparkle:
Verwende dafür einfach einen Trigger in der View.

Also einen DataTrigger? Und den binde ich dann einfach zu meinem Property? (In meinem Fall würde das Property so aussehen:

C#-Code:
private PathItemState _itemState;

public PathItemState ItemState
{
get {return _itemState;}
set
{
_itemState = value;
OnPropertyChanged(ref _itemState, value);
}

)

PathItemState ist ein enum; sieht folgendermaßen aus:

C#-Code:
public enum PathItemState
{
chapterEmpty = 0,
chapterCompleted = 1,

}

Also muss mein Setter im DataTrigger auf dieses Property zeigen, und für Value wähle ich dann den jeweiligen "Zustand" aus, bei dem der Trigger anspringen und die Farbe in der TextBox des UserControls verändern soll.

Zitat:
Was willst du mit diesem Code erreichen:
...
Soll es evtl. so aussehen:

C#-Code:
public Color TheColor { get { return Color.Red; } }

verwundert ja, so hätte es aussehen sollen. Offenbar ist der Kaffee nicht mehr das, was er mal war....

Zitat:
Und wozu brauchst du das UserControl eigentlich? Das braucht man wirklich nur, um Steuerelemente zu erstellen, die man in anderen Projekten wiederverwenden möchte, unabhängig von irgendwelchen ViewModels. Ansonsten reicht ein Template völlig aus.

Ich bin mir nicht 100% sicher, ob ich es mit einem Template auch so hinbekomme: ich möchte Kapitel in einem Buch kommentieren können; die Kommentare werden auf dem MainWindow dynamisch erstellt (Mist - jetzt wo ich das tippe, denke ich, "das ist womöglich genau DAS, wofür man sonst Templates verwendet..."). "Brauchen" ist vielleicht zuviel gesagt: ich bin lediglich Hobby-Coder und hatte neulich einen Blog über UserControls durchwühlt - hier hat es sich für mich einfach angeboten ein bisschen zu üben und zu experimentieren...

Noch einen Hinweis über die SAche mit dem Text="{Binding}" im Gegensatz zu Text="{Binding SelectedItem}"? Ich kann immernoch nicht ganz verorten, was ein {Binding} ohne Target-Property eigentlich bedeutet - woher weß Text (bzw. Binding) an welches Property er sich in diesem Fall binden soll?

Gruß
Vorph
25.01.2020 21:11 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.384
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat von GeneVorph:
{Binding} ohne Target-Property

Dann wird direkt auf den DataContext gebunden.

Zitat von GeneVorph:
Also einen DataTrigger? Und den binde ich dann einfach zu meinem Property?

So in etwa:

XML-Code:
<DataTrigger Binding="{Binding Path=State}" Value="{x:Static my:PathItemState.chapterEmpty }">

Zu den UserControls: In Windows Forms hat es immer Sinn ergeben, bestimmte Teile der Anwendung in eigene Controls zu kapseln. Aber in WPF gibt es Templates, die viel flexibler sind, und in den allermeisten Fällen ausreichen.
25.01.2020 22:27 Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 118
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Ah, da schau' an - kaum macht man's richtig, schon funktioniert's!

XML-Code:
<ComboBox>
<ComboBox.Style>
                <Style TargetType="ComboBox">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding CurrentChapterItem.ChapterStatus}" Value="registeredChapter">
                            <Setter Property="Foreground" Value="Red"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ComboBox.Style>
        </ComboBox>

Sehr schön Zunge raus

Was mich an XAML generell frustet ist, dass - kaum glaubt man, die "Regeln" verstanden zu haben - sich gerade gelerntes selten direkt auf "next-level"-Niveau anwenden lässt. Und die Sache hier ist ein schönes Beispiel.

Ich habe in der ComboBox jetzt einen TextBlock und ein Rectangle. Sieht dann so aus:

XML-Code:
<ComboBox x:Name="combo" Margin="10" MinWidth="80" VerticalAlignment="Center"
                    ItemsSource="{Binding Source={StaticResource ItemListSortedView}}"
                    SelectedItem="{Binding CurrentChapterItem}"
>
            ...

            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Rectangle x:Name="rect" Width="10" Height="10" Margin="0,0,10,0"/>
                        <TextBlock Text="{Binding ChapterID}"/>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
            <ComboBox.Style>
                <Style TargetType="ComboBox">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding CurrentChapterItem.ChapterStatus}" Value="registeredChapter">
<!-- spätestens hier beschwert sich der Compiler --> rect ist als Name nicht bekannt -->
                            <Setter TargetName="rect" Property="Foreground" Value="Red"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ComboBox.Style>
        </ComboBox>

Meine Idee war, statt dem Text das Rectangle farblich hervorzuheben. Leider funktioniert es so scheinbar nicht. Ich habe es außerdem mit einem Style in den UserControl.Ressources versucht - das hat aber genauso wenig funktioniert. Ich verstehe nicht, warum's mit Text funktioniert, mit dem Rectangle aber nicht enttäuscht

Pfft - halb drei; viel zu spät, besser ab ins Bett, das wird heut nix mehr Daumen runter
26.01.2020 02:31 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 118
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Womöglich habe ich die Antworten auf meinen letzten Post schon gefunden - wiedermal ist es aber so, das die für mich wesentlichen Fragen offen bleiben:

Einmal von Microsoft selbst ( https://docs.microsoft.com/de-de/dotnet/...etframework-4.8 ): Dort heißt es unter Hinweise:

Zitat:
Beispielsweise sind die generierten Container für ListBoxListBoxItem-Steuerelementen. bei ComboBoxhandelt es sich um ComboBoxItem-Steuerelemente. Verwenden Sie die ItemsPanel-Eigenschaft, um das Layout der Elemente zu beeinflussen.

Also, wenn ich das richtig interpretiere, kann ich das Rectangle irgendwie unter der ItemsPanel-Eigenschaft der ComboBox referenzieren oder einbinden und dann einen Style zuweisen. (Wobei ich das jetzt eher so lese, dass es hier um das generelle Erscheinungsbild geht, nicht um ein spezifisches, je nach UseCase?)

Und auch dieser Blog () lässt mich eher erahnen wie eine Lösung aussehen könnte, denn konkret behilflich zu sein. Interessanter Weise wird dasselbe Beispiel aufgenommen, wie von Microsoft (ohne Verweis auf die Quelle - na, wenn das mal kein Ärger gibt ;-) ):  https://www.lernmoment.de/csharp-program...kte-in-wpf-dar/

Insgesamt eigentlich verständlich erklärt (und hier wird auch klar, dass ich das UserControl wirklich nicht brauche), aber an den entscheidenden Stellen hätte ich mich über ein "wie" gefreut. So heißt es etwa:

Zitat:
Neben der ItemTemplate Eigenschaft haben Controls für Auflistungen die Eigenschaft ItemTemplateSelector. Dieser kannst du einen eigenen DataTemplateSelector zuweisen. Nun kannst du nicht nur ein DataTemplate verwenden, sondern gleich mehrere. Dabei entscheidet der DataTemplateSelector basierend auf Werten in den anzuzeigenden Objekten, welches DataTemplate benutzt werden soll.

Damit sollen sich nun bestimmte Werte hervorheben lassen. Es folgt auch ein Code-Beispiel, leider ohne Angabe wo es zu verwenden ist (Code behind? ViewModel? Anderweitig?).

Vielleicht verrenne ich mich ja aber auch gerade - falls dem so ist, wäre ich um jeden Hinweis in die richtige Richtung dennoch dankbar. Vielleicht is mein vorletzter post ja gar nicht so falsch und benötigt lediglich kleinere Korrekturen?

Vielen Dank, schönen Sonntag
Vorph
26.01.2020 10:01 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Papst Papst ist männlich
myCSharp.de-Mitglied

Dabei seit: 28.09.2014
Beiträge: 268
Entwicklungsumgebung: VS2017
Herkunft: Kassel


Papst ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Bezüglich des Codebeispiels - meinst du den DataTemplateSelector?

Das ist eine eigene Klasse, die dann in den Ressourcen deiner View referenziert (und ggf. instanziiert) werden muss.
26.01.2020 11:21 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.384
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Was genau ist deine Frage?
26.01.2020 15:41 Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 118
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Zitat:
Was genau ist deine Frage?

Sorry, das ging im Gedränge wohl unter:
Ich hatte es mit deiner Hilfe geschafft den Text im TextBlock der ComboBox je nach "Zustand" eines enums farblich zu verändern. Das Gleiche wollte ich jetzt auf ein Rectangle anwenden, bin aber gestern abend/heute früh stundenlang gescheitert.

Obwohl ich mir sicher war, dass ich es an diesem Punkt verstanden hatte - ich konnte mir leider nicht erklären, wo mein Fehler lag. Fälschlicherweise habe ich mir zu früh Asche auf's Haupt gestreut, weil mein Fazit das war, dass ich es total falsch versuche.

Mittlerweile habe ich die Lösung gefunden --> mein Code musste nur um folgende Zeile ergänzt werden:

XML-Code:
<DataTrigger Binding = "{Binding ElementName=combo, path=SelectedItem.ChapterStatus}" Value="registeredChapter" />

Hingegen hatte ich zuvor:

XML-Code:
<DataTrigger Binding="{Binding CurrentChapterItem.ChapterStatus}" Value="registeredChapter">

CurrentChapterItem ist ein Property des ViewModels. Meine Combobox binded bereits per SelectedItem an dieses Property, so dass ich der irrigen (?) Annahme war, ich könnte mit dem Rectangle genauso verfahren. Klappt dann aber nicht. Stattdessen musste ich ausdrücklich die Combobox referenzieren (Binding ElementName=comb0).

Gut, ich hab's ja jetzt hinbekommen. Dennoch, konkrete Frage: worin liegt der Unterschied zwischen
"Binding CurrentChapterItem.ChapterStatus" und "Binding ElementName=combo, Path=SelectedItem"?

Ich meine, ich verstehe schon, dass sich ElementName auf die ComboBox direkt bezieht, was ich ich nicht verstehe ist die Tatsache, dass das SelectedItem-Property der ComboBox auf das CurrentChapterItem des ViewModels bindet. Wenn ich aber das Rectangle direkt an genau dasselbe Property binde, reagiert es nicht. Hat das damit zu tun, dass sich das Rectangle im DataTemplate der ComboBox befindet?.
Gruß
Vorph
26.01.2020 15:59 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.384
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Das Binding mit ElementName bezieht sich auf ein Steuerelement in der View, an dessen Eigenschaften du binden kannst. Ansonsten bezieht sich das Binding auf den DataContext des Elements. In deinem Fall wäre ein einfacher Trigger (kein DataTrigger) die beste Lösung. Wobei mir trotz deines umfangreichen Textes nicht klar ist, was du eigentlich genau erreichen willst.

Wenn ein Binding nicht korrekt funktioniert, kannst du eine Fehlermeldung im Ausgabefenster finden, oder es selbst überprüfen, siehe Abschnitt Debugging in  [Artikel] MVVM und DataBinding.
26.01.2020 20:15 Beiträge des Benutzers | zu Buddylist hinzufügen
GeneVorph GeneVorph ist männlich
myCSharp.de-Mitglied

Dabei seit: 09.02.2015
Beiträge: 118
Entwicklungsumgebung: Visual Studio 2013

Themenstarter Thema begonnen von GeneVorph

GeneVorph ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Danke für den Link, Mr.Sparkle - das Kapitel mit über's Debugging hat mir schon mal gleich geholfen fröhlich

Zitat:
Wobei mir trotz deines umfangreichen Textes nicht klar ist, was du eigentlich genau erreichen willst.

War zu viel Info, wa? großes Grinsen
Mein UserControl verfügt über ein Rectangle und eine TextBox. Das Rectangle besitzt ein Binding auf ein Property des ViewModels, das meine View darüber unterrichtet, ob ein Kapite in einem Buchl schon kommentiert wurde (registeredChapter) oder nicht (unregisteredChapter). Einmal Farbton grün - einmal rot.

Jetzt, wo ich weiß wie es geht - eigentlich total simpel. Meine Lösung s. oben.

Zitat:
as Binding mit ElementName bezieht sich auf ein Steuerelement in der View, an dessen Eigenschaften du binden kannst. Ansonsten bezieht sich das Binding auf den DataContext des Elements.

Den Teil hatte ich schon verstanden. Was ich nicht verstehe: der DataContext des Elements 'combo' ist das PathControlViewModel. Daran ist es gebunden.
In meinem ersten Versuch das Rectangle einzufärben hatte ich einfach

XML-Code:
<DataTrigger Binding="{Binding CurrentChapterItem.ChapterStatus}" Value="registeredChapter">

im Code. Ohne ElementName. Dabei ist CurrentChapterItem ja genau jenes Property, das sich im DataContext von 'combo' befindet.
Meine Frage war also mehr oder minder: Müssten nicht beide Bindings (s. meinen vorherigen Post) zum selben Ergebnis führen?
Ich weiß, ich hab' da einen Denkfehler, komme aber nicht drauf...
26.01.2020 22:36 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
MrSparkle MrSparkle ist männlich
myCSharp.de-Team

avatar-2159.gif


Dabei seit: 16.05.2006
Beiträge: 5.384
Herkunft: Leipzig


MrSparkle ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top



Zitat von GeneVorph:
War zu viel Info, wa? :D

Zu viel Text, zu wenig Information. Du mußt nicht jeden Gedankengang hier dokumentieren. Poste den relevanten Code und eine konkrete Frage, dann machst du es deinen Helfern leichter.
Siehe  [Hinweis] Wie poste ich richtig?, Punkt 5

Wenn du eine neue Frage hast, erstelle ein neues Thema und poste den relevanten Code und eine konkrete Frage. So verliert man nicht den Überblick.
Siehe  [Hinweis] Wie poste ich richtig?, Punkt 1.2


Zitat von GeneVorph:
Dabei ist CurrentChapterItem ja genau jenes Property, das sich im DataContext von 'combo' befindet.

Das läßt sich von hier aus nicht sagen, weil nicht klar ist, wie dein Code jetzt aussieht. Aber du könntest es z.B. mit einem DebugConverter mit wenig Aufwand selbst überprüfen.
28.01.2020 09:56 Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 4 Monate.
Der letzte Beitrag ist älter als 4 Monate.
Antwort erstellen


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 07.06.2020 11:27