随着.NET技术的不断发展,越来越多的开发者正在将应用程序从传统的WinForm迁移到更现代化的WPF(Windows Presentation Foundation)框架。这种转变不仅是技术栈的更新,更是UI开发理念的革新。本文将通过TextBox控件这一常用元素,深入剖析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图形渲染,界面表现力大幅提升。
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);
XML<!-- WPF中创建TextBox -->
<TextBox x:Name="txtName"
Width="200"
Height="30"
Margin="20"
Text="请输入姓名"
FontFamily="微软雅黑"
FontSize="12" />
C#TextBox txtComments = new TextBox();
txtComments.Multiline = true;
txtComments.ScrollBars = ScrollBars.Vertical;
txtComments.Size = new Size(300, 100);
XML<TextBox x:Name="txtComments"
Height="100"
Width="300"
TextWrapping="Wrap"
AcceptsReturn="True"
VerticalScrollBarVisibility="Auto"
AcceptsTab="True" />
C#// 选择文本
txtName.SelectionStart = 0;
txtName.SelectionLength = 5;
txtName.SelectedText = "Hello";
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();
}
}
}
在WPF中实现水印效果比WinForm更加简单和灵活。
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();
}
}
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;
}
}
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));
}
}
}
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);
}
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();
}
}
}
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>
特性 | WinForm TextBox | WPF 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 许可协议。转载请注明出处!