Laden...

WPF: DataTrigger bei Checkboxen reagiert nicht

Erstellt von sth_Weird vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.405 Views
S
sth_Weird Themenstarter:in
469 Beiträge seit 2007
vor 8 Jahren
WPF: DataTrigger bei Checkboxen reagiert nicht

Hallo,
Ich habe ein Control mit n+1 Checkboxen. Eine Checkbox hat die Funktion "Keine Auswahl", die anderen n sind die "Auswahlmöglichkeiten". Die n Checkboxen für die "Auswahlmöglichkeiten" sind gebunden (etwas Background-Info: gebunden an Flags diverser Flag-Enums, dieser Part funktioniert bereits einwandfrei). Die Checkbox "Keine Auswahl" ist nicht gebunden. Ich möchte folgendes haben: Wenn eine oder mehrere IsChecked der n Auswahlmöglichkeit-Checkboxen auf true sind, dann soll sich die IsChecked der "Keine Auswahl" Checkbox automatisch auf false setzen, aber wenn keine der anderen Checkboxen IsChecked=true sind, dann soll sie sich automatisch auf true setzen.

das probiere ich:

<CheckBox Grid.Column="0" Grid.Row="1" Name="cbNothingSelected" IsChecked="False" Content="Keine Auswahl" Margin="0,0,5,0" VerticalAlignment="Center">
                            <CheckBox.Style>
                                <Style TargetType="CheckBox">
                                    <Style.Triggers>
                                        <MultiDataTrigger> 
                                            <MultiDataTrigger.Conditions>
                                                <Condition Binding="{Binding ElementName=cbAuswahl1, Path=IsChecked}" Value="False" />
                                                <Condition Binding="{Binding ElementName=cbAuswahl2, Path=IsChecked}" Value="False" />
                                                <Condition Binding="{Binding ElementName=cbAuswahl3, Path=IsChecked}" Value="False" />
                                            </MultiDataTrigger.Conditions>
                                            <Setter Property="IsChecked" Value="True"></Setter>
                                        </MultiDataTrigger>
                                        <DataTrigger Binding="{Binding ElementName=cbAuswahl1, Path=IsChecked}" Value="True">
                                            <Setter Property="IsChecked" Value="False"></Setter>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding ElementName=cbAuswahl2, Path=IsChecked}" Value="True">
                                            <Setter Property="IsChecked" Value="False"></Setter>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding ElementName=cbAuswahl3, Path=IsChecked}" Value="True">
                                            <Setter Property="IsChecked" Value="False"></Setter>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </CheckBox.Style>
                        </CheckBox>
                        <CheckBox Grid.Column="0" Grid.Row="2" Name="cbAuswahl1"...

Also der MultiTrigger soll prüfen ob die Auswahl-Checkboxen alle IsChecked=false haben und falls ja das eigene IsChecked auf true setzen.
Unten sind drei DataTrigger, diese sollen das IsChecked der Checkbox auf false setzen, wenn eine der Checkboxen IsChecked=true haben. 3 DataTrigger da ich damit die OR Beziehung abbilden will, der Multitrigger verknüpft die Conditions ja mit AND.

Es passiert: nichts. Ich kann wild auf den Checkboxen rumklicken, die "Keine Auswahl" Checkbox wird nie automatisch gesetzt/rückgesetzt so wie ich es erwarten würde.
Es werden keine Warnungs oder Fehlermeldungen ausgegeben. Compiliert fehlerfrei, es fliegen keine Exceptions. Die Trigger scheinen einfach nur ignoriert zu werden.
Sieht hier jemand spontan das Problem? Habe bisher noch nicht viel mit Triggern gearbeitet, wenn dann war es nur sowas wie Schriftart fett wenn selektiert oder so (hat bisher immer funktioniert)...

gruß & danke
sth_Weird

++++++++++++++++++++~+
Fluchen ist die einzige Sprache, die jeder Programmierer perfekt beherrscht


Linux is for free...if your time is worth nothing
++++++++++++++++++++~+

2.207 Beiträge seit 2011
vor 8 Jahren

Nimm mal bei

<CheckBox Grid.Column="0" Grid.Row="1" Name="cbNothingSelected" IsChecked="False" Content="Keine Auswahl" Margin="0,0,5,0" VerticalAlignment="Center">

das

IsChecked="False" 

raus.

Meinst du vielleicht

IsEnabled="False"

?

Würde sich vielleicht eher eignen für deinen UseCase.

Gruss

Coffeebean

T
314 Beiträge seit 2013
vor 8 Jahren

Alternativ einfach ohne Trigger und eine Property die die entsprechende Information liefert anbieten.

1.378 Beiträge seit 2006
vor 8 Jahren

Nimm mal bei

das

IsChecked="False"   

raus.

Das wird es wohl sein. Ein Style-Setter kann keine manuell gesetzten Properties überschreiben. Wenn du aus irgendeinem Grund ein Property vom Start weg setzen willst, mach dies ebenfalls im Style per Setter.

Lg, XXX

S
sth_Weird Themenstarter:in
469 Beiträge seit 2007
vor 8 Jahren

Ok das war's, danke...Das IsChecked = false sollte der Defaultwert sein.

Ich habe jetzt auch noch einen anderen Fall, da ist IsChecked gebunden (und hat Converter und ConverterParameter).
Aus eurer Begründung der Antworten leite ich dann aber ab, dass ich den Wert von IsChecked hier auch nicht so wie von mir angedacht über einen Trigger ändern kann, oder??? Wie müsste ich dann vorgehen, wenn ich das IsChecked setzen will, aber das Binding beibehalten (der Trigger soll quasi das gleiche auslösen, als hätte ich manuell auf die CheckBox geklickt, d.h. der Wert der gebundenen Property soll sich somit auch aktualisieren)? Wie gesagt das Binding von IsChecked bindet ein Property des ViewModels, hat Converter und ConverterParameter.
Direkt im Setter das gebundene Property setzen geht ja auch nicht:

