一、自定义依赖属性
1.1. 注册依赖属性
//申明属性
public double? SmallToMediumBodyThinkness
{
get { return (double?)GetValue(SmallToMediumBodyThinknessProperty); }
set
{
this.tbSmallToMedium.Text = value.ToString();
SetValue(SmallToMediumBodyThinknessProperty, value);
}
}
//注册属性
public static readonly DependencyProperty SmallToMediumBodyThinknessProperty
= DependencyProperty.Register("SmallToMediumBodyThinkness"
, typeof(double?)
, typeof(BodySizeRangeSettingControl)
, new PropertyMetadata(0D)
, SmallToMediumBodyThinknessOnChange);
//监听属性的变化
private static bool SmallToMediumBodyThinknessOnChange(object value)
{
return true;
}
ps:此时注册成功,可以使用自定属性
1.2. Xaml使用自定义属性
<StackPanel Orientation="Horizontal" >
<local:BodySizeRangeSettingControl
SmallToMediumBodyThinkness="1"/>
</StackPanel>
二. 监听自定义依赖属性并触发委托事件
2.1 使用DependencyPropertyDescriptor类
<Grid>
<StackPanel Orientation="Horizontal">
<TextBox x:Name="tbSmallToMedium" Margin="48,-5,0,0" />
</StackPanel>
</Grid>
private void UserControl_Loaded(object sender, RoutedEventArgs e)
//依赖属性描述器,传参自定义控件类型&属性
DependencyPropertyDescriptor dpds = DependencyPropertyDescriptor
.FromProperty(SmallToMediumBodyThinknessProperty, typeof(BodySizeRangeSettingControl));
//调用AddValueChanged方法
if (dpds != null)
{
dpds.AddValueChanged(this, SmallToMediumBodyChange);
}
}
//监听到SmallToMediumBodyThinknessProperty属性变化
private void SmallToMediumBodyChange(object sender, EventArgs e)
{
var obj = (BodySizeRangeSettingControl)sender;
//赋值给TextBox
this.tbSmallToMedium.Text = obj.SmallToMediumBodyThinkness.ToString();
}
三、自定义路由事件
3.1 使用EventManager.RegisterRoutedEvent注册
//注册
public static readonly RoutedEvent textChangedEvent =
EventManager.RegisterRoutedEvent("BodySizeTextChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(BodySizeRangeSettingControl));
public event RoutedEventHandler BodySizeTextChanged
{
add
{
AddHandler(textChangedEvent, value);
}
remove
{
RemoveHandler(textChangedEvent, value);
}
}
//触发
private void tbSmallToMedium_TextChanged(object sender, TextChangedEventArgs e)
{
string txtinput = ((TextBox)sender).Text;
if (IsNumber(txtinput))
{
this.SmallToMediumBodyThinkness = Convert.ToDouble(txtinput);
this.RaiseTextChanged();
}
else
{
this.tbSmallToMedium.Text = this.SmallToMediumBodyThinkness.ToString();
}
}
<TextBox x:Name="tbSmallToMedium" Margin="48,-5,0,0" TextChanged="tbSmallToMedium_TextChanged" />
<local:BodySizeRangeSettingControl BodySizeTextChanged="BodySizeRangeSettingControl_BodySizeTextChanged"
SmallToMediumBodyThinkness="{Binding ElementName=BodySizeTemplate_List_Box, Path=SelectedItem.BodySizeTemplate.Adultsmthreshold,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource _doubleLengthUnitConverter}}"
MediumToLargeBodyThinkness="{Binding ElementName=BodySizeTemplate_List_Box,Path=SelectedItem.BodySizeTemplate.Adultmlthreshold,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource _doubleLengthUnitConverter}}"
LargeToExtraLargeBodyThinkness="{Binding ElementName=BodySizeTemplate_List_Box,Path=SelectedItem.BodySizeTemplate.Adultlxlthreshold,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,Converter={StaticResource _doubleLengthUnitConverter}}"/>
<Button x:Name="_bodySizeRangeTextChangedbtn" Visibility="Collapsed" Command="{Binding BodySizeRangeTextChangeCmd}"/>
private void BodySizeRangeSettingControl_BodySizeTextChanged(object sender, RoutedEventArgs e)
{
if (_bodySizeRangeTextChangedbtn.Command != null)
_bodySizeRangeTextChangedbtn.Command.Execute(new object());
}
private ICommand _bodySizeRangeTextChangeCmd;
public ICommand BodySizeRangeTextChangeCmd
{
get { return _bodySizeRangeTextChangeCmd = _bodySizeRangeTextChangeCmd ?? new DelegateCommand(BodySizeRangeTextChange); }
}
private void BodySizeRangeTextChange()
{
if (SelectedBodySizeTemplateItem != null && Entity != null)
{
var oldTempdate = TotalBodySizeTemplates.Where(c => c.Id == SelectedBodySizeTemplateItem.BodySizeTemplate.Id).FirstOrDefault();
if (oldTempdate != null)
_isModified = !(SelectedBodySizeTemplateItem.BodySizeTemplate.Adultlxlthreshold == oldTempdate.Adultlxlthreshold
&& SelectedBodySizeTemplateItem.BodySizeTemplate.Adultmlthreshold == oldTempdate.Adultmlthreshold
&& SelectedBodySizeTemplateItem.BodySizeTemplate.Adultsmthreshold == oldTempdate.Adultsmthreshold
&& SelectedBodySizeTemplateItem.BodySizeTemplate.Childlxlthreshold ==
oldTempdate.Childlxlthreshold
&& SelectedBodySizeTemplateItem.BodySizeTemplate.Childmlthreshold ==
oldTempdate.Childmlthreshold
&& SelectedBodySizeTemplateItem.BodySizeTemplate.Childsmthreshold ==
oldTempdate.Childsmthreshold);
SaveCommand.RaiseCanExecuteChanged();
SaveAsBtnCommand.RaiseCanExecuteChanged();
CancelCommand.RaiseCanExecuteChanged();
}
}
四、如何给自定义依赖属性设置数据校验
4.1 实现接口IDataErrorInfo(vm)
/// <summary>
/// 后端代码
/// </summary>
public BodySizeRangeSettingControl()
{
InitializeComponent();
//Binding sBinding = new Binding("Text") { Source = this.SmallToMediumBodyThinkness };
//绑定属性,设置数据源
Binding sBinding = new Binding("SmallToMediumBodyThinkness") { Source = this };
sBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
//设置检查规则
RangeValidationRule rangeValidationRule = new RangeValidationRule();
sBinding.ValidationRules.Add(rangeValidationRule);
//开启通知
sBinding.NotifyOnValidationError = true;
this.tbSmallToMedium.SetBinding(TextBox.TextProperty,sBinding);
}
//创建Validation.Error事件
private void tbLargeToExtra_Error(object sender, ValidationErrorEventArgs e)
{
if (Validation.GetErrors(this.tbSmallToMedium).Count > 0) {
//把错误提示信息赋予text.ToolTip
this.tbSmallToMedium.ToolTip = Validation.GetErrors(this.tbSmallToMedium)[0].ErrorContent;
}
}
/// <summary>
/// 创建校验规则
/// </summary>
public class RangeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double d = 0;
if (double.TryParse(value.ToString(), out d))
{
if (d < 0) {
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "数据范围有误!!!");
}
}
<!--前段代码 设置属性Validation.Error-->
<TextBox x:Name="tbSmallToMedium" Margin="48,-5,0,0" TextChanged="tbSmallToMedium_TextChanged" Validation.Error="tbSmallToMedium_Error"/>
<!--设置错误模板-->
<Style TargetType="TextBox">
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="2"/>
</Style>
</Style.Resources>
<Style.Setters>
<Setter Property="FontFamily" Value="ArialMT"/>
<Setter Property="FontSize" Value="14"/>
<Setter Property="Foreground" Value="#2C2D2E"/>
<Setter Property="Width" Value="55"/>
<Setter Property="Height" Value="25"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Margin" Value="20,-5,0,0"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel x:Name="skpAdorner">
<Border>
<StackPanel x:Name="skpError" Orientation="Horizontal">
<AdornedElementPlaceholder x:Name="aepPanel" />
<DockPanel x:Name="dkpIcon"
Width="10"
Height="28"
Margin="-10,-5,0,0"
VerticalAlignment="Center"
Background="Transparent">
<Border x:Name="brdIcon"
Width="4"
Height="12"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="{StaticResource ErrorIcon}" />
</DockPanel>
</StackPanel>
</Border>
<DockPanel x:Name="dkpPenel"
Width="Auto"
Height="Auto"
MaxWidth="329"
Margin="-160,0,0,0"
Background="Transparent"
Visibility="Hidden">
<StackPanel>
<Border BorderThickness="0">
<Rectangle Width="329"
Height="18"
Fill="{StaticResource ValidationTop}"
SnapsToDevicePixels="True" />
</Border>
<Border Width="329"
Background="{StaticResource ValidationCenter}"
Padding="12,0,12,0"
SnapsToDevicePixels="True" BorderThickness="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border x:Name="brdPanelIcon"
Grid.Column="0"
Width="22"
Height="19"
Background="{StaticResource ErrorIconOnPanel}"
BorderBrush="{x:Null}"
BorderThickness="0"
SnapsToDevicePixels="True" />
<TextBlock x:Name="tbkPanelText"
Grid.Column="1"
Margin="5,5,0,0"
FontFamily="{StaticResource UID_XR_FontFamily}"
FontSize="{StaticResource UID_XR_Tooltip_FontSize}"
FontWeight="{StaticResource UID_XR_Regular_FontWeight}"
Foreground="#F80505"
LineHeight="18"
Text="{Binding ElementName=aepPanel,
Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}"
TextWrapping="WrapWithOverflow" />
</Grid>
</Border>
<Rectangle Width="329"
Height="18"
Fill="{StaticResource ValidationBottom}"
SnapsToDevicePixels="True" />
</StackPanel>
</DockPanel>
</StackPanel>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Mouse.MouseEnter" SourceName="dkpIcon">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="dkpPenel" Storyboard.TargetProperty="Visibility">
<ObjectAnimationUsingKeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Visible}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave" SourceName="dkpIcon">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Storyboard.TargetName="dkpPenel" Storyboard.TargetProperty="Visibility">
<ObjectAnimationUsingKeyFrames>
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value="{x:Static Visibility.Hidden}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>