Подтвердить что ты не робот

ToggleButton меняет изображение в зависимости от состояния

Я хотел бы использовать ToggleButton следующим образом: Существует 5 различных изображений, и каждый из них должен отображаться в зависимости от текущего состояния:

  • отключена Кнопка
  • включена, снята флажка Кнопка
  • включена, не отмечена, указана курсором мыши
  • включена, отмечена
  • кнопка включена, отмечена, указана курсором мыши

Я нашел простой пример с двумя изображениями здесь, но как изменить изображение в зависимости от свойства "checked"?

Второй вопрос: как я могу избежать создания разных стилей для каждой кнопки в моем приложении? Я использую около 20 различных кнопок, и каждый из них имеет разные значки.

Пока я использую только один значок, ниже моего кода. Возможно ли иметь общий код (стиль и шаблон) и определить источник изображений в разделе, где я хочу создать кнопку (как в разделе 3 моего кода)?

<ControlTemplate x:Key="ToggleButtonTemplate" TargetType="{x:Type ToggleButton}">
    <Grid>
        <Border x:Name="ContentBorder" CornerRadius="4" BorderBrush="Transparent" BorderThickness="1" Background="{DynamicResource ButtonOff}">
            <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" RecognizesAccessKey="True"/>
        </Border>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="IsPressed" Value="true">
            <Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource ButtonOn}"/>
        </Trigger>
        <Trigger Property="IsChecked" Value="true">
            <Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource ButtonOn}"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter TargetName="ContentBorder" Property="Background" Value="{DynamicResource ButtonDisabled}"/>
            <Setter Property="Foreground" Value="{DynamicResource BorderDisabled}"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

<Style x:Key="ToggleButtonStyle" TargetType="{x:Type ToggleButton}">
    <Setter Property="Width" Value="64" />
    <Setter Property="Height" Value="64" />
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template" Value="{DynamicResource ToggleButtonTemplate}" />
</Style>

<ToggleButton IsChecked="{Binding Path=IsLectorModeEnabled}" Command="{Binding CmdLector}" Style="{DynamicResource ToggleButtonStyle}">
    <Image Source="{DynamicResource LectorImage}" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="None" />
</ToggleButton>
4b9b3361

Ответ 1

Вы можете получить необходимую функциональность, создав UserControl, который предоставляет свойства зависимостей для Command, IsChecked и один для каждого изображения с состоянием. Пользовательский элемент управления будет содержать кнопку переключения и изображение.

Вы можете использовать MultiDataTriggers для определения вашего состояния и swtich изображения в зависимости от состояния.

Поскольку вы выставили DependencyProperties для изображений с состоянием, их можно настроить с помощью привязки данных, где бы вы ни объявляли свой контроль. Триггеры автоматически переключат источник изображения для вас, как только состояние изменится.

[Edit: добавлен код, который поможет объяснить]

Вот частичный пример, чтобы вы начали:

MyToggleButton.xaml:

<UserControl x:Class="ToggleTest.MyToggleButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ToggleButton
    IsChecked='{Binding RelativeSource={RelativeSource FindAncestor, 
    AncestorType={x:Type ToggleButton} }, 
    Path=IsChecked}'>
    <Image
        x:Name='ButtonImage'>
        <Image.Style>
            <Style
                TargetType='{x:Type Image}'>
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition
                                Binding='{Binding 
                                RelativeSource={RelativeSource FindAncestor, 
                                AncestorType={x:Type ToggleButton} }, 
                                Path=IsChecked}'
                                Value='True' />
                            <Condition
                                Binding='{Binding 
                                RelativeSource={RelativeSource Self}, 
                                Path=IsEnabled}'
                                Value='True' />
                        </MultiDataTrigger.Conditions>
                        <Setter
                            Property='Source'
                            Value='{Binding 
                            RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type UserControl} }, 
                            Path=EnabledChecked}' />
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition
                                Binding='{Binding 
                                RelativeSource={RelativeSource FindAncestor, 
                                AncestorType={x:Type ToggleButton} }, 
                                Path=IsChecked}'
                                Value='False' />
                            <Condition
                                Binding='{Binding 
                                RelativeSource={RelativeSource Self}, 
                                Path=IsEnabled}'
                                Value='True' />
                        </MultiDataTrigger.Conditions>
                        <Setter
                            Property='Source'
                            Value='{Binding 
                            RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type UserControl} }, 
                            Path=EnabledUnchecked}' />
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition
                                Binding='{Binding 
                                RelativeSource={RelativeSource FindAncestor, 
                                AncestorType={x:Type ToggleButton} }, 
                                Path=IsChecked}'
                                Value='False' />
                            <Condition
                                Binding='{Binding 
                                RelativeSource={RelativeSource Self}, 
                                Path=IsEnabled}'
                                Value='False' />
                        </MultiDataTrigger.Conditions>
                        <Setter
                            Property='Source'
                            Value='{Binding 
                            RelativeSource={RelativeSource FindAncestor, 
                            AncestorType={x:Type UserControl} }, 
                            Path=DisabledUnchecked}' />
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </Image.Style>
    </Image>
