我有一个自定义属性,其中会输入一个名称。如下所示:
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,一个需要有名字,第二个应该有第二个名字。在没有太多代码的情况下,为此分配此名称的最佳方法是什么?
Generic.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
答案 0 :(得分:1)
使用Control的Tag属性。使用Split()拆分全名,并将结果数组存储在Tag属性中。
EG;
<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]}" />
答案 1 :(得分:1)
我建议您对已更改的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属性。
答案 2 :(得分: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