编辑
2025-10-09
C#
00

目录

为什么从WinForm迁移到WPF?
界面设计的革命性变化
数据绑定的强大优势
更现代的图形渲染
TextBox控件:从WinForm到WPF的具体对比
基础创建与属性设置
WinForm中的TextBox
WPF中的TextBox
多行文本支持对比
WinForm实现多行文本
WPF实现多行文本
文本选择与操作
WinForm中的文本选择
WPF中的文本选择
高级TextBox应用实例
示例1:带有水印效果的TextBox
WPF水印实现
WinForm水印实现对比
示例2:带验证功能的TextBox
WPF验证实现
WinForm验证实现对比
示例3:MVVM模式下的TextBox数据绑定
示例4:自定义样式的TextBox
WPF TextBox与WinForm TextBox的全面对比
结语

随着.NET技术的不断发展,越来越多的开发者正在将应用程序从传统的WinForm迁移到更现代化的WPF(Windows Presentation Foundation)框架。这种转变不仅是技术栈的更新,更是UI开发理念的革新。本文将通过TextBox控件这一常用元素,深入剖析WinForm到WPF的转型过程,为正在或即将进行技术迁移的开发者提供实用指南。

为什么从WinForm迁移到WPF?

界面设计的革命性变化

WPF采用XAML(可扩展应用标记语言)来描述用户界面,这种声明式的UI设计方式为开发者提供了前所未有的灵活性:

C#
<!-- WPF中使用XAML定义UI --> <Grid> <TextBox x:Name="txtInput" Width="200" Height="30" /> </Grid>

相比之下,WinForm的界面设计主要依赖于设计器生成的代码:

C#
// WinForm中通过代码定义UI this.txtInput = new System.Windows.Forms.TextBox(); this.txtInput.Location = new System.Drawing.Point(12, 12); this.txtInput.Size = new System.Drawing.Size(200, 20); this.Controls.Add(this.txtInput);

数据绑定的强大优势

WPF的数据绑定机制远超WinForm,可以轻松实现UI与数据的自动同步:

C#
<!-- XAML中的数据绑定 --> <TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />

更现代的图形渲染

WPF基于DirectX,提供硬件加速的2D和3D图形渲染,界面表现力大幅提升。

TextBox控件:从WinForm到WPF的具体对比

基础创建与属性设置

WinForm中的TextBox

C#
// WinForm中创建TextBox TextBox txtName = new TextBox(); txtName.Location = new Point(20, 20); txtName.Size = new Size(200, 20); txtName.Text = "请输入姓名"; txtName.Font = new Font("微软雅黑", 10F); this.Controls.Add(txtName);

WPF中的TextBox

XML
<!-- WPF中创建TextBox --> <TextBox x:Name="txtName" Width="200" Height="30" Margin="20" Text="请输入姓名" FontFamily="微软雅黑" FontSize="12" />

image.png

多行文本支持对比

WinForm实现多行文本

C#
TextBox txtComments = new TextBox(); txtComments.Multiline = true; txtComments.ScrollBars = ScrollBars.Vertical; txtComments.Size = new Size(300, 100);

WPF实现多行文本

XML
<TextBox x:Name="txtComments" Height="100" Width="300" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" AcceptsTab="True" />

image.png

文本选择与操作

WinForm中的文本选择

C#
// 选择文本 txtName.SelectionStart = 0; txtName.SelectionLength = 5; txtName.SelectedText = "Hello";

WPF中的文本选择