</ToggleButton>

И файл cs:

using System;

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;

    namespace ToggleTest

{
    /// <summary>
    /// Interaction logic for ToggleButton.xaml
    /// </summary>
    public partial class MyToggleButton : UserControl
    {
        public MyToggleButton()
        {
            InitializeComponent();
        }


        public static readonly DependencyProperty EnabledUncheckedProperty =
            DependencyProperty.Register(
            "EnabledUnchecked",
            typeof(ImageSource),
            typeof(MyToggleButton),
            new PropertyMetadata(onEnabledUncheckedChangedCallback));

        public ImageSource EnabledUnchecked
        {
            get { return (ImageSource)GetValue(EnabledUncheckedProperty); }
            set { SetValue(EnabledUncheckedProperty, value); }
        }

        static void onEnabledUncheckedChangedCallback(
            DependencyObject dobj,
            DependencyPropertyChangedEventArgs args)
        {
            //do something if needed
        }

        public static readonly DependencyProperty DisabledUncheckedProperty =
            DependencyProperty.Register(
            "DisabledUnchecked",
            typeof(ImageSource),
            typeof(MyToggleButton),
            new PropertyMetadata(onDisabledUncheckedChangedCallback));

        public ImageSource DisabledUnchecked
        {
            get { return (ImageSource)GetValue(DisabledUncheckedProperty); }
            set { SetValue(DisabledUncheckedProperty, value); }
        }

        static void onDisabledUncheckedChangedCallback(
            DependencyObject dobj,
            DependencyPropertyChangedEventArgs args)
        {
            //do something if needed
        }


        public static readonly DependencyProperty EnabledCheckedProperty =
            DependencyProperty.Register(
            "EnabledChecked",
            typeof(ImageSource),
            typeof(MyToggleButton),
            new PropertyMetadata(onEnabledCheckedChangedCallback));

        public ImageSource EnabledChecked
        {
            get { return (ImageSource)GetValue(EnabledCheckedProperty); }
            set { SetValue(EnabledCheckedProperty, value); }
        }

        static void onEnabledCheckedChangedCallback(
            DependencyObject dobj,
            DependencyPropertyChangedEventArgs args)
        {
            //do something if needed
        }


        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register(
            "IsChecked",
            typeof(Boolean),
            typeof(MyToggleButton),
            new PropertyMetadata(onCheckedChangedCallback));

        public Boolean IsChecked
        {
            get { return (Boolean)GetValue(IsCheckedProperty); }
            set { if(value != IsChecked) SetValue(IsCheckedProperty, value); }
        }

        static void onCheckedChangedCallback(
            DependencyObject dobj,
            DependencyPropertyChangedEventArgs args)
        {
            //do something, if needed
        }



    }
}

Этот элемент управления можно использовать следующим образом:

<local:MyToggleButton
            IsChecked='True'
            IsEnabled='False'
            EnabledChecked='<add your image source here>'
            EnabledUnchecked='<add your image source here>'
            DisabledUnchecked='<add your image source here>'/>

Ответ 2

Это решение является простым:

 <ToggleButton IsChecked="{Binding IsCheckedState}">
            <Image Width="24" Height="24"  >
                <Image.Style>
                    <Style TargetType="{x:Type Image}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsCheckedState}" Value="true">
                                <Setter Property="Source" Value="Images/checked.ico"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding IsCheckedState}" Value="false">
                                <Setter Property="Source" Value="Images/unchecked.ico"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Image.Style>
            </Image>
        </ToggleButton>

Ответ 3

Сэр Эд Гонсалес, спасибо вам за хороший пример.

Единственная проблема заключается в том, что привязка к свойству зависимостей MyToggleButton.IsChecked не работает должным образом (платформа: Windows 7., NET 4.0, VS2010). Поэтому я сделал некоторые изменения в вашем примере.

XAML:

<ToggleButton x:Class="MyApp.ToggleButtonEx"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         Checked="ToggleButton_CheckedChanged"
         Unchecked="ToggleButton_CheckedChanged"
         IsEnabledChanged="ToggleButton_IsEnabledChanged"
         Loaded="ToggleButton_Loaded">
    <Image x:Name='ButtonImage'/>
