Wie kann man eine Gruppe von Umschalttasten dazu bringen, sich wie Optionsfelder in WPF zu verhalten?

122

Ich habe eine Gruppe von Schaltflächen, die sich wie Umschalttasten verhalten sollen, aber auch als Optionsfelder, bei denen jeweils nur eine Taste ausgewählt / gedrückt werden kann. Es muss auch einen Zustand haben, in dem keine der Tasten ausgewählt / gedrückt wird.

Das Verhalten ähnelt einer Photoshop-Symbolleiste, in der jederzeit null oder eines der Werkzeuge ausgewählt wird!

Irgendeine Idee, wie dies in WPF implementiert werden kann?

Code-Zoop
quelle

Antworten:

38

Am einfachsten ist es, eine ListBox so zu gestalten, dass ToggleButtons für ihre ItemTemplate verwendet werden

<Style TargetType="{x:Type ListBox}">
    <Setter Property="ListBox.ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <ToggleButton Content="{Binding}" 
                              IsChecked="{Binding IsSelected, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"
                />
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

Anschließend können Sie die SelectionMode-Eigenschaft der ListBox verwenden, um SingleSelect vs MultiSelect zu verarbeiten.

Bryan Anderson
quelle
ich danke Ihnen für das Teilen! Ich habe mich gefragt, ob dies eine gute Praxis ist ... aber es scheint in
Ordnung
1
@ LeeLouviere: Möchten Sie näher erläutern, warum nicht? Ist das nicht ein Paradebeispiel für die Verwendung der Artikelvorlage?
ODER Mapper
4
Es ist ein schlechtes Beispiel, weil Sie Anzeige und Verhalten verwechseln. Sie ändern die Anzeige über die Datenvorlage, haben aber immer noch das Verhalten einer Listbox und nicht das Verhalten einer Reihe von Optionsfeldern. Tastaturinteraktion ist komisch. Eine bessere Lösung wäre ein ItemsControl mit RadioButtons, das als ToggleButtons bezeichnet wird (siehe die andere Antwort mit der höchsten Bewertung).
Zarat
Warum das Rad neu erfinden?
Wobbles
300

Dies ist meiner Meinung nach der einfachste Weg.

<RadioButton Style="{StaticResource {x:Type ToggleButton}}" />

Genießen! - Stichsäge

Uday Kiran Thummalapalli
quelle
29
Diese Antwort sollte bei weitem ausgewählt werden. Bietet Ihnen alle Vorteile eines Radiobuttons ohne die Nachteile einer Bindung an einen Controller. Ich habe zuerst versucht, einen unsichtbaren Radiobutton-Satz zu trennen, aber das hatte unnötigen Overhead und endete mit einem Fehler, bei dem alle angeklickten Schaltflächen hervorgehoben, aber nicht unbedingt überprüft wurden.
Lee Louviere
16
Wenn Sie dies auf alle RadioButtons in einem Element (z. B. a Grid) anwenden müssen , verwenden Sie <Grid.Resources> <Style TargetType="RadioButton" BasedOn="{StaticResource {x:Type ToggleButton}}" /> </Grid.Resources>.
Roman Starkov
16
Ein Nachteil dieser Methode ist, dass Sie ein Optionsfeld nicht durch Klicken auf ein Häkchen deaktivieren können.
Julien
2
Kann ein benutzerdefinierter Stil für einen solchen Umschaltknopf verwendet werden?
Wondra
2
@wondra Sie können einem FrameworkElement nur einen einzigen Stil zuweisen. Sie können jedoch die Romkyns-Lösung anpassen und vom ToggleButton-Stil erben:<Style BasedOn="{StaticResource {x:Type ToggleButton}}" x:Key="Blubb" TargetType="RadioButton"><Setter Property="Background" Value="Yellow" /></Style>
Suigi
32
<RadioButton Content="Point" >
    <RadioButton.Template>
        <ControlTemplate>
            <ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                          Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"/>
        </ControlTemplate>
    </RadioButton.Template>
</RadioButton>

es funktioniert bei mir, viel Spaß!

RoKK
quelle
Ich weiß, das ist nicht die Frage. Aber was tun, wenn sich die Schaltfläche wie die Radiobuttons verhalten soll, bei denen immer eine ausgewählt werden muss?
Karsten
Zu meiner Antwort meine eigene Frage: Lesen Sie die Antwort von Uday Kiran :-)
Karsten
Schön, dass dies genauso funktioniert wie die Umschalttaste. Klicken Sie zum Aktivieren und klicken Sie auf dieselbe Schaltfläche, um das Kontrollkästchen zu deaktivieren. und wenn ich alle RadioButtons in eine Gruppe eingeordnet habe, verhält es sich wie Optionsfelder. Danke RoKK !!!
Mili
2
Es ist eine gute Lösung. Wenn wir jedoch eine Veranstaltung haben. es wird zweimal aufgerufen.
Khiem-Kim Ho Xuan
Wenn ein anderer Inhalt als eine einfache Zeichenfolge hinzugefügt wird, erhalte ich ein "Element ist bereits das Kind eines anderen Elements". Error. Gibt es einen Weg darum herum?
Tobias Hoefer
5

Sie können jederzeit ein generisches Ereignis beim Klicken auf den ToggleButton verwenden, das alle ToggleButton.IsChecked in einer Gruppensteuerung (Grid, WrapPanel, ...) mithilfe des VisualTreeHelper auf false setzt. Überprüfen Sie dann den Absender erneut. Oder so ähnlich.

