【WPF专题 】如何自定义控件

一、自定义依赖属性

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>
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xq0512

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值