赞
踩
本文主要讲述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; else return BlackTemplate; } else if(button.Name == "btnExecChipAnalysis") { if (chipBtn == ChipBtn.Analysis) return WhiteTemplate; else return BlackTemplate; } else if(button.Name == "btnExecAllChipAnalysis") { if (chipBtn == ChipBtn.AllAnalysis) return WhiteTemplate; else return BlackTemplate; } else if(button.Name == "btnImportChipImage") { if (chipBtn == ChipBtn.Import) return WhiteTemplate; else 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) { try { 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")); else 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) { try { 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")); else 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))); else 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) { try { 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); else return new SolidColorBrush(Colors.Black); } catch (Exception) { throw; } } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { return null; } }
为什么说这个图很复杂呢,明明跟上面的例子一模一样,主要是这个第二第三个按钮,他是动态的,不仅文字动态,他左边那个小图标“F”样子的那个也要变,而且点击了之后背景变了之后,这个小图标也要变,因为他是黑底的,要改为白底。
上面这种用模板的实现方式还是太复杂了,可以不要参考了,实际上,使用依赖属性就能做到,而且非常简单。我参考了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 自定义现有控件的外观
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。