首页 > 其他分享 >WPF开发用户控件、用户控件属性依赖DependencyProperty实现双向绑定、以及自定义实现Command双向绑定功能演示

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

时间:2024-10-11 17:24:22浏览次数:8  
标签:ICommand 控件 CommandParameter DependencyProperty 绑定 typeof 双向 public

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 onm ouseLeftButtonDown(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

 

   

标签:ICommand,控件,CommandParameter,DependencyProperty,绑定,typeof,双向,public
From: https://www.cnblogs.com/ywtssydm/p/18429885

相关文章

  • 【Qt】详细Qt基础 (包括自定义控件)
    目录QT概述创建项目项目文件(.pro)main.cppmainwindow.uimainwindow.hmainwindow.cpp窗口类QWidget窗口显示QDialog窗口QPushButton创建显示对象树基本概念功能坐标体系控件ItemWidgetsQListWidgetQTreeWidgetQTableWidget自定义控件QT概述模块功能QtCore......
  • 界面控件DevExpress WinForms v24.1新版亮点 - 可访问性和UI自动化增强
    DevExpressWinForms拥有180+组件和UI库,能为WindowsForms平台创建具有影响力的业务解决方案。DevExpressWinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!DevExpressWinForms控件v24.1日前已经全新发布,新......
  • CANoe_调用C#控件的方法_DEMO方法演示
    1、DEMO存放位置D:\Users\Public\Documents\Vector\CANoe\SampleConfigurations11.0.96\CAN\MoreExamples\ActiveX_DotNET_Panels每个人的电脑因为有区别存放位置不一样2、控件制作--使用C#控件可以直接制作 3、控件代码usingSystem;usingSystem.Collections;usin......
  • 给控件添加阴影效果SystemDropShadowChrome
    引入命名空间 xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero2"给控件添加引用,这个性能比较好。例如给Combobox下拉框添加引用效果<--!其他代码--><Popupx:Name="PART_Popup"AllowsTransparency="true"Grid.Colum......
  • Qt/C++加载不同的地图控件/地图类型/缩放标尺/缩略图/比例尺/实时路况/全景视图等
    一、前言说明在展示地图的时候,有些常规的操作,比如调整地图的缩放级别,切换到卫星图等,希望能够在地图上直接操作实现,于是就有了一堆地图控件,可以根据自己的需求动态的添加和删除,这样就更直接更快捷,而不是通过函数去设置。几乎每个地图厂家都提供了类似的控件,尽管命名可能有些差别,常......
  • 界面控件Kendo UI for jQuery 2024 Q3亮点 - 支持切换编辑模式
    随着最新的2024Q3版本,Progress使用户能够使用现成的页面模板和构建块更快地构建令人惊叹的应用程序,使您的Telerik和KendoUI开发体验更好。Telerik和KendoUI 2024Q3版本将焦点放在新推出的页面模板和构建块上,每个页面模板和构建块都预先配置了TelerikUIforBlazor、Kend......
  • 双向栈表
    include<stdio.h>include<stdlib.h>include<stdbool.h>defineMAXSIZE100//定义数组的最大长度typedefstruct{intdata[MAXSIZE];inttop1;//第一个栈的栈顶指针inttop2;//第二个栈的栈顶指针}DoubleStack;//初始化双栈voidinitStack(DoubleStack*s......
  • 我店平台模式:商家与消费者双向探索
    在当今这个数字化时代,消费者的购物体验与商家的经营模式正经历着前所未有的变革。而我店平台,作为这一变革的引领者,正通过一系列创新机制,为商家与消费者搭建起一座互利共赢的桥梁。其中,“金币商城”、“抵用券”、“积分奖励”等机制成为了我店平台上的亮点,不仅让消费者享受到了实......
  • 界面控件Kendo UI for jQuery 2024 Q3亮点 - 支持切换编辑模式
    随着最新的2024Q3版本,Progress使用户能够使用现成的页面模板和构建块更快地构建令人惊叹的应用程序,使您的Telerik和KendoUI开发体验更好。Telerik和KendoUI 2024Q3版本将焦点放在新推出的页面模板和构建块上,每个页面模板和构建块都预先配置了TelerikUIforBlazor、KendoU......
  • Pyside6 键盘输入控件---单行文本框QLineEdit
    1.QLineEdit的介绍(官翻)单行文本编辑器允许用户输入和编辑单行纯文本,具有一些实用的编辑功能,包括撤销和重做,剪切和粘贴,以及拖放。通过修改行编辑器的echomde(),它还可以用作只写字段,用于输入密码等信息。QTextEdit是一个与之相关的类,它允许多行、富文本编辑。使用maxLength......