前言:

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)。

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

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

私人微信:

WeskyNet001

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

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

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

  1. 使用XAML在WPF项目中承载ArcGIS Engine地图控件开发

    原文 http://blog.csdn.net/flexmapserver/article/details/5868882 用Windows Form进行ArcGIS Engine二次开发时常见的形式 ...

  2. WPF基础知识、界面布局及控件Binding(转)

    WPF是和WinForm对应的,而其核心是数据驱动事件,在开发中显示的是UI界面和逻辑关系相分离的一种开放语言.UI界面是在XAML语言环境下开发人员可以进行一些自主设计的前台界面,逻辑关系还是基于c ...

  3. WPF基础知识、界面布局及控件Binding

    WPF是和WinForm对应的,而其核心是数据驱动事件,在开发中显示的是UI界面和逻辑关系相分离的一种开放语言.UI界面是在XAML语言环境下开发人员可以进行一些自主设计的前台界面,逻辑关系还是基于c ...

  4. WPF下可编辑Header的Tab控件实现

    介绍 有这样一个需求,当用户双击Tab控件Header区域时, 希望可以直接编辑.对于WPF控件,提供一个ControlTemplate在加上一些Trigger就可以实现.效果如下: 代码 首先,我们 ...

  5. WPF从我炫系列4---装饰控件的用法

    这一节的讲解中,我将为大家介绍WPF装饰控件的用法,主要为大家讲解一下几个控件的用法. ScrollViewer滚动条控件 Border边框控件 ViewBox自由缩放控件 1. ScrollView ...

  6. WPF自定义控件(二)の重写原生控件样式模板

    话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式. 开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么 ...

  7. WPF中。。DataGrid 实现时间控件和下拉框控件

    DatePicker 和新的 DataGrid 行 用户与 DataGrid 中日期列的交互给我造成了很大的麻烦. 我通过将一个 Data Source 对象拖动到 WPF 窗口上,创建了一个 Dat ...

  8. WPF 构建无外观(Lookless)控件

    原文:WPF 构建无外观(Lookless)控件 构建一个用户可以使用Template属性设置外观的WPF控件需要以下几步 1.继承自System.Windows.Controls.Control 2 ...

  9. 【WPF学习】第六十章 创建控件模板

    经过数十天的忙碌,今天终于有时间写博客. 前面一章通过介绍有关模板工作方式相关的内容,同时介绍了FrameWorkElement下所有控件的模板.接下来将介绍如何构建一个简单的自定义按钮,并在该过程中 ...

随机推荐

  1. 集合流之“将List<Integer>转为String并用逗号分割”

    1.使用[流+Collectors]转换 import java.util.ArrayList; import java.util.List; import java.util.stream.Coll ...

  2. Netty之非阻塞处理

    Netty 是一个异步的.基于事件驱动的网络应用框架,用以快速开发高性能.高可靠性的网络 IO 程序. 一.异步模型 同步I/O : 需要进程去真正的去操作I/O: 异步I/O:内核在I/O操作完成后 ...

  3. elf,基于flexbox的响应式CSS框架

    官网地址:http://jrainlau.github.io/elf/项目地址:https://github.com/jrainlau/elf 介绍 取名为"精灵"的elf,是一个 ...

  4. 《深入理解ES6》笔记—— Promise与异步编程(11)

    为什么要异步编程 我们在写前端代码时,经常会对dom做事件处理操作,比如点击.激活焦点.失去焦点等:再比如我们用ajax请求数据,使用回调函数获取返回值.这些都属于异步编程. 也许你已经大概知道Jav ...

  5. python实战----Todo清单续写

    添加分页功能 第一步:是对视图函数的改写,通过查询数据库数据,进行分页显示 # 修改清单显示的视图函数 @app.route('/list/') @app.route('/list/<int:p ...

  6. 驳《我不是很懂 Node.js 社区的 DRY 文化》

    今天在群里有人讨论方老师的文章<我不是很懂 Node.js 社区的 DRY 文化>,我也看了一遍,槽点太多,不知道如何下笔. 方老师分析了几个依赖最多的 npm 包,每个都只有不到百行代码 ...

  7. 在TypeScript项目中进行BDD测试

    在TypeScript项目中进行BDD测试 什么是BDD? BDD(Behavior-Driven Design)是软件团队的一种工作方式,通过以下方式缩小业务人员和技术人员之间的差距: 鼓励跨角色协 ...

  8. Java中使用最频繁及最通用的Java工具类

    在Java中,工具类定义了一组公共方法,Java中使用最频繁及最通用的Java工具类. 一. org.apache.commons.io.IOUtils closeQuietly:关闭一个IO流.so ...

  9. AcWing 1220. 生命之树

    题目链接 题目描述: 在X森林里,上帝创建了生命之树. 他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值. 上帝要在这棵树内选出一个非空节点集 S,使得对于 S 中的任 ...

  10. LC-141andLC-142

    142. 环形链表 II 思路: 设链表共有 a+b 个节点,其中 链表头部到链表入口 有 a 个节点(不计链表入口节点), 链表环 有 b 个节点. 再设两指针分别走了 f,s 步,则有: f = ...