private void ToggleButton_Click(object sender, RoutedEventArgs e)
    {
        int childAmount = VisualTreeHelper.GetChildrenCount((sender as ToggleButton).Parent);

        ToggleButton tb;
        for (int i = 0; i < childAmount; i++)
        {
            tb = null;
            tb = VisualTreeHelper.GetChild((sender as ToggleButton).Parent, i) as ToggleButton;

            if (tb != null)
                tb.IsChecked = false;
        }

        (sender as ToggleButton).IsChecked = true;
    }
Sam
quelle
4

Sie können ein Raster mit Radiobuttons einfügen und eine Schaltflächenvorlage für Raduiobuttons erstellen. als nur programmgesteuert entfernen prüfen, ob die Tasten nicht umgeschaltet werden sollen

Arsen Mkrtchyan
quelle
Aber gibt es durch die Verwendung von Optionsfeldern eine Möglichkeit, die Auswahl aller Schaltflächen aufzuheben? Einmal ausgewählt, sehe ich keine einfache Möglichkeit, die Auswahl aufzuheben!
Code-Zoop
RadioButton hat eine IsChecked-Eigenschaft, die Sie bei Bedarf im Code auf false setzen können
Arsen Mkrtchyan
2

Sie können es auch versuchen System.Windows.Controls.Primitives.ToggleButton

 <ToggleButton Name="btnTest" VerticalAlignment="Top">Test</ToggleButton>

Schreiben Sie dann Code gegen die IsCheckedEigenschaft, um den Radiobutton-Effekt nachzuahmen

 private void btnTest_Checked(object sender, RoutedEventArgs e)
 {
     btn2.IsChecked = false;
     btn3.IsChecked = false;
 }
Jojo Sardez
quelle
Dies ist nicht sehr allgemein und wiederverwendbar ... zum Beispiel ist es in ListBoxItems nicht verwendbar .
Aneves
0

Ich habe dies für RibbonToggleButtons gemacht, aber vielleicht ist es das gleiche für normale ToggleButtons.

Ich habe das IsChecked für jede Schaltfläche mit EnumToBooleanConverter von hier aus an einen Aufzählungswert "mode" gebunden. Wie binde ich RadioButtons an eine Aufzählung? (Geben Sie den Aufzählungswert für diese Schaltfläche mit dem ConverterParameter an. Sie sollten einen Aufzählungswert für jede Schaltfläche haben.)

Um zu verhindern, dass eine bereits aktivierte Schaltfläche deaktiviert wird, fügen Sie diese in Ihren Code für das Click-Ereignis für jede der RibbonToggleButtons ein:

    private void PreventUncheckRibbonToggleButtonOnClick ( object sender, RoutedEventArgs e ) {

        // Prevent unchecking a checked toggle button - so that one always remains checked
        // Cancel the click if you hit an already-checked button

        var button = (RibbonToggleButton)sender;
        if( button.IsChecked != null ) { // Not sure why checked can be null but that's fine, ignore it
            bool notChecked = ( ! (bool)button.IsChecked );
            if( notChecked ){ // I guess this means the click would uncheck it
                button.IsChecked = true; 
            }
        }
    }
Simon F.
quelle
0

Um Leuten wie Julian und mir zu helfen (vor zwei Minuten ...). Sie können daraus ableiten RadioButton.

class RadioToggleButton : RadioButton
{
    protected override void OnToggle()
    {
        if (IsChecked == true) IsChecked = IsThreeState ? (bool?)null : (bool?)false;
        else IsChecked = IsChecked.HasValue;
    }
}

Dann können Sie es verwenden, wie Uday Kiran vorgeschlagen hat ...

<Window x:Class="Sample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Sample"
    Title="MainWindow" Height="600" Width="600">
    <StackPanel>
        <local:RadioToggleButton Content="Button" Style="{StaticResource {x:Type ToggleButton}}" />
    </StackPanel>
</Window>

Diese Methode erlaubt es, jeweils nur eine ToggleButtonzu sein Checked, und sie erlaubt auch das Aufheben der Überprüfung.

Prinz Owen
quelle
0

Ich nahm ein paar Antworten und fügte zusätzlichen Code hinzu. Jetzt können Sie verschiedene Gruppen von Umschalttasten haben, die sich wie eine Umschalttaste verhalten:

<UserControl.Resources>
    <Style x:Key="GroupToggleStyle" TargetType="ToggleButton">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding GroupName, RelativeSource={RelativeSource Self}}" Value="Group1"/>
                    <Condition Binding="{Binding BooleanProperty}" Value="true"/>
                </MultiDataTrigger.Conditions>
                <MultiDataTrigger.Setters>
                    <Setter Property="IsChecked" Value="true"/>
                </MultiDataTrigger.Setters>
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>
</UserControl.Resources>

Und die verschiedenen Gruppen von Optionsfeldern, die wie Umschalttasten aussehen:

<Radio Button GroupName="Group1" Style="{StaticResource {x:Type ToggleButton}}">
<Radio Button GroupName="Group1" Style="{StaticResource {x:Type ToggleButton}}">
<Radio Button GroupName="Group2" Style="{StaticResource {x:Type ToggleButton}}">
<Radio Button GroupName="Group3" Style="{StaticResource {x:Type ToggleButton}}">
Erdbeerstrauch
quelle