C#
<Window x:Class="AppTextBox.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:AppTextBox" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded"> <Grid> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="文本选择示例" FontSize="18" FontWeight="Bold" Margin="0,0,0,10"/> <TextBox x:Name="txtName" Grid.Row="1" Height="30" Margin="0,0,0,10" FontSize="14" VerticalContentAlignment="Center"/> <WrapPanel Grid.Row="2" Margin="0,10,0,0"> <Button x:Name="btnSelectFirst5" Content="选择前5个字符" Margin="5" Padding="5" Click="btnSelectFirst5_Click"/> <Button x:Name="btnReplaceFirst5" Content="替换前5个字符为Hello" Margin="5" Padding="5" Click="btnReplaceFirst5_Click"/> <Button x:Name="btnSelectLast5" Content="选择后5个字符" Margin="5" Padding="5" Click="btnSelectLast5_Click"/> <Button x:Name="btnReplaceLast5" Content="替换后5个字符为World" Margin="5" Padding="5" Click="btnReplaceLast5_Click"/> <Button x:Name="btnGetSelection" Content="获取选中内容" Margin="5" Padding="5" Click="btnGetSelection_Click"/> <Button x:Name="btnClearSelection" Content="清除选择" Margin="5" Padding="5" Click="btnClearSelection_Click"/> <Button x:Name="btnSelectAll" Content="全选文本" Margin="5" Padding="5" Click="btnSelectAll_Click"/> <Button x:Name="btnResetText" Content="重置文本" Margin="5" Padding="5" Click="btnResetText_Click"/> </WrapPanel> </Grid> </Grid> </Window>
C#
using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Xml.Linq; namespace AppTextBox { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { // 初始化文本框内容 txtName.Text = "这是一段可以选择的示例文本"; } private void btnSelectFirst5_Click(object sender, RoutedEventArgs e) { // 选择文本的第一种方式 txtName.SelectionStart = 0; txtName.SelectionLength = 5; txtName.Focus(); // 使文本框获得焦点以显示选择 } private void btnReplaceFirst5_Click(object sender, RoutedEventArgs e) { // 选择并替换文本的第一种方式 txtName.SelectionStart = 0; txtName.SelectionLength = 5; txtName.SelectedText = "Hello"; txtName.Focus(); } private void btnSelectLast5_Click(object sender, RoutedEventArgs e) { // 选择文本的第二种方式 int startIndex = Math.Max(0, txtName.Text.Length - 5); txtName.Select(startIndex, 5); txtName.Focus(); } private void btnReplaceLast5_Click(object sender, RoutedEventArgs e) { // 选择并替换文本的第二种方式 int startIndex = Math.Max(0, txtName.Text.Length - 5); txtName.Select(startIndex, 5); txtName.SelectedText = "World"; txtName.Focus(); } private void btnGetSelection_Click(object sender, RoutedEventArgs e) { // 获取当前选择的文本 string selectedText = txtName.SelectedText; MessageBox.Show($"当前选择的文本是: {selectedText}", "选择信息"); } private void btnClearSelection_Click(object sender, RoutedEventArgs e) { // 清除选择 txtName.SelectionLength = 0; txtName.Focus(); } private void btnSelectAll_Click(object sender, RoutedEventArgs e) { // 全选文本 txtName.SelectAll(); txtName.Focus(); } private void btnResetText_Click(object sender, RoutedEventArgs e) { // 重置文本框内容 txtName.Text = "这是一段可以选择的示例文本"; txtName.Focus(); } } }

image.png

高级TextBox应用实例

示例1:带有水印效果的TextBox

在WPF中实现水印效果比WinForm更加简单和灵活。

WPF水印实现

XML
<Window x:Class="AppTextBox.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:AppTextBox" mc:Ignorable="d" Title="Window1" Height="450" Width="800"> <Window.Resources> <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" /> </Window.Resources> <Grid> <!-- 使用Style实现水印效果 --> <TextBox x:Name="txtSearch" Width="200" Height="30"> <TextBox.Style> <Style TargetType="TextBox"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TextBox"> <Grid> <TextBox x:Name="PART_TextBox" Text="{Binding Path=Text, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}" Background="Transparent" Panel.ZIndex="2" /> <TextBlock Text="请输入搜索内容..." Foreground="Gray" Margin="5,3,0,0" Visibility="{Binding Path=Text.IsEmpty, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </TextBox.Style> </TextBox> </Grid> </Window>
C#
// 在后台代码中需添加转换器 public class BooleanToVisibilityConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { bool isEmpty = (bool)value; return isEmpty ? Visibility.Visible : Visibility.Collapsed; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }

image.png

WinForm水印实现对比

C#
// WinForm中实现水印需要自定义控件或者监听事件 private void txtSearch_Enter(object sender, EventArgs e) { if (txtSearch.Text == "请输入搜索内容...") { txtSearch.Text = ""; txtSearch.ForeColor = Color.Black; } } private void txtSearch_Leave(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(txtSearch.Text)) { txtSearch.Text = "请输入搜索内容..."; txtSearch.ForeColor = Color.Gray; } }

示例2:带验证功能的TextBox

WPF的数据绑定和验证机制使得实现输入验证变得简单。

WPF验证实现

XML
<Window x:Class="AppTextBox.Window2" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:AppTextBox" mc:Ignorable="d" Title="Window2" Height="450" Width="800"> <Window.DataContext> <local:RuleModel /> </Window.DataContext> <Grid Margin="20"> <StackPanel> <TextBlock Text="请输入电子邮箱:" Margin="0,0,0,5"/> <TextBox x:Name="txtEmail" Width="250" HorizontalAlignment="Left"> <TextBox.Text> <Binding Path="Email" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <local:EmailValidationRule /> </Binding.ValidationRules> </Binding> </TextBox.Text> <TextBox.Style> <Style TargetType="TextBox"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" /> <Setter Property="Border.BorderBrush" Value="Red" /> </Trigger> </Style.Triggers> </Style> </TextBox.Style> </TextBox> <Button Content="提交" Width="100" HorizontalAlignment="Left" Margin="0,20,0,0" Click="SubmitButton_Click"/> <TextBlock x:Name="resultTextBlock" Margin="0,10,0,0"/> </StackPanel> </Grid> </Window>
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace AppTextBox { /// <summary> /// Interaction logic for Window2.xaml /// </summary> public partial class Window2 : Window { public Window2() { InitializeComponent(); } private void SubmitButton_Click(object sender, RoutedEventArgs e) { if (Validation.GetHasError(txtEmail)) { resultTextBlock.Text = "请修正输入错误后再提交"; resultTextBlock.Foreground = System.Windows.Media.Brushes.Red; } else { resultTextBlock.Text = "邮箱验证成功!"; resultTextBlock.Foreground = System.Windows.Media.Brushes.Green; } } } }
C#
using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Controls; namespace AppTextBox { // 自定义邮箱验证规则 public class EmailValidationRule : ValidationRule { public override ValidationResult Validate(object value, CultureInfo cultureInfo) { string email = value as string; if (string.IsNullOrWhiteSpace(email)) return new ValidationResult(false, "邮箱不能为空"); // 简单的邮箱格式验证 if (!Regex.IsMatch(email, @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$")) return new ValidationResult(false, "邮箱格式不正确"); return ValidationResult.ValidResult; } } }
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; namespace AppTextBox { public class RuleModel : INotifyPropertyChanged { private string _email; public string Email { get { return _email; } set { if (_email != value) { _email = value; OnPropertyChanged(); } } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }

image.png

WinForm验证实现对比

C#
private bool ValidateEmail(string email) { if (string.IsNullOrWhiteSpace(email)) { errorProvider1.SetError(txtEmail, "邮箱不能为空"); return false; } if (!Regex.IsMatch(email, @"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$")) { errorProvider1.SetError(txtEmail, "邮箱格式不正确"); return false; } errorProvider1.SetError(txtEmail, ""); return true; } private void txtEmail_TextChanged(object sender, EventArgs e) { ValidateEmail(txtEmail.Text); }

示例3:MVVM模式下的TextBox数据绑定

WPF的MVVM架构让数据绑定变得更加清晰和高效。

XML
<Window x:Class="AppTextBox.Window3" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:AppTextBox" mc:Ignorable="d" Title="Window3" Height="450" Width="800"> <Window.Resources> <Style TargetType="TextBlock"> <Setter Property="Margin" Value="5" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> <Style TargetType="TextBox"> <Setter Property="Margin" Value="5" /> <Setter Property="Padding" Value="5" /> <Setter Property="Height" Value="30" /> </Style> <Style TargetType="Button"> <Setter Property="Margin" Value="5" /> <Setter Property="Padding" Value="15,5" /> <Setter Property="Height" Value="35" /> </Style> </Window.Resources> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <!-- 标题 --> <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="个人信息录入" FontSize="20" FontWeight="Bold" Margin="5,5,5,20"/> <!-- 姓名输入 --> <TextBlock Grid.Row="1" Grid.Column="0" Text="姓名:"/> <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding PersonName, UpdateSourceTrigger=PropertyChanged}"/> <!-- 年龄输入 --> <TextBlock Grid.Row="2" Grid.Column="0" Text="年龄:"/> <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding PersonAge, UpdateSourceTrigger=PropertyChanged}"/> <!-- 输入数据展示 --> <Border Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="LightGray" BorderThickness="1" Margin="5,15" Padding="10"> <StackPanel> <TextBlock Text="预览信息:" FontWeight="Bold"/> <TextBlock> <Run Text="姓名: "/> <Run Text="{Binding PersonName, Mode=OneWay}"/> </TextBlock> <TextBlock> <Run Text="年龄: "/> <Run Text="{Binding PersonAge, Mode=OneWay}"/> <Run Text="岁"/> </TextBlock> </StackPanel> </Border> <!-- 保存按钮 --> <Button Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Content="保存" HorizontalAlignment="Right" Command="{Binding SaveCommand}"/> <!-- 状态展示区 --> <TextBlock Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding StatusMessage}" VerticalAlignment="Bottom" Foreground="Green"/> </Grid> </Window>
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace AppTextBox { public class Person { public string Name { get; set; } public int Age { get; set; } public override string ToString() { return $"{Name}, {Age}岁"; } } }
C#
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; using System.Windows; namespace AppTextBox { public class PersonViewModel : INotifyPropertyChanged { private Person _person; private string _personName; public string PersonName { get { return _personName; } set { if (_personName != value) { _personName = value; OnPropertyChanged(nameof(PersonName)); // 当值改变时,可能影响保存命令的可用性 CommandManager.InvalidateRequerySuggested(); } } } private int _personAge; public int PersonAge { get { return _personAge; } set { if (_personAge != value) { _personAge = value; OnPropertyChanged(nameof(PersonAge)); // 当值改变时,可能影响保存命令的可用性 CommandManager.InvalidateRequerySuggested(); } } } private string _statusMessage; public string StatusMessage { get { return _statusMessage; } set { if (_statusMessage != value) { _statusMessage = value; OnPropertyChanged(nameof(StatusMessage)); } } } public ICommand SaveCommand { get; private set; } public PersonViewModel() { _person = new Person(); SaveCommand = new RelayCommand(SavePerson, CanSavePerson); } private bool CanSavePerson() { // 验证输入的有效性 if (string.IsNullOrWhiteSpace(PersonName)) return false; // 尝试确保年龄是有效的正整数 return PersonAge > 0; } private void SavePerson() { try { // 将数据从ViewModel传递到Model _person.Name = PersonName; _person.Age = PersonAge; // 这里可以添加持久化逻辑,例如保存到数据库 // 显示保存结果 MessageBox.Show($"保存成功:{_person}", "信息", MessageBoxButton.OK, MessageBoxImage.Information); // 更新状态消息 StatusMessage = $"已于 {DateTime.Now:yyyy-MM-dd HH:mm:ss} 保存信息"; } catch (Exception ex) { MessageBox.Show($"保存失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error); StatusMessage = "保存失败,请检查输入"; } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace AppTextBox { public class RelayCommand : ICommand { private readonly Action _execute; private readonly Func<bool> _canExecute; public RelayCommand(Action execute, Func<bool> canExecute = null) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(); } public void Execute(object parameter) { _execute(); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } } }
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace AppTextBox { /// <summary> /// Interaction logic for Window3.xaml /// </summary> public partial class Window3 : Window { public Window3() { InitializeComponent(); DataContext = new PersonViewModel(); } } }

image.png

示例4:自定义样式的TextBox

WPF提供了强大的样式和模板功能,可以轻松自定义控件外观。

XML
<Window x:Class="AppTextBox.Window4" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:AppTextBox" mc:Ignorable="d" Title="Window4" Height="450" Width="800"> <Window.Resources> <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> <!-- 先定义软阴影效果资源 --> <DropShadowEffect x:Key="SoftShadowEffect" ShadowDepth="1" Direction="270" Color="#20000000" BlurRadius="5" Opacity="0.3" /> <!-- 自定义TextBox样式 --> <Style x:Key="ModernTextBox" TargetType="TextBox"> <Setter Property="Height" Value="40" /> <Setter Property="Padding" Value="10,0" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="Background" Value="Transparent" /> <Setter Property="Foreground" Value="#333333" /> <Setter Property="FontSize" Value="14" /> <Setter Property="FontFamily" Value="Segoe UI" /> <Setter Property="BorderThickness" Value="0" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TextBox"> <Grid> <!-- 主边框 --> <Border x:Name="MainBorder" Background="#F7F9FC" CornerRadius="8" BorderThickness="1" BorderBrush="#E0E6ED" Effect="{StaticResource SoftShadowEffect}"> <Grid> <!-- 输入文本区域 --> <ScrollViewer x:Name="PART_ContentHost" Margin="10,2" VerticalAlignment="Center" Foreground="{TemplateBinding Foreground}" /> <!-- 占位提示文本 --> <TextBlock Text="{TemplateBinding Tag}" Foreground="#A0AEC0" Margin="12,0,0,0" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" VerticalAlignment="Center" Visibility="{Binding Text.IsEmpty, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BooleanToVisibilityConverter}}" /> </Grid> </Border> </Grid> <ControlTemplate.Triggers> <!-- 获取焦点时的视觉效果 --> <Trigger Property="IsFocused" Value="True"> <Setter TargetName="MainBorder" Property="BorderBrush" Value="#3498db" /> <Setter TargetName="MainBorder" Property="BorderThickness" Value="2" /> <Setter TargetName="MainBorder" Property="Background" Value="#FFFFFF" /> </Trigger> <!-- 鼠标悬停效果 --> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="MainBorder" Property="BorderBrush" Value="#CBD5E0" /> <Setter TargetName="MainBorder" Property="Background" Value="#FFFFFF" /> </Trigger> <!-- 禁用状态效果 --> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="MainBorder" Property="Background" Value="#F0F0F0" /> <Setter TargetName="MainBorder" Property="BorderBrush" Value="#E0E0E0" /> <Setter Property="Foreground" Value="#AAAAAA" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid> <StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Margin="20"> <TextBlock Text="登录信息" FontSize="24" FontWeight="SemiBold" Margin="0,0,0,30" Foreground="#2D3748"/> <!-- 使用自定义样式的TextBox --> <TextBox Style="{StaticResource ModernTextBox}" Tag="请输入用户名" Width="300" Margin="0,0,0,15" /> <TextBox Style="{StaticResource ModernTextBox}" Tag="请输入密码" Width="300" Margin="0,0,0,20" /> <Button Content="登 录" Height="40" Width="300" Background="#3498db" Foreground="White" BorderThickness="0" FontSize="14" FontWeight="SemiBold"> <Button.Resources> <Style TargetType="Border"> <Setter Property="CornerRadius" Value="8"/> </Style> </Button.Resources> </Button> </StackPanel> </Grid> </Window>

image.png

WPF TextBox与WinForm TextBox的全面对比

特性WinForm TextBoxWPF TextBox
基本布局通过Location、Size属性进行绝对定位使用Grid、StackPanel等布局容器进行相对定位
样式定制有限,主要通过Properties窗口设置极其灵活,支持通过XAML样式和模板完全自定义外观
数据绑定基础绑定能力,大多数情况需要手动同步强大的双向绑定,支持转换器、验证规则等高级特性
事件处理使用传统的事件处理模式支持命令模式(Command),事件可以在XAML中直接绑定
多行文本通过Multiline属性支持通过TextWrapping和AcceptsReturn属性支持,且布局更灵活
输入验证通常需要使用ErrorProvider或自定义逻辑内置的验证机制,可通过IDataErrorInfo接口和ValidationRule轻松实现
控件模板不支持模板化完全支持控件模板,可以重新定义控件外观而保留行为
水印效果需要自行处理Enter/Leave事件可通过样式和绑定轻松实现
架构支持不适合MVVM模式天然支持MVVM架构模式

结语

从WinForm到WPF的转型不仅是技术框架的变更,更是UI开发理念的升级。通过TextBox这一基础控件的对比,我们可以看到WPF在界面设计、数据绑定和用户体验方面带来的巨大进步。无论是开发新应用还是迁移现有项目,掌握WPF的特性和开发模式都将帮助开发者构建更现代、更易维护的Windows桌面应用程序。

希望本文的详细示例和实践指导能够帮助你顺利完成从WinForm到WPF的技术转型,充分发挥WPF框架的强大能力,打造出更优秀的用户体验。

欢迎在评论区分享你在迁移过程中的心得体会和遇到的问题,我们一起探讨解决方案,共同进步!


#WPF开发 #C#编程 #WinForm迁移 #TextBox控件 #MVVM架构 #数据绑定 #界面设计 #.NET开发 #桌面应用开发

本文作者:技术老小子

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!