WPF自定义控件,拆分字符串的最佳方式
本文关键字:最佳 方式 字符串 拆分 自定义控件 WPF | 更新日期: 2023-09-27 18:24:31
我有一个自定义属性,它将输入一个名称。如下所示:
UserProfile.cs
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace Controls
{
public class UserProfile : Control
{
#region Fields
public static readonly DependencyProperty PhotoSizeProperty;
public static readonly DependencyProperty UserNameProperty;
#endregion
static UserProfile()
{
// Initialize as lookless control
DefaultStyleKeyProperty.OverrideMetadata(typeof(UserProfile),
new FrameworkPropertyMetadata(typeof(UserProfile)));
// Initialize dependency properties
PhotoSizeProperty = DependencyProperty.Register("PhotoSize", typeof(Double), typeof(UserProfile), null);
UserNameProperty = DependencyProperty.Register("UserName", typeof(String), typeof(UserProfile), null);
}
#region Custom Control Properties
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Size of the user image"), Category("Common Properties")]
public Double PhotoSize
{
get { return (Double)GetValue(PhotoSizeProperty); }
set { SetValue(PhotoSizeProperty, value); }
}
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Username, split first and last names"), Category("Common Properties")]
public String UserName
{
get { return (String)GetValue(UserNameProperty); }
set { SetValue(UserNameProperty, value); }
}
#endregion
}
public class CalculateBorder : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Double parm = System.Convert.ToDouble(parameter);
return new Thickness((double)value / parm);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class CalculateFont : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Double parm = System.Convert.ToDouble(parameter);
return (double)value / parm;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
这是我控件的通用样式。有两个TextBlock,一个需要有第一个名称,另一个应该有第二个名称。在没有太多过度代码的情况下,拆分此名称的最佳方法是什么?
通用.xaml
<Style TargetType="{x:Type local:UserProfile}">
<Setter Property="Width" Value="150" />
<Setter Property="Foreground" Value="White" />
<Setter Property="FontSize" Value="{Binding Converter={StaticResource CalculateFont},
ConverterParameter=35,
RelativeSource={RelativeSource AncestorType={x:Type local:UserProfile}},
Path=(local:UserProfile.PhotoSize)}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:UserProfile}">
<Grid x:Name="circleGrid" Width="{Binding PhotoSize}">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Path=ActualWidth, ElementName=circleGrid}" />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Border x:Name="circleBorder"
Grid.Row="0"
CornerRadius="{Binding Path=ActualWidth, ElementName=circleGrid}"
Width="{Binding Path=ActualWidth, ElementName=circleGrid}"
Height="{Binding Path=ActualWidth, ElementName=circleGrid}"
BorderBrush="White"
BorderThickness="{Binding Converter={StaticResource CalculateBorder},
ConverterParameter=35,
RelativeSource={RelativeSource AncestorType={x:Type local:UserProfile}},
Path=(local:UserProfile.PhotoSize)}">
<Border.Background>
<ImageBrush ImageSource="D:'Users'Martyn Ball'Pictures'11061728_10153409797331063_2946862347621203654_o.jpg" Stretch="UniformToFill" />
</Border.Background>
</Border>
<WrapPanel Grid.Row="1" HorizontalAlignment="Center">
<TextBlock x:Name="firstName"
FontWeight="Bold"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding UserName}" />
<TextBlock Text=" "/>
<TextBlock x:Name="lastName"
FontWeight="Normal"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding UserName}" />
</WrapPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
编辑:
为什么我不能这样创建这个属性,SplitUsername
?
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Username, split first and last names"), Category("Common Properties")]
public String UserName
{
get { return (String)GetValue(UserNameProperty); }
set { SetValue(UserNameProperty, value); }
}
public string[] SplitUsername
{
get { return GetValue(UserNameProperty).ToString().Split(' '); }
}
#endregion
我正试图以我的风格绑定到它,但我收到一个错误,说它无法识别或访问。
Text="{TemplateBinding SplitUsername[0]}"
编辑2
好的,这是一个属性,它应该构成一个包含[0] => "Firstname, [1] => "Secondname"
的数组。
public string[] SplitUsername
{
get { return GetValue(UserNameProperty).ToString().Split(' '); }
}
这是我的绑定,它不起作用:
<TextBlock x:Name="firstName"
FontWeight="Bold"
Foreground="{TemplateBinding Foreground}"
Text="{Binding SplitUsername[0]}" />
<TextBlock Text=" "/>
<TextBlock x:Name="lastName"
FontWeight="Normal"
Foreground="{TemplateBinding Foreground}"
Text="{Binding SplitUsername[1]}" />
我似乎没有犯任何错误!
编辑3
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Username, split first and last names"), Category("Common Properties")]
public String UserName
{
get { return (String)GetValue(UserNameProperty); }
set { SetValue(UserNameProperty, value); }
}
public static readonly DependencyProperty UserNameProperty = DependencyProperty.Register("UserName", typeof(String), typeof(UserProfile),
new FrameworkPropertyMetadata(
false,
new PropertyChangedCallback(UserNamePropertyChanged)));
private static void UserNamePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
UserProfile profile = sender as UserProfile;
TextBlock firstName = profile.GetTemplateChild("firstName") as TextBlock;
TextBlock lastName = profile.GetTemplateChild("lastName") as TextBlock;
if (firstName != null && lastName != null)
{
if (args.NewValue == null)
{
firstName.Text = string.Empty;
lastName.Text = string.Empty;
}
else
{
string newValue = args.NewValue.ToString();
if (string.IsNullOrWhiteSpace(newValue))
{
firstName.Text = string.Empty;
lastName.Text = string.Empty;
}
else
{
string[] splittedValues = newValue.Split(' ');
if (splittedValues.Length == 1)
{
firstName.Text = newValue;
lastName.Text = string.Empty;
}
else if (splittedValues.Length == 2)
{
firstName.Text = splittedValues[0];
lastName.Text = splittedValues[1];
}
else if (splittedValues.Length > 2)
{
firstName.Text = splittedValues[0];
lastName.Text = newValue.Substring(splittedValues[0].Length + 1);
}
}
}
}
}
#endregion
我建议您对更改的UserName属性做出反应,并在代码中设置文本框,而不是从控制模板进行绑定。像这样:
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Username, split first and last names"), Category("Common Properties")]
public String UserName
{
get { return (String)GetValue(UserNameProperty); }
set { SetValue(UserNameProperty, value); }
}
public static readonly DependencyProperty UserNameProperty = DependencyProperty.Register("UserName", typeof(String), typeof(UserProfile), new PropertyMetadata("Firstname Lastname",UserNamePropertyChanged));
private static void UserNamePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
UserProfile profile = sender as UserProfile;
profile.RefreshFirstAndLastName();
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.RefreshFirstAndLastName();
}
private void RefreshFirstAndLastName()
{
TextBlock firstName = this.GetTemplateChild("firstName") as TextBlock;
TextBlock lastName = this.GetTemplateChild("lastName") as TextBlock;
if (firstName != null && lastName != null)
{
if (string.IsNullOrWhiteSpace(this.UserName))
{
firstName.Text = string.Empty;
lastName.Text = string.Empty;
}
else
{
string[] splittedValues = this.UserName.Split(' ');
if (splittedValues.Length == 1)
{
firstName.Text = this.UserName;
lastName.Text = string.Empty;
}
else if (splittedValues.Length == 2)
{
firstName.Text = splittedValues[0];
lastName.Text = splittedValues[1];
}
else if (splittedValues.Length > 2)
{
firstName.Text = splittedValues[0];
lastName.Text = this.UserName.Substring(splittedValues[0].Length + 1);
}
}
}
}
我知道在使用WPF时这看起来很奇怪。但请记住,您在控制范围内。您在视图中,这并不违反MVVM。
更新1:
我发现你的代码有问题。在MainWindow.xaml中更改UserProfile的定义,如下所示:
<Controls:UserProfile PhotoSize="150" UserName="{Binding Text, ElementName=Username}" />
您必须绑定到TextBox的Text属性。
使用控件的Tag属性。使用Split()拆分全名,并将结果数组存储在Tag属性中。
例如;
<Button x:Name="BtnName" Content="Anjum Khan" />
<TextBlock Background="#FFEECF0A" Text="{Binding Tag[0], ElementName=BtnName}" />
<TextBlock Background="#FF5DF1AE" Text="{Binding Tag[1], ElementName=BtnName}" />
BtnName.Tag = BtnName.Content.ToString().Split(new char[] { ' ' });
TextBlocks将分别显示名字和姓氏。你可以建立在这个概念的基础上。
你的模板制作也会起作用:
<TextBlock x:Name="firstName"
FontWeight="Bold"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Tag[0]}" />
设法使其工作,这是Generic.xaml中的绑定
<TextBlock x:Name="firstName"
FontWeight="Bold"
Foreground="{TemplateBinding Foreground}"
Text="{Binding SplitUsername[0], RelativeSource={RelativeSource TemplatedParent}}" />
<TextBlock Text=" "/>
<TextBlock x:Name="lastName"
FontWeight="Normal"
Foreground="{TemplateBinding Foreground}"
Text="{Binding SplitUsername[1], RelativeSource={RelativeSource TemplatedParent}}" />
这是UserProfile.cs中的代码
#region Custom Control Properties
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Size of the user image"), Category("Common Properties")]
public Double PhotoSize
{
get { return (Double)GetValue(PhotoSizeProperty); }
set { SetValue(PhotoSizeProperty, value); }
}
/// <summary>
/// Gets or sets the Label which is displayed next to the field
/// </summary>
[Description("Username, split first and last names"), Category("Common Properties")]
public String UserName
{
get { return (String)GetValue(UserNameProperty); }
set { SetValue(UserNameProperty, value); }
}
public string[] SplitUsername
{
get { return GetValue(UserNameProperty).ToString().Split(' '); }
}
#endregion