WPF之自定义控件及添加依赖属性
一、问题描述
我们要自定义一个Button,不使用任何原生Button的样式效果,所以,直接继承自UserControl而不是Button,但是又要具备Button的功能,所以,内部添加Button控件并重新设置样式模板,UserControl中没有Command和CommandParameter,所以,我们添加相应的依赖属性,并将其绑定到内部Button控件的Command和CommadParameter属性上,这样就能在外部像使用原生Button一样使用自定义Button设置Command和CommandParameter了。
不过,现实还是很残酷的,当我们将自定义依赖属性绑定到内部Button上时,我们设置了自定义控件的this.DataContext = this;而当我们使用自定义控件时,要绑定的命令又存在于另一个外部的DataContext,一个控件只能有一个DataContext,于是矛盾产生了。
<UserControl x:Class="CHC.AibirdGStationPro.Control.AppButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CHC.AibirdGStationPro.Control"
mc:Ignorable="d"
Name="appButton" Height="auto" Width="auto" BorderThickness="0" Background="Transparent">
<!--定义控件-->
<Grid>
<Button x:Name="myButton" Height="102" Width="102" Style="{StaticResource AppButtonStyle}"
MouseLeftButtonDown="Button_MouseLeftButtonDown"
MouseLeftButtonUp="Button_MouseLeftButtonUp" Command="{Binding Command }" CommandParameter="{Binding CommandParameter}"/>
</Grid>
</UserControl>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace CHC.AibirdGStationPro.Control
{
/// <summary>
/// AppButton.xaml 的交互逻辑
/// </summary>
public partial class AppButton : UserControl
{
public AppButton()
{
InitializeComponent();
this.DataContext = this;
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(AppButton), new PropertyMetadata(null));
public string CommandParameter
{
get { return (string)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
// Using a DependencyProperty as the backing store for CommandParameterProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(AppButton), new PropertyMetadata(""));
}
}
二、解决方案
方案一、在外部绑定Command时,不使用DataContext进行绑定,而使用ElementName,也就是先利用一个控件将要绑定的Command获取到,然后再间接绑定该控件的Command属性,以此完成对外部命令的绑定,但比较麻烦。
方案二、使用RelativeSource进行内部绑定,参考wpf 自定义控件中ElementName和DataContext之间的冲突
由于内部绑定时使用了this.DataContext = this,导致外部绑定不能使用外部DataContext,因此,如果内部绑定可以不使用DataContext,问题就能得到解决,而RelativeSource能做到这一点。
<!--定义控件-->
<Grid>
<Button x:Name="myButton" Height="102" Width="102" Style="{StaticResource AppButtonStyle}"
MouseLeftButtonDown="Button_MouseLeftButtonDown"
MouseLeftButtonUp="Button_MouseLeftButtonUp"
Command="{Binding Command ,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}"
CommandParameter="{Binding CommandParameter ,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type UserControl}},Mode=TwoWay}"/>
</Grid>
<control:AppButton x:Name="btnRoutePlanning" NormalImage="{StaticResource RoutePlanning}" FocusedImage="{StaticResource RoutePlanning_focused}"
Command="{Binding Path=StartUpAppCommand}" CommandParameter="btnRoutePlanning"/>
小结:
1、要实现数据绑定,关键是要设置好数据源,保证能够找到对应的数据,默认会从DataContext中查找,所以,DataContext一般都要设置,绑定自身属性时要设为this.DataContext = this。
2、RelativeSource通过根据控件类型查找相应的控件并绑定其属性,在自定义控件时很好解决了使用DataContext带来的问题。
3、自定义控件如果有自定义依赖属性,那应当将DataContext留给外部绑定,而不要在内部使用this.DataContext = this;
上一篇: 修改elementUI组件库的单元格高度
下一篇: WPF自定义依赖属性