添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

WPF多个按钮点击切换样式

本文主要讲述WPF中多个按钮,点击状态为一个样式,未点击状态为一个样式,两种样式通过点击这个动作会发生改变,点击另一个按钮,当前已点击的按钮样式也改变的情况。

不复杂样式的多个按钮

主要做法就是将按钮使用radiobutton来代替,然后各个radiobutton的GroupName取名为同一个,如本例中就是取名为“button1”。

<RadioButton Foreground="White" Background="#586c88" HorizontalContentAlignment = "Center" VerticalContentAlignment = "Center" Padding="0" GroupName="button1">
    <RadioButton.Template>
        <ControlTemplate TargetType="RadioButton">
            <Border Name="bd" BorderThickness="4" CornerRadius="4" BorderBrush="#586c88" Background="#586c88">
                <ContentPresenter Content="{Binding Position}" HorizontalAlignment="Center"/>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsChecked" Value="True">
                    <Setter TargetName="bd" Property="Background" Value="#21b4de" />
                    <Setter TargetName="bd" Property="BorderBrush" Value="#21b4de" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </RadioButton.Template>
</RadioButton>

不复杂样式的多个按钮
上图A1代表点击的,B1代表没点击的,其他都是其他样式,使用触发器,当radiobutton的ischeck属性改变的时候更改他的颜色

复杂样式的多个按钮

上图只是改个颜色那么上述的代码已经足够实现了,但是,假如这个按钮是拥有UI设计的,那么就点击状态有一个图片,未点击状态为另一个图片,然后文字或者字体颜色也可能发生变化,比如当背景颜色变为纯黑的时候,字体为黑色就看不到了,就要改为白色,当背景颜色变为纯白的时候,字体为白色就看不到了,就要改回黑色。那么这种时候就要更改Button的Background了,本例决定使用模板选择器来更改样式。
前端xaml代码

<Button x:Name="btnCaptureChipImage" Height="34" Padding="0" VerticalAlignment="Center" IsEnabled="{Binding ChipAnalysisButtonEnabled}"  Click="btnCaptureChipImage_Click" BorderThickness="0" Cursor="Hand">
    <ContentPresenter Content="{Binding ChipBtn}">
        <ContentPresenter.ContentTemplateSelector>
            <local:ChipBtnTemplateSelector>
                <local:ChipBtnTemplateSelector.WhiteTemplate>
                    <DataTemplate>
                        <Grid Height="34" MinWidth="97">
                            <Grid.Background>
                                <ImageBrush ImageSource="/Images/BlueButton.png"  Stretch="Fill" TileMode="None" />
                            </Grid.Background>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="/Images/Camera_White.png" Width="16" Height="16" Margin="10,0,0,0"/>
                                <TextBlock Text="{DynamicResource Res_C_ExecWork}" TextWrapping="Wrap" FontSize="16" Foreground="White" VerticalAlignment="Center" Margin="5,0,5,0"/>
                            </StackPanel>
                        </Grid>
                    </DataTemplate>
                </local:ChipBtnTemplateSelector.WhiteTemplate>
                <local:ChipBtnTemplateSelector.BlackTemplate>
                    <DataTemplate>
                        <Grid Height="34" MinWidth="97">
                            <Grid.Background>
                                <ImageBrush ImageSource="/Images/WhiteButton.png"  Stretch="Fill" TileMode="None" />
                            </Grid.Background>
                            <StackPanel Orientation="Horizontal">
                                <Image Source="/Images/Camera_Black.png" Width="16" Height="16" Margin="10,0,0,0"/>
                                <TextBlock Text="{DynamicResource Res_C_ExecWork}" TextWrapping="Wrap" FontSize="16" Foreground="Black" VerticalAlignment="Center" Margin="5,0,5,0"/>
                            </StackPanel>
                        </Grid>
                    </DataTemplate>
                </local:ChipBtnTemplateSelector.BlackTemplate>
            </local:ChipBtnTemplateSelector>
        </ContentPresenter.ContentTemplateSelector>
    </ContentPresenter>