</ToggleButton>

CS:

public partial class ToggleButtonEx : ToggleButton
{
    public ToggleButtonEx()
    {
        InitializeComponent();            
    }

    public static readonly DependencyProperty EnabledUncheckedProperty =
        DependencyProperty.Register(
        "EnabledUnchecked",
        typeof(ImageSource),
        typeof(ToggleButtonEx),
        new PropertyMetadata(onEnabledUncheckedChangedCallback));

    public ImageSource EnabledUnchecked
    {
        get { return (ImageSource)GetValue(EnabledUncheckedProperty); }
        set { SetValue(EnabledUncheckedProperty, value); }
    }

    static void onEnabledUncheckedChangedCallback(
        DependencyObject dobj,
        DependencyPropertyChangedEventArgs args)
    {
        //do something if needed
    }

    public static readonly DependencyProperty DisabledUncheckedProperty =
        DependencyProperty.Register(
        "DisabledUnchecked",
        typeof(ImageSource),
        typeof(ToggleButtonEx),
        new PropertyMetadata(onDisabledUncheckedChangedCallback));

    public ImageSource DisabledUnchecked
    {
        get { return (ImageSource)GetValue(DisabledUncheckedProperty); }
        set { SetValue(DisabledUncheckedProperty, value); }
    }

    static void onDisabledUncheckedChangedCallback(
        DependencyObject dobj,
        DependencyPropertyChangedEventArgs args)
    {
        //do something if needed
    }


    public static readonly DependencyProperty EnabledCheckedProperty =
        DependencyProperty.Register(
        "EnabledChecked",
        typeof(ImageSource),
        typeof(ToggleButtonEx),
        new PropertyMetadata(onEnabledCheckedChangedCallback));

    public ImageSource EnabledChecked
    {
        get { return (ImageSource)GetValue(EnabledCheckedProperty); }
        set { SetValue(EnabledCheckedProperty, value); }
    }

    static void onEnabledCheckedChangedCallback(
        DependencyObject dobj,
        DependencyPropertyChangedEventArgs args)
    {
        //do something if needed
    }

    private void ToggleButton_CheckedChanged(object sender, RoutedEventArgs e)
    {
        ChangeImage();
    }

    private void ToggleButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        ChangeImage();
    }

    private void ToggleButton_Loaded(object sender, RoutedEventArgs e)
    {
        ChangeImage();
    }

    private void ChangeImage()
    {
        if (IsEnabled)
        {
            if(IsChecked == true)
                ButtonImage.Source = EnabledChecked;
            else
                ButtonImage.Source = EnabledUnchecked;
        }
        else
        {
            ButtonImage.Source = DisabledUnchecked;
        }
    }
}

Шаблон использования остается неизменным:

<local:MyToggleButton
        IsChecked='True'
        IsEnabled='False'
        EnabledChecked='<add your image source here>'
        EnabledUnchecked='<add your image source here>'
        DisabledUnchecked='<add your image source here>'/>

Ответ 4

Я сделал то же самое для своего RibbonToggleButton, но немного легче. Я помещаю триггер стиля внутри кнопки вместо использования дополнительного элемента изображения.

 <RibbonToggleButton Label="{x:Static p:Resources.Main_Connect}" Command="{Binding ConnectRemoteCommand}" CommandParameter="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}">
                        <RibbonToggleButton.Style>
                            <Style TargetType="{x:Type RibbonToggleButton}">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Value="true">
                                        <Setter Property="LargeImageSource" Value="../../Resources/Images/GPS-On.png"/>
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding Path=IsChecked, RelativeSource={RelativeSource Self}}" Value="false">
                                        <Setter Property="LargeImageSource" Value="../../Resources/Images/GPS-Off.png"/>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </RibbonToggleButton.Style>
                    </RibbonToggleButton>

Ответ 5

Сэр Эд Гонсалес, спасибо вам за хороший пример.

Единственная проблема заключается в том, что привязка к MyToggleButton.IsChecked свойство зависимостей не работает должным образом (платформа: Windows 7., NET 4.0, VS2010). Поэтому я сделал некоторые изменения в вашем примере.

Просто удалите static в IsChecked DependencyProperty, добавьте ваш ChangeImage() в IsChecked(), и пример сэра Эд Гонсалеса хорошо работает ^^

public readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register(
            "IsChecked" ...

public Boolean IsChecked
... if (value != IsChecked) SetValue(IsCheckedProperty, value); ChangeImage();