【小技巧积累】用Style实现必填提示“*”根据选项的不同而显示或隐藏

1.问题需求

有一个界面,界面上有一组单选按钮(一个是“可选”,另一个是“必填”),还有一个“备注”信息的文本输入框。现在要求在选择“必填”时,“备注”信息不能为空,此时应该在“备注”文本框前显示必填标志(常用的是“*”),如图2所示;而在选在“可选”时,“备注”信息可为空,此时必填标志“*”应该隐藏起来,如图1所示。

图1 备注可选

图2 备注必填

2.问题分析

当然,这个问题实际上很简单。如果是文本“备注”是通过TextBlock和文本输入框放在同一个GroupBox中,那么我们可以在“备注”TextBlock和文本输入框之间加一个显示“*”的TextBlock(为了描述方便,假设将其命名为tbStar)。则在选择“可选”时,将tbStar的Visibility属性设置为Hidden(隐藏);而在选择“必填”时,将tbStar的Visibility属性设置为Visible(可见)。至于,如何响应选择“可选”还是选择“必填”,我们可以使用事件和可以使用命令,这个不是这里要讲的重点,我们下面的代码中用了命令。

 

但是,通过图1和图2,我们看到此处的难点是:“备注”和“*”不是显示在GroupBox控件内部的,而是显示在GroupBox的Header属性中的。对于Header属性的设置,我们不可能直接将两个TextBlock控件(一个用于显示“备注”,一个用于显示“*”)设置为其值。于是,我们这里采用样式Style来实现。

3.实现代码

关于界面的XAML代码如下所示:

复制代码
 1 <Window x:Class="WPFTestDemo.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         Title="MainWindow" Height="350" Width="525">
 5     <Window.Resources>
 6         <Style x:Key="setHeaderStyle" TargetType="GroupBox">
 7             <Setter Property="Header">
 8                 <Setter.Value>
 9                     <StackPanel Orientation="Horizontal">
10                         <TextBlock Text="备注" />
11                         <TextBlock x:Name="txtStar" Text="*" Foreground="Red" Visibility="Collapsed"/>
12                     </StackPanel>
13                 </Setter.Value>
14             </Setter>
15         </Style>
16     </Window.Resources>
17     <Grid>
18         <Grid.RowDefinitions>
19             <RowDefinition Height="*" />
20             <RowDefinition Height="3*" />
21         </Grid.RowDefinitions>
22         <GroupBox Grid.Row="0" Margin="4" >
23             <StackPanel Orientation="Horizontal">
24                 <RadioButton VerticalAlignment="Stretch" Content="可选" IsChecked="True"
25                              Command="{Binding Command}" CommandParameter="NoNeed"/>
26                 <RadioButton VerticalAlignment="Stretch" Content="必填"
27                              Command="{Binding Command}" CommandParameter="Need"/>
28             </StackPanel>
29         </GroupBox>
30         <GroupBox Grid.Row="1" Margin="4" Style="{StaticResource setHeaderStyle}">
31             <TextBox ></TextBox>
32         </GroupBox>
33     </Grid>
34 </Window>
复制代码

从上面的代码第30行可见,控件GroupBox引用了静态资源setHeaderStyle。而从第6-15行可见,资源setHeaderStyle通过Setter设置了GroupBox的Header属性为一个StackPanel控件,而在StackPanel中提供了两个TextBlock,一个显示“备注”,一个显示“*”。第24-27行代码显示我们通过命令来响应单选按钮“可选”和“必填”的选择,这里的命令绑定到DataContext的Command属性。下面是界面的视图代码实现,

复制代码
 1 public partial class MainWindow : Window
 2 {
 3     private ViewModel viewModel = new ViewModel();
 4 
 5     public MainWindow()
 6     {
 7         InitializeComponent();
 8         this.DataContext = this.viewModel;
 9         this.viewModel.Command.ExecuteEvent += new Action<Object>(
10             delegate(object obj)
11             {
12                 OptionEnum oe = OptionEnum.NoNeed;
13                 Enum.TryParse<OptionEnum>((string)obj, out oe);
14                 if (oe == OptionEnum.NoNeed)
15                 {
16                     TextBlock tb = GetTextBlockStar();
17                     tb.Visibility = Visibility.Hidden;
18                 }
19                 else
20                 {
21                     TextBlock tb = GetTextBlockStar();
22                     tb.Visibility = Visibility.Visible;
23                 }
24             });
25     }
26     private TextBlock GetTextBlockStar()
27     {
28         Style style = (Style)this.FindResource("setHeaderStyle");
29         Setter sb = (Setter)style.Setters[0];
30         StackPanel sp = (StackPanel)sb.Value;
31         return (TextBlock)sp.Children[1];
32     }
33 }
复制代码

上面代码中的第9-24行的代码就是定义了用于响应单选按钮选择的命令,在第16-17行时,判断出选择了“可选”单选按钮,此时设置显示“*”的TextBlock控件的Visibility属性为Hidden(隐藏);而在第21-22行判断出选择了“必填”单选按钮,此时设置显示“*”的TextBlock控件的Visibility属性为Visible(可见)。而我们如何获取显示“*”的TextBlock控件呢?在辅助方法GetTextBlockStar()中,我们通过Window的FindResource()方法来获取Key为setHeaderStyle的资源,然后再一步步地深入去找到显示“*”的TextBlock控件(这里就不一一说明了)。关于其他的辅助代码如下所示(这些代码就不一一分析)。

复制代码
 1 public class ViewModel
 2 {
 3     private MyCommand command;
 4     public MyCommand Command
 5     {
 6         get { return command; }
 7         set { command = value; }
 8     }
 9 
10     public ViewModel()
11     {
12         command = new MyCommand();
13     }
14 }
15 
16 public class MyCommand : ICommand
17 {
18     public event Action<Object> ExecuteEvent;
19 
20     public bool CanExecute(object parameter)
21     {
22         return ExecuteEvent != null;
23     }
24 
25     public void Execute(Object parameter)
26     {
27         if (ExecuteEvent != null)
28         {
29             ExecuteEvent(parameter);
30         }
31     }
32 
33     public event EventHandler CanExecuteChanged;
34 }
35 
36 public enum OptionEnum
37 {
38     NoNeed,
39     Need
40 }
复制代码

posted on   lienhua34  阅读(2631)  评论(0编辑  收藏  举报

编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端

导航

< 2012年9月 >
26 27 28 29 30 31 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 1 2 3 4 5 6
点击右上角即可分享
微信分享提示