WPF自定义RadioButton运行时修改图片文本的替代实现方案咨询
可选实现方案
方案1:使用自定义附加属性(推荐轻度扩展场景)
Tag是无类型的object属性,仅能存储单个值,可读性和类型安全性都很差。你可以通过附加属性定义三个强类型属性,分别存储图标、主标题、副标题,满足多值绑定需求的同时也方便后续扩展。
首先定义附加属性的C#代码:
public static class ButtonExtensions { // 图标源附加属性 public static readonly DependencyProperty IconSourceProperty = DependencyProperty.RegisterAttached( "IconSource", typeof(ImageSource), typeof(ButtonExtensions), new PropertyMetadata(null)); public static void SetIconSource(DependencyObject element, ImageSource value) => element.SetValue(IconSourceProperty, value); public static ImageSource GetIconSource(DependencyObject element) => (ImageSource)element.GetValue(IconSourceProperty); // 主标题附加属性 public static readonly DependencyProperty TitleProperty = DependencyProperty.RegisterAttached( "Title", typeof(string), typeof(ButtonExtensions), new PropertyMetadata(string.Empty)); public static void SetTitle(DependencyObject element, string value) => element.SetValue(TitleProperty, value); public static string GetTitle(DependencyObject element) => (string)element.GetValue(TitleProperty); // 副标题附加属性 public static readonly DependencyProperty SubtitleProperty = DependencyProperty.RegisterAttached( "Subtitle", typeof(string), typeof(ButtonExtensions), new PropertyMetadata(string.Empty)); public static void SetSubtitle(DependencyObject element, string value) => element.SetValue(SubtitleProperty, value); public static string GetSubtitle(DependencyObject element) => (string)element.GetValue(SubtitleProperty); }
然后修改你的ControlTemplate,替换原来硬编码的文本和Tag绑定:
<Image Source="{Binding Path=(local:ButtonExtensions.IconSource), RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" Stretch="Uniform" Width="45" IsEnabled="True" /> <StackPanel Margin="2"> <TextBlock Foreground="#DCDDDE" FontSize="18" FontFamily="Arial" Text="{Binding Path=(local:ButtonExtensions.Title), RelativeSource={RelativeSource TemplatedParent}}"/> <TextBlock Foreground="#52555C" FontSize="12" FontFamily="Arial" Text="{Binding Path=(local:ButtonExtensions.Subtitle), RelativeSource={RelativeSource TemplatedParent}}"/> </StackPanel>
运行时创建控件的赋值方式:
RadioButton radioButton = new RadioButton(); radioButton.GroupName = "Side"; radioButton.Style = (Style)Resources["ToggleButton_Chose"]; ButtonExtensions.SetIconSource(radioButton, new BitmapImage(new Uri("图标路径"))); ButtonExtensions.SetTitle(radioButton, "自定义主标题"); ButtonExtensions.SetSubtitle(radioButton, "自定义副标题");
方案2:自定义派生控件(推荐高频复用场景)
如果这类按钮是项目通用控件,可以直接继承RadioButton定义自定义控件,内置三个依赖属性,封装性更好,也支持直接在XAML中声明使用:
自定义控件C#代码:
public class ImageTextRadioButton : RadioButton { public static readonly DependencyProperty IconSourceProperty = DependencyProperty.Register( nameof(IconSource), typeof(ImageSource), typeof(ImageTextRadioButton), new PropertyMetadata(null)); public ImageSource IconSource { get => (ImageSource)GetValue(IconSourceProperty); set => SetValue(IconSourceProperty, value); } public static readonly DependencyProperty TitleProperty = DependencyProperty.Register( nameof(Title), typeof(string), typeof(ImageTextRadioButton), new PropertyMetadata(string.Empty)); public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); } public static readonly DependencyProperty SubtitleProperty = DependencyProperty.Register( nameof(Subtitle), typeof(string), typeof(ImageTextRadioButton), new PropertyMetadata(string.Empty)); public string Subtitle { get => (string)GetValue(SubtitleProperty); set => SetValue(SubtitleProperty, value); } }
对应修改样式的TargetType和绑定逻辑:
<Style x:Key="ToggleButton_Chose" TargetType="{x:Type local:ImageTextRadioButton}" > <!-- 其余Setter保持不变 --> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:ImageTextRadioButton}"> <!-- 其余结构保持不变 --> <Image Source="{TemplateBinding IconSource}" HorizontalAlignment="Left" Stretch="Uniform" Width="45" IsEnabled="True" /> <StackPanel Margin="2"> <TextBlock Foreground="#DCDDDE" FontSize="18" FontFamily="Arial" Text="{TemplateBinding Title}"/> <TextBlock Foreground="#52555C" FontSize="12" FontFamily="Arial" Text="{TemplateBinding Subtitle}"/> </StackPanel> </ControlTemplate> </Setter.Value> </Setter> </Style>
运行时赋值更简洁:
ImageTextRadioButton radioButton = new ImageTextRadioButton(); radioButton.GroupName = "Side"; radioButton.Style = (Style)Resources["ToggleButton_Chose"]; radioButton.IconSource = new BitmapImage(new Uri("图标路径")); radioButton.Title = "自定义主标题"; radioButton.Subtitle = "自定义副标题";
方案3:MVVM+数据绑定(推荐100个批量生成场景)
你有100个同类型按钮,完全不需要手动逐个创建控件,可以通过MVVM模式实现自动批量生成,减少重复代码:
首先创建项的ViewModel:
public class RadioButtonItemViewModel : INotifyPropertyChanged { public ImageSource IconSource { get; set; } public string Title { get; set; } public string Subtitle { get; set; } public bool IsChecked { get; set; } // 可根据业务需求添加其他属性 }
在页面ViewModel中定义绑定集合:
public ObservableCollection<RadioButtonItemViewModel> RadioButtonItems { get; set; } = new ObservableCollection<RadioButtonItemViewModel>(); // 初始化时批量添加100个项即可,不需要手动创建控件
XAML中用ItemsControl绑定集合,自动生成RadioButton:
<ItemsControl ItemsSource="{Binding RadioButtonItems}"> <ItemsControl.ItemTemplate> <DataTemplate> <RadioButton GroupName="Side" Style="{StaticResource ToggleButton_Chose}" local:ButtonExtensions.IconSource="{Binding IconSource}" local:ButtonExtensions.Title="{Binding Title}" local:ButtonExtensions.Subtitle="{Binding Subtitle}" IsChecked="{Binding IsChecked}"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
后续只需要操作ViewModel集合即可完成所有按钮的增删改配置,不需要写任何控件创建的后台代码。
内容的提问来源于stack exchange,提问作者Onzeq
相关产品推荐
相关产品推荐

