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

WPF自定义控件,拆分字符串的最佳方式

我建议您对更改的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