</Button>

后台 模板选择器代码

/// <summary>
/// 版型设计页面四个按钮模板选择器
/// </summary>
public class ChipBtnTemplateSelector : DataTemplateSelector
    public DataTemplate WhiteTemplate { get; set; }
    public DataTemplate BlackTemplate { get; set; }
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
        if (item == null)
            return null;
        Button button = container.GetParentObject() as Button;
        ChipBtn chipBtn = (ChipBtn)item;
        if(button.Name == "btnCaptureChipImage")
            if (chipBtn == ChipBtn.Camera)
                return WhiteTemplate;
                return BlackTemplate;
        else if(button.Name == "btnExecChipAnalysis")
            if (chipBtn == ChipBtn.Analysis)
                return WhiteTemplate;
                return BlackTemplate;
        else if(button.Name == "btnExecAllChipAnalysis")
            if (chipBtn == ChipBtn.AllAnalysis)
                return WhiteTemplate;
                return BlackTemplate;
        else if(button.Name == "btnImportChipImage")
            if (chipBtn == ChipBtn.Import)
                return WhiteTemplate;
                return BlackTemplate;
        return null;
//按钮Click事件更改ChipBtn枚举值。
private void btnCaptureChipImage_Click(object sender, RoutedEventArgs e)
    ViewModel.ChipBtn = ChipBtn.Camera;

复杂样式的多个按钮
上图左一按钮代表点击的,其他三个代表没点击的,使用模板选择器每次点击就更改VM中定义的ChipBtn,然后Button的ContentPresenter的Content binding的就是ChipBtn他一改变就进入了模板选择器的SelectTemplate方法,在该方法中通过查找当前按钮的Name与点击时改变的ChipBtn做匹配,匹配正确就A模板,匹配不正确就B模板。这个方法一共进四次(有几个按钮就进几次,有四个按钮,每个按钮进一次,因为每个按钮都绑定了ChipBtn)。

更加复杂的样式的多个按钮

多个按钮选中一个变色,选中其他的,这个变回,那个选中的变色,同时按钮是会变的,按钮中的左边图片跟文字颜色会随着后台另一个属性的变化而变化。那就不能用上面所说的模板选择器了。因为就算同是白的 也有不同的图片不同的文字颜色。那么如果还用模板选择器,那么每个按钮就要定义2*不同图片种类数(本次例子中为5个)就是10个了,上面所说的模板选择器已经很冗余了,这个更冗余了,就排除了,选择了下列方法,用了三个IValueConverter转换器改他的背景,按钮内左边的图片与文字颜色。
前端xaml代码

<Button x:Name="button1" Click="button1_Click" Height="34" Margin="10,0,0,0" Padding="0" Cursor="Hand">
    <Button.Background>
        <ImageBrush Stretch="Fill" TileMode="None">
            <ImageBrush.ImageSource>
                <MultiBinding Converter="{StaticResource ButtonBackgroundChanged}" FallbackValue="/Images/WhiteButton.png">
                    <Binding Path="AnalysisBtn"/>
                    <Binding Path="CurrentProject.TabItemName[0]"/>
                </MultiBinding>
            </ImageBrush.ImageSource>
        </ImageBrush>
    </Button.Background>
    <StackPanel Orientation="Horizontal" MinWidth="97">
        <Image Width="16" Height="16" Margin="5,0,0,0">
            <Image.Source>
                <MultiBinding Converter="{StaticResource ButtonImageChanged}" FallbackValue="/Images/FAM_Black.png">
                    <Binding Path="AnalysisBtn"/>
                    <Binding Path="CurrentProject.TabItemName[0]"/>
                    <Binding ElementName="button1" Path="Name"/>
                </MultiBinding>
            </Image.Source>
        </Image>
        <TextBlock Text="{Binding CurrentProject.TabItemName[0],FallbackValue='FAM Scatter'}" TextWrapping="Wrap" FontSize="16" Margin="5,0,5,0" VerticalAlignment="Center">
            <TextBlock.Foreground>
                <MultiBinding Converter="{StaticResource TextForegroundChanged}" FallbackValue="Black">
                    <Binding Path="AnalysisBtn"/>
                    <Binding Path="CurrentProject.TabItemName[0]"/>
                </MultiBinding>
            </TextBlock.Foreground>
        </TextBlock>
    </StackPanel>
