Jak sprawić, aby grupa przycisków przełączania działała jak przyciski radiowe w WPF?


122

Mam grupę przycisków, które powinny działać jak przyciski przełączania, ale także jako przyciski radiowe, w których można wybrać / nacisnąć tylko jeden przycisk w danym momencie. Musi również mieć stan, w którym żaden z przycisków nie jest zaznaczony / wciśnięty.

Zachowanie będzie podobne do paska narzędzi programu Photoshop, w którym w dowolnym momencie wybierane jest zero lub jedno z narzędzi!

Masz jakiś pomysł, jak można to zaimplementować w WPF?

Odpowiedzi:


38

Najłatwiejszym sposobem jest nadanie stylu ListBox używaniu ToggleButtons dla jego ItemTemplate

<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>

Następnie możesz użyć właściwości SelectionMode ListBox, aby obsłużyć SingleSelect vs MultiSelect.


Dziękuję za udostępnienie! zastanawiałem się, czy to dobra praktyka ... ale wydaje się, że jest w porządku ..
GorillaApe

1
@LeeLouviere: Czy zechciałbyś wyjaśnić, dlaczego nie? Czy to nie jest doskonały przykład użycia szablonu przedmiotu?
LUB Mapper

4
To zły przykład, ponieważ mylisz sposób wyświetlania i zachowanie. Zmieniasz sposób wyświetlania za pomocą tabliczki danych, ale nadal masz zachowanie pola listy, a nie zachowanie zestawu przycisków radiowych / przełączników. Interakcja z klawiaturą jest dziwna. Lepszym rozwiązaniem byłby ItemsControl z RadioButtons, stylizowany na ToggleButtons (zobacz inną odpowiedź o najwyższym głosowaniu).
Zarat

Po co odkrywać koło na nowo?
Wobbles

300

Moim zdaniem to najłatwiejszy sposób.

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

Cieszyć się! - Pricksaw


29
Ta odpowiedź powinna być zdecydowanie wybrana. Daje wszystkie zalety przycisku radiowego bez wad wiązania z niektórymi kontrolerami. Najpierw próbowałem powiązać, aby oddzielić niewidoczny zestaw przycisków radiowych, ale to miało niepotrzebne obciążenie i zakończyło się błędem, w którym wszystkie kliknięte przyciski wyglądały na podświetlone, ale niekoniecznie sprawdzone.
Lee Louviere

16
Lub, jeśli chcesz zastosować to do wszystkich RadioButtonów wewnątrz elementu (np. A Grid), użyj <Grid.Resources> <Style TargetType="RadioButton" BasedOn="{StaticResource {x:Type ToggleButton}}" /> </Grid.Resources>.
Roman Starkov

16
Wadą tej metody jest to, że nie można odznaczyć przycisku opcji, klikając zaznaczony.
Julien

2
Czy można jakoś użyć niestandardowego stylu na takim przełączniku?
wondra

2
@wondra Możesz przypisać tylko jeden styl do FrameworkElement. Możesz jednak dostosować rozwiązanie romkyns i dziedziczyć po stylu ToggleButton:<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>

na mnie działa, ciesz się!


Wiem, że to nie jest pytanie. Ale co zrobić, jeśli przycisk ma zachowywać się jak przyciski radiowe, w przypadku których zawsze należy go wybrać?
Karsten

Na moje własne pytanie: przeczytaj odpowiedź Udaya Kirana :-)
Karsten

Świetnie, to działa tak samo jak przycisk przełączania. Kliknij, aby zaznaczyć i kliknij ten sam przycisk, aby odznaczyć. a gdy umieściłem wszystkie RadioButtons w tej samej grupie, działają one jak przyciski radiowe. Dziękuję RoKK !!!
mili

2
To dobre rozwiązanie. Jednak kiedy mamy wydarzenie. zostanie wywołany dwukrotnie.
Khiem-Kim Ho Xuan

Jeśli dodasz zawartość inną niż prosty ciąg, otrzymam „Element jest już dzieckiem innego elementu”. błąd. Czy jest na to sposób?
Tobias Hoefer,

5

zawsze możesz użyć zdarzenia ogólnego w Click of the ToggleButton, które ustawia wszystkie ToggleButton.IsChecked w groupcontrol (Grid, WrapPanel, ...) na false za pomocą VisualTreeHelper; następnie ponownie sprawdź nadawcę. Albo coś w tym rodzaju.

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;
    }

4

możesz umieścić siatkę z przyciskami radiowymi w niej i utworzyć przycisk podobny do szablonu dla raduiobuttons. niż programowe usuwanie, sprawdź, czy nie chcesz przełączać przycisków


Ale czy za pomocą przycisków opcji można odznaczyć wszystkie przyciski? Po wybraniu nie widzę łatwego sposobu na odznaczenie tego!
code-zoop

RadioButton ma właściwość IsChecked, możesz ustawić ją na false w kodzie, kiedy potrzebujesz
Arsen Mkrtchyan

2

Możesz też spróbować System.Windows.Controls.Primitives.ToggleButton

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

Następnie napisz kod dotyczący IsCheckedwłaściwości, aby naśladować efekt radiobutton

 private void btnTest_Checked(object sender, RoutedEventArgs e)
 {
     btn2.IsChecked = false;
     btn3.IsChecked = false;
 }

Nie jest to zbyt ogólne i wielokrotnego użytku ... na przykład nie można go używać w ListBoxItems.
ANeves

0

Zrobiłem to dla RibbonToggleButtons, ale może to samo dotyczy zwykłych ToggleButtons.

Powiązałem IsChecked dla każdego przycisku z wartością wyliczenia „mode” przy użyciu EnumToBooleanConverter stąd Jak powiązać RadioButtons z wyliczeniem? (Określ wartość wyliczenia dla tego przycisku przy użyciu parametru ConverterParameter. Dla każdego przycisku należy podać jedną wartość wyliczenia)

Następnie, aby zapobiec odznaczeniu przycisku, który jest już zaznaczony, umieść to w kodzie za zdarzeniem Click dla każdego z RibbonToggleButtons:

    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; 
            }
        }
    }

0

Aby pomóc ludziom takim jak Julian i ja (dwie minuty temu ...). Możesz z tego RadioButtonwywnioskować.

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

Następnie możesz go używać tak, jak sugerował Uday Kiran ...

<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>

Metoda ta pozwala tylko jeden ToggleButtonbędzie Checkedw danym momencie, a także pozwala odznaczenie.


0

Wziąłem kilka odpowiedzi i dodałem dodatkowy kod. Teraz możesz mieć różne grupy przycisków przełączania, które działają jak jeden przycisk przełączania:

<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>

Oraz różne grupy przycisków opcji, które wyglądają jak przyciski przełączania:

<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}}">
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.