WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示
1、新建了一个用户控件,里面画了一个实心圆,以及一个文本控件的组合,当作我要实验使用的用户控件(TestUserControl)。
2、在主窗体里面进行引用,可以看到引用以后,会在工具箱上显示新增的用户控件
3、为了测试方便,我直接在先前的Lo'gin页面直接进行添加该用户控件,效果如下。
4、运行效果如下。由于该用户控件没有设置过任何属性,所以现在是没有任何事件、也没有办法更改默认文本等信息的。
5、接下来进行设置属性,用于可以直接更改TextName属性的Text值。设置一个MyText属性,用于可以获取和设置用户控件内的TextBlock的Text值。
6、然后可以在Xaml里面直接通过更改MyText的属性,来更新显示的Text值。如下图所示,设置MyText属性后,设置值为666,同步更新成666了。
7、但是如果想要实现双向绑定,其实还不太够,直接Binding会提示错误XDG0062:Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'. 如图。
8、以上问题可以通过自定义依赖属性来解决。在用户控件的设计器交互代码类(TestUserControl)里面,新增以下代码,功能如图所示。
9、现在在xaml里面,设置Binding就不会提示错误了。
10、并且也可以直接设置值,效果同上面设置属性以后直接写值效果一样。
11、在Login页面的ViewModel里面,新增属性提供给双向绑定使用。
12、设置MyText进行Binding到刚刚写的ViewModel的属性TestText上。
13、运行效果如下图所示,说明双向绑定成功了。
14、接下来对用户控件设置单击事件的双向绑定。先设置Command有关的依赖属性。
15、一些有关方法和其他的属性设置,就不做过多介绍了,看图说话。
16、然后是关键的一步,需要设置单机事件与Command属性关联。当然,Command是命名得来的,所以也可以使用其他的命名,也都是OK的,不用在意这些细节,只是默认情况下,单击都喜欢用Command。如果自带的控件也没有双击、右键等双向绑定,也可以通过设置依赖属性来实现。
17、在ViewModel里面定义单击事件以及有关执行的方法。方法为一个弹出消息框。
18、使用Command进行绑定事件名称。
19、运行,并单击实心圆的效果,并弹出提示框,说明单击事件通过依赖属性进行设置成功。
20、接下来测试一下带参数的事件。在viewmodel里面,对刚才无参数的事件,改为带一个string参数的。
21、在xaml里面,传入一个字符串参数,就叫 Hello world
22、运行,并点击实心圆后效果如图所示,说明带参数也是OK的。
23、其他套路如出一辙,大佬们可以自行尝试,例如通过设置背景依赖属性,变更实心圆的背景,而不是整个用户控件(正方形)的背景。这部分本来也要写一个给大佬们压压惊,由于时间关系,大佬们可以自己尝试玩一下。
提示:背景 Background是系统自带的,所以需要new。通过属性依赖进行更改圆的颜色,而不是背景色。有兴趣的大佬或者需要学习的,可以动手玩一玩,加深印象。
以上就是该文章的全部内容,如果对你有帮助,欢迎大佬点赞、留言与转发。如需转发,请注明我的博客出处:
https://www.cnblogs.com/weskynet/p/16290422.html
以下是有关最终的源代码:
TestUserControl:
<Grid> <Viewbox Stretch="Fill"> <Canvas Width="200" Height="200"> <Ellipse Name="rect3" Width="200" Height="200" Stroke="Orange" StrokeThickness="100" > </Ellipse> </Canvas> </Viewbox> <TextBlock x:Name="TextName" Text="123" VerticalAlignment="Center" HorizontalAlignment="Center"></TextBlock> </Grid>
public partial class TestUserControl : UserControl { public TestUserControl() { InitializeComponent(); } public static readonly DependencyProperty MyTextProperty = DependencyProperty.Register("MyText", typeof(String), typeof(TestUserControl), new PropertyMetadata((String)null, new PropertyChangedCallback(TextChanged))); private static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TestUserControl control = d as TestUserControl; if (control != null) { String oldText = e.OldValue as String; // 旧的值 String newText = e.NewValue as String; // 更新的新的值 control.UpdateMyText(newText); } } private void UpdateMyText(string newValue) { this.TextName.Text = newValue; } [Bindable(true)] [Category("Appearance")] // using System.ComponentModel; public string MyText { get { return (String)GetValue(MyTextProperty); } set { SetValue(MyTextProperty, value); } } public static readonly DependencyProperty CommandProperty = DependencyProperty.Register("Command", typeof(ICommand), typeof(TestUserControl), new PropertyMetadata((ICommand)null, new PropertyChangedCallback(CommandChanged))); public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(TestUserControl)); public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register("CommandTarget", typeof(IInputElement), typeof(TestUserControl)); private static void CommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TestUserControl control = d as TestUserControl; if (control != null) { ICommand oldCommand = e.OldValue as ICommand; ICommand newCommand = e.NewValue as ICommand; control.UpdateCommand(oldCommand, newCommand); } } private void UpdateCommand(ICommand oldCommand, ICommand newCommand) { if (oldCommand != null) { oldCommand.CanExecuteChanged -= CanExecuteChanged; } if (newCommand != null) { newCommand.CanExecuteChanged += CanExecuteChanged; } } private void CanExecuteChanged(object sender, EventArgs e) { RoutedCommand command = this.Command as RoutedCommand; if (command != null) { this.IsEnabled = command.CanExecute(CommandParameter, CommandTarget); } else if (this.Command != null) { this.IsEnabled = this.Command.CanExecute(CommandParameter); } } public ICommand Command { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } } public object CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public IInputElement CommandTarget { get { return (IInputElement)GetValue(CommandTargetProperty); } set { SetValue(CommandTargetProperty, value); } } protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) { base.OnMouseLeftButtonDown(e); RoutedCommand command = Command as RoutedCommand; if (command != null) command.Execute(CommandParameter, CommandTarget); else if (Command != null) this.Command.Execute(CommandParameter); } } }
LoginViewModel:
public class LoginViewModel: BindableBase { public LoginViewModel() { } public string _testText = "999"; public string TextText { get { return _testText; } set { SetProperty(ref _testText, value); } } private DelegateCommand<string> _testCommand; public DelegateCommand<string> TestCommand { get { if (_testCommand == null) { _testCommand = new DelegateCommand<string>(ExecuteTestCommand); } return _testCommand; } } private void ExecuteTestCommand(string value) { MessageBox.Show(value); } }
继承处理
在实际项目中,很多时候会创建多个用户控件来完成不同的功能,但是这些控件中往往有部分功能是冗余的,如下列示例代码:
TestUserControlA
<UserControl ......> <Grid Background="Green"> <Button Content="删除" Width="100" Height="50" Click="Button_Click"/> </Grid> </UserControl>
public partial class TestUserControlA : UserControl { public TestUserControlA() { InitializeComponent(); } public ICommand DeleteCommand { get { return (ICommand)GetValue(DeleteCommandProperty); } set { SetValue(DeleteCommandProperty, value); } } public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(TestUserControlA), new PropertyMetadata(default)); public object CommandParameter { get { return (object)GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(TestUserControlA), new PropertyMetadata(default)); private void Button_Click(object sender, RoutedEventArgs e) { DeleteCommand?.Execute(CommandParameter); } }
TestUserControlB
<UserControl ......> <Grid Background="Green"> <Button Content="删除" Width="100" Height="50" Click="Button_Click"/> </Grid> </UserControl>
public partial class TestUserControlB : UserControl { public TestUserControlB() { InitializeComponent(); } public ICommand DeleteCommand { get { return (ICommand)GetValue(DeleteCommandProperty); } set { SetValue(DeleteCommandProperty, value); } } public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(TestUserControlB), new PropertyMetadata(default)); public object CommandParameter { get { return (object)GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(TestUserControlB), new PropertyMetadata(default)); private void Button_Click(object sender, RoutedEventArgs e) { DeleteCommand?.Execute(CommandParameter); } }
观察上述代码,可以发现TestUserControlA和TestUserControlB中的两个依赖属性其含义是相同的,这个时候可以考虑进行抽取到父类,来消除冗余,抽取之后结果如下:
注意此处创建的是类
public class ComponentBase:UserControl { public ICommand DeleteCommand { get { return (ICommand)GetValue(DeleteCommandProperty); } set { SetValue(DeleteCommandProperty, value); } } public static readonly DependencyProperty DeleteCommandProperty = DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(ComponentBase), new PropertyMetadata(default)); public object CommandParameter { get { return (object)GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } } public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register("CommandParameter", typeof(object), typeof(ComponentBase), new PropertyMetadata(default)); }
TestUserControlA
<local:ComponentBase x:Class="Components.TestUserControlA" ......> <Grid Background="Green"> <Button Content="删除" Width="100" Height="50" Click="Button_Click"/> </Grid> </local:ComponentBase>
public partial class TestUserControlA : ComponentBase { public TestUserControlA() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { DeleteCommand?.Execute(CommandParameter); } }
TestUserControlB
<local:ComponentBase x:Class="Components.TestUserControlB" ......> <Grid Background="Green"> <Button Content="删除" Width="100" Height="50" Click="Button_Click"/> </Grid> </local:ComponentBase>
public partial class TestUserControlB : ComponentBase { public TestUserControlB() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { DeleteCommand?.Execute(CommandParameter); } }
来源:https://blog.csdn.net/jjailsa/article/details/135498594