</Button>

xmal代码中声明IValueConverter转换器

//声明三个转换器
<local:ButtonBackgroundChanged x:Key="ButtonBackgroundChanged"/>
<local:ButtonImageChanged x:Key="ButtonImageChanged"/>
<local:TextForegroundChanged x:Key="TextForegroundChanged"/>

后台IValueConverter转换器代码

//定义三个转换器
public class ButtonBackgroundChanged : IMultiValueConverter
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            if (values[1] == DependencyProperty.UnsetValue)
                return new System.Windows.Media.Imaging.BitmapImage(new Uri("pack://application:,,,/当前项目名称;component/Images/WhiteButton.png"));
            AnalysisBtn analysisBtn = (AnalysisBtn)values[0];
            string geneName = values[1].ToString().Substring(0, 3);
            if (geneName == analysisBtn.ToString())
                return new System.Windows.Media.Imaging.BitmapImage(new Uri("pack://application:,,,/当前项目名称;component/Images/BlueButton.png"));
                return new System.Windows.Media.Imaging.BitmapImage(new Uri("pack://application:,,,/当前项目名称;component/Images/WhiteButton.png"));
        catch(Exception)
            throw;
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        return null;
public class ButtonImageChanged : IMultiValueConverter
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            if (values[1] == DependencyProperty.UnsetValue)
                if(values[2].ToString() == "button1")
                    return new System.Windows.Media.Imaging.BitmapImage(new Uri("pack://application:,,,/当前项目名称;component/Images/FAM_Black.png"));
                    return new System.Windows.Media.Imaging.BitmapImage(new Uri("pack://application:,,,/当前项目名称;component/Images/VIC_Black.png"));
            AnalysisBtn analysisBtn = (AnalysisBtn)values[0];
            string geneName = values[1].ToString().Substring(0, 3);
            if (geneName == analysisBtn.ToString())
                return new System.Windows.Media.Imaging.BitmapImage(new Uri(string.Format("pack://application:,,,/当前项目名称;component/Images/{0}_White.png",geneName)));
                return new System.Windows.Media.Imaging.BitmapImage(new Uri(string.Format("pack://application:,,,/当前项目名称;component/Images/{0}_Black.png", geneName)));
        catch (Exception)
            throw;
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        return null;
public class TextForegroundChanged : IMultiValueConverter
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            if (values[1] == DependencyProperty.UnsetValue)
                return new SolidColorBrush(Colors.Black);
            AnalysisBtn analysisBtn = (AnalysisBtn)values[0];
            string geneName = values[1].ToString().Substring(0, 3);
            if (geneName == analysisBtn.ToString())
                return new SolidColorBrush(Colors.White);
                return new SolidColorBrush(Colors.Black);
        catch (Exception)
            throw;
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        return null;

更加复杂的样式的多个按钮
为什么说这个图很复杂呢,明明跟上面的例子一模一样,主要是这个第二第三个按钮,他是动态的,不仅文字动态,他左边那个小图标“F”样子的那个也要变,而且点击了之后背景变了之后,这个小图标也要变,因为他是黑底的,要改为白底。

2019年11月7日更新

上面这种用模板的实现方式还是太复杂了,可以不要参考了,实际上,使用依赖属性就能做到,而且非常简单。我参考了WPF依赖属性的正确学习方法

先自定义一个MyButton继承Button

public class MyButton : Button
    public static readonly DependencyProperty ForeImageProperty = DependencyProperty.Register(nameof(ForeImage), typeof(string), typeof(MyButton), new PropertyMetadata(null));
    public static readonly DependencyProperty BackImageProperty = DependencyProperty.Register(nameof(BackImage), typeof(string), typeof(MyButton), new PropertyMetadata(null));
    public string ForeImage
        get { return (string)GetValue(ForeImageProperty); }
        set { SetValue(ForeImageProperty, value); }
    public string BackImage
        get { return (string)GetValue(BackImageProperty); }
        set { SetValue(BackImageProperty, value); }