<Setter Property="{Binding Path=MyFlags, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource FlagsToBoolConverter}, ConverterParameter=FlagXYZ}" Value="False"></Setter>

wirft zur Laufzeit ne Exception.
Mir fallen als Lösung nur ein, jedes einzelne Flag als DependencyProperty meines CustomControls zu implementieren und im setzen/rücksetzen die Sonderaktionen durchzuführen, die ich eigentlich mit den DataTriggern abhändeln wollte. Damit ist allerdings die Idee futsch, dass mein CustomControl nur die Gesamtmenge der Flags als DependencyProperty anbietet und nicht jedes einzelne.
Oder ich machs mit Events, ist aber sehr böse nach MVVM und auch nicht testbar...

Gruß & danke
sth_Weird

++++++++++++++++++++~+
Fluchen ist die einzige Sprache, die jeder Programmierer perfekt beherrscht


Linux is for free...if your time is worth nothing
++++++++++++++++++++~+

1.378 Beiträge seit 2006
vor 8 Jahren

Hallo sth_Weird,

als Property im Setter muss natürlich das Ziel-Property (IsChecked) angegeben werden und im Valuebereich kommt dann das Binding inkl. Converter rein:

<Setter Property="IsChecked" Value="{Binding Path=MyFlags, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource FlagsToBoolConverter}, ConverterParameter=FlagXYZ}"></Setter>

Lg, XXX

S
sth_Weird Themenstarter:in
469 Beiträge seit 2007
vor 8 Jahren

hallo,

ja, aber ich möchte ja das IsChecked auf true setzen (was dann den Wert des Properties im hinterlegten Binding aktualisieren soll)...
Also ganz einfaches Beispiel: ich habe 2 Checkboxen die gebunden sind an 2 boolsche Werte des ViewModels. Eine dritte ungebundene Checkbox soll, wenn IsChecked = true wird, diese beiden Checkboxen auch IsChecked = true setzen. So ne Art "alles anwählen".
Da die Checkboxen bzw. IsChecked aber gebunden ist scheint das nicht zu gehen. Nimmt man das IsChecked-Binding raus tut's, aber wie soll der Wert dann zurück ins ViewModel wandern, wenn er nicht gebunden ist?.

Als Gegenbeispiel der umgekehrte Fall, wenn beide gebundene Checkboxen IsChecked=true sind, sollte die "alles anwählen" Checkbox automatisch auch angewählt sein.
Das bekommt man über einen DataTrigger prima hin, denn die Ziel-Checkbox ist ja nicht gebunden und somit kann man deren IsChecked im Setter des DataTriggers überschreiben.

gruß
sth_Weird

++++++++++++++++++++~+
Fluchen ist die einzige Sprache, die jeder Programmierer perfekt beherrscht


Linux is for free...if your time is worth nothing
++++++++++++++++++++~+

M
184 Beiträge seit 2012
vor 8 Jahren

Und wenn du das komplett über das ViewModel abbildest?

CheckBox1 bindest du an Property1 (Boolean)
CheckBox2 bindest du an Property2 (Boolean)
CheckBox3 (Alles anwählen) bindest du ein ein weiteres Property (Boolean)

Im Getter des 3. Property prüfst du, ob Property1 und Property2 true sind, dann gibst du auch true zurück, ansonsten false.
Property1 und Property2 müssen dann natürlich über INotifyPropertyChanged mitteilen, dass sich Property3 ggf. geändert hat.

Und im Setter setzt du Property1 und Property2 auf true.

1.378 Beiträge seit 2006
vor 8 Jahren

Und wenn du das komplett über das ViewModel abbildest?

Ist sicherlich die schönste Lösung... Einfach die Checkboxen an ein Property binden und dort die Logik abbilden die du erreichen willst.

S
sth_Weird Themenstarter:in
469 Beiträge seit 2007
vor 8 Jahren

Nuja das ganze hat eigentlich in dem Sinne kein ViewModel, es ist ein CustomControl das ein DependencyProperty "MyFlags" hat. Ich verwende es in einem Formular, und binde dort das MyFlags DependencyProperty an das ViewModel des ganzen Formulars. Ich hätte die Logik nun ungern im ViewModel des Formulars untergebracht, da sie ja an jeder Verwendungsstelle des CustomControls gilt.
Als einzig andere Alternative fällt mir dann aber ein, in meinem CustomControl noch ein DependencyProperty einzufügen das ich an die ungebundene Checkbox hefte. Leider wäre dieses Property dann auch nach außen sichtbar an allen Verwendungsstellen und könnte gebunden werden. Das würde mir nicht so gut gefallen...Oder gibt es DependencyProperties, dich im im DataTemplate des CustomControls binden kann, aber nicht an der Verwendungsstelle?
Oder doch mit Events arbeiten??? Es ist ja ein abgeschlossenes CustomControl da dürfte das ja eigentlich MVVM-technisch nicht so tragisch sein...

gruß
sth_Weird

++++++++++++++++++++~+
Fluchen ist die einzige Sprache, die jeder Programmierer perfekt beherrscht


Linux is for free...if your time is worth nothing
++++++++++++++++++++~+

T
314 Beiträge seit 2013
vor 8 Jahren

Du kannst auch einfach die Properties im UC anbieten. Dann können sie auch nicht von außen gebunden, aber über das Control beliebig gesetzt werden.

Ansonsten kannst Du natürlich auch die Events nutzen. Manchmal sollte man einfach machen, was einem richtig erscheint und nicht auf biegen und brechen versuchen irgendein Pattern einzusetzen.