【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 前言:

Wpf开发过程中,最经常使用的功能之一,就是用户控件(UserControl)了。用户控件可以用于开发用户自己的控件进行使用,甚至可以用于打造一套属于自己的UI框架。依赖属性(DependencyProperty)是为用户控件提供可支持双向绑定的必备技巧之一,同样用处也非常广泛。

以下案例,为了图方便,我以之前的博客的基础为模板,直接进行开发。如有遇到疑问的地方,可以查看先前的博客(WPF使用prism框架+Unity IOC容器实现MVVM双向绑定和依赖注入)的文章做个前瞻了解:

https://www.cnblogs.com/weskynet/p/15967764.html

 

以下是正文(代码在文末)

 

0、配置环境

客户端环境:WIN 10 专业版

VS开发环境:VS 2022 企业版

运行时环境:.NET 6

开发语言:C#

前端框架:WPF

 

1、新建了一个用户控件,里面画了一个实心圆,以及一个文本控件的组合,当作我要实验使用的用户控件(TestUserControl)。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

2、在主窗体里面进行引用,可以看到引用以后,会在工具箱上显示新增的用户控件

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

3、为了测试方便,我直接在先前的Lo'gin页面直接进行添加该用户控件,效果如下。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

4、运行效果如下。由于该用户控件没有设置过任何属性,所以现在是没有任何事件、也没有办法更改默认文本等信息的。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

5、接下来进行设置属性,用于可以直接更改TextName属性的Text值。设置一个MyText属性,用于可以获取和设置用户控件内的TextBlock的Text值。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

6、然后可以在Xaml里面直接通过更改MyText的属性,来更新显示的Text值。如下图所示,设置MyText属性后,设置值为666,同步更新成666了。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

7、但是如果想要实现双向绑定,其实还不太够,直接Binding会提示错误XDG0062:Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'. 如图。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

8、以上问题可以通过自定义依赖属性来解决。在用户控件的设计器交互代码类(TestUserControl)里面,新增以下代码,功能如图所示。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

9、现在在xaml里面,设置Binding就不会提示错误了。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

 

10、并且也可以直接设置值,效果同上面设置属性以后直接写值效果一样。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

11、在Login页面的ViewModel里面,新增属性提供给双向绑定使用。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

12、设置MyText进行Binding到刚刚写的ViewModel的属性TestText上。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

13、运行效果如下图所示,说明双向绑定成功了。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

14、接下来对用户控件设置单击事件的双向绑定。先设置Command有关的依赖属性。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

15、一些有关方法和其他的属性设置,就不做过多介绍了,看图说话。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

 

16、然后是关键的一步,需要设置单机事件与Command属性关联。当然,Command是命名得来的,所以也可以使用其他的命名,也都是OK的,不用在意这些细节,只是默认情况下,单击都喜欢用Command。如果自带的控件也没有双击、右键等双向绑定,也可以通过设置依赖属性来实现。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

17、在ViewModel里面定义单击事件以及有关执行的方法。方法为一个弹出消息框。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

18、使用Command进行绑定事件名称。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

19、运行,并单击实心圆的效果,并弹出提示框,说明单击事件通过依赖属性进行设置成功。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

20、接下来测试一下带参数的事件。在viewmodel里面,对刚才无参数的事件,改为带一个string参数的。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

21、在xaml里面,传入一个字符串参数,就叫 Hello world

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

22、运行,并点击实心圆后效果如图所示,说明带参数也是OK的。

 【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

23、其他套路如出一辙,大佬们可以自行尝试,例如通过设置背景依赖属性,变更实心圆的背景,而不是整个用户控件(正方形)的背景。这部分本来也要写一个给大佬们压压惊,由于时间关系,大佬们可以自己尝试玩一下。

提示:背景 Background是系统自带的,所以需要new。通过属性依赖进行更改圆的颜色,而不是背景色。有兴趣的大佬或者需要学习的,可以动手玩一玩,加深印象。

 

以上就是该文章的全部内容,如果对你有帮助,欢迎大佬点赞、留言与转发。如需转发,请注明我的博客出处:

https://www.cnblogs.com/weskynet/p/16290422.html

 

如果有知识分享、技术讨论的热情,可通过原文链接(以上博客园链接为原文链接,CSDN为自动同步链接,其他均为盗版链接) 的文章最下方,点击加入.NET 讨论QQ群。或者也可以扫下方我的微信二维码头像加我私人微信,然后我可以拉到我的微信交流群一起学习和技术了解,也都是OK的,欢迎大佬们来玩。 

私人微信:

WeskyNet001

【WPF】WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

 

 

 

以下是有关最终的源代码:

 

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);         }      }

 

 

 

 

 

 

 

发表评论

相关文章