然后定义一个style修改他的模板

<Style TargetType="{x:Type local:MyButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid Height="34" MinWidth="97" Name="dpBtn">
                    <Grid.Background>
                        <ImageBrush ImageSource="/Images/BlueButton.png" Stretch="Fill" TileMode="None" />
                    </Grid.Background>
                    <StackPanel Orientation="Horizontal">
                        <Image Name="img" Source="{Binding ForeImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}" Width="16" Height="16" Margin="10,0,0,0"/>
                        <TextBlock Name="txt" Text="{Binding Content, RelativeSource={x:Static RelativeSource.TemplatedParent}}" TextWrapping="Wrap" FontSize="16" Foreground="White" VerticalAlignment="Center" Margin="5,0,5,0"/>
                    </StackPanel>
                </Grid>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding IsMouseOver,RelativeSource={x:Static RelativeSource.Self}}" Value="True">
                        <Setter Property="Background" TargetName="dpBtn">
                            <Setter.Value>
                                <ImageBrush ImageSource="/Images/BlueButton.png" Stretch="Fill" TileMode="None" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Source" TargetName="img" Value="{Binding ForeImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                        <Setter Property="Foreground" TargetName="txt" Value="white"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsMouseOver,RelativeSource={x:Static RelativeSource.Self}}" Value="False">
                        <Setter Property="Background" TargetName="dpBtn">
                            <Setter.Value>
                                <ImageBrush ImageSource="/Images/WhiteButton.png" Stretch="Fill" TileMode="None" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Source" TargetName="img" Value="{Binding BackImage, RelativeSource={x:Static RelativeSource.TemplatedParent}}"/>
                        <Setter Property="Foreground" TargetName="txt" Value="black"/>
                    </DataTrigger>
                    <Trigger Property="IsEnabled" Value="true"/>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="Gray"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

主界面调用

<StackPanel x:Name="analysispanel" Orientation="Horizontal">
	<local:MyButton x:Name="bt1" ForeImage="/Images/Camera_White.png" BackImage="/Images/Camera_Black.png" Content="相机" Height="34" MinWidth="97"/>
	<local:MyButton x:Name="bt2" ForeImage="/Images/AllAnalysis_White.png" BackImage="/Images/AllAnalysis_Black.png" Content="全部分析" Height="34" MinWidth="97"/>
	<local:MyButton x:Name="bt3" ForeImage="/Images/Analysis_White.png" BackImage="/Images/Analysis_Black.png" Content="分析" Height="34" MinWidth="97"/>
	<local:MyButton x:Name="bt4" ForeImage="/Images/Import_White.png" BackImage="/Images/Import_Black.png" Content="导入" Height="34" MinWidth="97"/>
</StackPanel>

其他还可以参考微软官方的通过创建 ControlTemplate 自定义现有控件的外观

WPF多个按钮点击切换样式本文主要讲述WPF中多个按钮,点击状态为一个样式,未点击状态为一个样式,两种样式通过点击这个动作会发生改变,点击另一个按钮,当前已点击的按钮样式也改变的情况。不复杂样式的多个按钮主要做法就是将按钮使用radiobutton来代替,然后各个radiobutton的GroupName取名为同一个,如本例中就是取名为“button1”。&amp;amp;lt;RadioButton ...
IValueConverter类 Bingding.Converter https://www.cnblogs.com/gaoshang212/p/4973300.html?utm_source=tuicool&utm_medium=referral 1.需求说明 显示界面上有多个RadioButton,需要选择其中一个来修改一个枚举类型的值。举例:有七个RadioButton,星期一到星期日,选择其中之一可以改变枚举类型week的对应值。 2.实现方法 利用Converter...
1.StackPanel WrapPanel DockPanel StackPanel <!--排列成一行或一列 StackPanel 默认排列方向 :垂直 水平:高度与父窗口的高度相同 子元素超出部分会被隐藏--> <!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Center"> <Button>按钮1</Button> <Button Marg
好的,关于WPF运行时动态切换ItemsControl.ItemsPanel的问题,我可以为您提供以下思路: 1. 创建多个ItemsPanel,例如:StackPanel、WrapPanel、UniformGrid等。 2. 在XAML文件中,使用Resources定义这些ItemsPanel。 3. 创建一个ItemsControl,并在ItemsControl中使用DataTemplate来定义Item的样式。 4. 在ItemsControl中,使用一个默认的ItemsPanel。 5. 在运行时,根据需要动态切换ItemsControl的ItemsPanel。 6. 在切换时,先从ItemsControl的Resources中获取要切换的ItemsPanel,然后将其设置为ItemsControl的ItemsPanel。 以下是一个简单的示例代码: ```xml <!--MainWindow.xaml--> <Window> <Window.Resources> <ItemsPanelTemplate x:Key="StackPanelTemplate"> <StackPanel/> </ItemsPanelTemplate> <ItemsPanelTemplate x:Key="WrapPanelTemplate"> <WrapPanel/> </ItemsPanelTemplate> <ItemsPanelTemplate x:Key="UniformGridTemplate"> <UniformGrid/> </ItemsPanelTemplate> </Window.Resources> <StackPanel> <StackPanel Orientation="Horizontal"> <Button Content="StackPanel" Click="StackPanel_Click"/> <Button Content="WrapPanel" Click="WrapPanel_Click"/> <Button Content="UniformGrid" Click="UniformGrid_Click"/> </StackPanel> <ItemsControl ItemsSource="{Binding Items}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"/> </DataTemplate> </ItemsControl.ItemTemplate> <!--默认的ItemsPanel--> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </ItemsControl> </StackPanel> </Window> ```csharp //MainWindow.xaml.cs public partial class MainWindow : Window public ObservableCollection<string> Items { get; set; } public MainWindow() InitializeComponent(); Items = new ObservableCollection<string>() { "Item 1", "Item 2", "Item 3" }; DataContext = this; private void StackPanel_Click(object sender, RoutedEventArgs e) ItemsControl.ItemsPanel = (ItemsPanelTemplate)Resources["StackPanelTemplate"]; private void WrapPanel_Click(object sender, RoutedEventArgs e) ItemsControl.ItemsPanel = (ItemsPanelTemplate)Resources["WrapPanelTemplate"]; private void UniformGrid_Click(object sender, RoutedEventArgs e) ItemsControl.ItemsPanel = (ItemsPanelTemplate)Resources["UniformGridTemplate"]; 在这个示例中,我们创建了三个不同的ItemsPanel,分别是StackPanel、WrapPanel和UniformGrid,然后在XAML文件中使用Resources定义它们。在MainWindow中,我们创建了一个ItemsControl,并在ItemsControl中使用DataTemplate来定义Item的样式,同时设置了一个默认的ItemsPanel。 在运行时,我们通过点击按钮来动态切换ItemsControl的ItemsPanel。在每个按钮的Click事件中,我们从MainWindow的Resources中获取要切换的ItemsPanel,然后将其设置为ItemsControl的ItemsPanel。 希望以上思路能够对您有所帮助。
<MultiTrigger.Conditions> <Condition Property="IsSelected" Value="true" /> <Condition Property="IsSelectionActive" Value="false" /> </MultiTrigger.Conditions> <!--这个是选中的颜色--> <Setter Property="Background" TargetName="Bd" Value="#f3f3ff" /> <Setter Property="Foreground" Value="Black" /> </MultiTrigger> WPF中TextBox更改完了之后进行操作 抹茶芭菲: 请问这个SourceUpdated事件为啥要在失去TextBox的焦点才会执行,可以在TextBox更改Text的时候立即执行吗 WPF自定义最大化最小化关闭按钮 迷惘小书童: 已更新,你看看