工作日志- - -自定义控件(详解)

示例版本在Prism Dryloc框架上示例的

搭建框架介绍
  • 1 在程序中下载Nuget包Prism.DryIoc
  • 2 将App.xaml 和App.cs文件改为以下示例
<prism:PrismApplication
    x:Class="WpfApp4.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/">
    <Application.Resources />
</prism:PrismApplication>
using Prism.DryIoc;
using Prism.Ioc;
using System.Windows;
using WpfApp4.ViewModel;

namespace WpfApp4
{
    /// <summary>
    /// App.xaml 的交互逻辑
    /// </summary>
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<MainWindow,Class1>();
        }
    }
}
  • 3 绑定上下文 view 绑定到ViewModel 两种方法

1 创建自定义控件类

知识:创建自定义控件类,你可以理解为创建一个和Button一样的类我们需要继承一个控件(不一定要继承示例的这个类,其他类也可以)

using System.Windows.Controls;

namespace WpfApp4
{
    public class MyControl : ContentControl
    {
        
    }
}

1.1绘制自定义控件外观

上面继承了 : ContentControl类这个MyControl就是我们的控件名称了,下一步给他创建一个外观吧。创建资源字典 名称为“Dictionary1”

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:con="clr-namespace:WpfApp4">
    <Style TargetType="con:MyControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="con:MyControl">
                    <Border
                        x:Name="border"
                        Width="{TemplateBinding Width}"
                        Height="{TemplateBinding Height}">
                        <StackPanel>
                            <Rectangle
                                Width="100"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                            <Rectangle
                                Width="150"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                            <Rectangle
                                Width="100"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                            <Rectangle
                                Width="50"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                            <Rectangle
                                Width="25"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                            <Rectangle
                                Width="12.5"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                            <Rectangle
                                Width="6.25"
                                Height="30"
                                Fill="#a6a6a6"
                                Stroke="#3b3b3b" />
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

在App中引用当前资源

<prism:PrismApplication
    x:Class="WpfApp4.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://prismlibrary.com/">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary1.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</prism:PrismApplication>

在前端引用

<Window
    x:Class="WpfApp4.MainWindow"
    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:local="clr-namespace:WpfApp4"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid >
        <local:MyControl/>
    </Grid>
</Window>

效果图:

1.2添加自定义控件的依赖属性  

        这样我们就算创建了一个自定义控件,但我们如果想控制他的大小我们就需要给控件添加一些,依赖属性。添加依赖属性:注释在代码里!!!

using System.Windows;
using System.Windows.Controls;

namespace WpfApp4
{
    public class MyControl : ContentControl
    {
        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }
        public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double), typeof(MainWindowViewModel), new PropertyMetadata(0.0, Change));

        private static void Change(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //当前 X 值 发生更改时触发当前方法
        }
        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }
        public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(double), typeof(MainWindowViewModel), new PropertyMetadata(0.0));
        //解释: nameof(Y)是基于哪一个属性  typeof(double):当前属性的数据类型   typeof(MainWindowViewModel)当前属性属于哪一个类  new PropertyMetadata(0.0)); 给当前依赖属性的默认值   

        //取命注意 DependencyProperty 类型的名称必须Property结尾
    }
}

修改一下资源字典的绑定  (只修改了 第13行)

 <StackPanel Width="{TemplateBinding X}" Height="{TemplateBinding Y}">

在前端给属性赋值上,就发现大小可以自定义了

 <Grid >
        <local:MyControl X="200" Y="250"/>
    </Grid>

1.3当前效果图

1.4 添加自定义控件的事件

1  修改一下上面的MyControl类 在类中的第8行 和Change方法中调用事件

using System.Windows;
using System.Windows.Controls;

namespace WpfApp4
{
    public class MyControl : ContentControl
    {
        public event RoutedEventHandler MyCustomEvent;
        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }
        public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double), typeof(MyControl), new PropertyMetadata(0.0, Change));

        //当前 X 值 发生更改时触发当前方法
        private static void Change(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //当值发生修改当前事件触发
            (d as MyControl).MyCustomEvent?.Invoke(d, new RoutedEventArgs());
        }
        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }
        public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(double), typeof(MyControl), new PropertyMetadata(0.0));
        //解释: nameof(Y)是基于哪一个属性  typeof(double):当前属性的数据类型   typeof(MyControl)当前属性属于哪一个类  new PropertyMetadata(0.0)); 给当前依赖属性的默认值   

        //取命注意 DependencyProperty 类型的名称必须Property结尾
    }
}

2 在前端绑定当前事件触发到的Icommand

<Window
    x:Class="WpfApp4.MainWindow"
    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:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:WpfApp4"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    Title="MainWindow"
    Width="800"
    Height="450"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d">
    <Grid>
        <local:MyControl X="200" Y="250">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="MyCustomEvent">
                    <prism:InvokeCommandAction Command="{Binding MyProperty}" />
                    <!--绑定触发事件的方法-->
                </i:EventTrigger>
            </i:Interaction.Triggers>
            s
        </local:MyControl>
    </Grid>
</Window>

3 在视图对应的ViewModel中添加绑定的命令以及触发的方法

using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Windows;
using System.Windows.Input;

namespace WpfApp4
{
    public class MainWindowViewModel:BindableBase
    {
        public MainWindowViewModel()
        {

        }
     
        public ICommand MyProperty { get => new DelegateCommand<object>(L); }

        private void L(object s)
        {
            //触发到的方法
        }
    }
}

效果就是每修改X的值,就会触发当前的方法,但怎么传递参数呢? 

1.5 创建Icommand类型的依赖属性

icommand能解决什么问题?在我们想触发的位置触发当前命令,并传递参数。

1 第一步在MyControl中创建Icommand类型的属性

using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfApp4
{
    public class MyControl : ContentControl
    {
        public event RoutedEventHandler MyCustomEvent;
        public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }
        public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double), typeof(MyControl), new PropertyMetadata(0.0, Change));

        //当前 X 值 发生更改时触发当前方法
        private static void Change(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //当值发生修改当前事件触发
            //(d as MyControl).MyCustomEvent?.Invoke(d, new RoutedEventArgs());
            //command 触发命令 Execute方法 d为传递的参数
            (d as MyControl).Command?.Execute(d);
        }
        public double Y
        {
            get { return (double)GetValue(YProperty); }
            set { SetValue(YProperty, value); }
        }
        public static readonly DependencyProperty YProperty = DependencyProperty.Register(nameof(Y), typeof(double), typeof(MyControl), new PropertyMetadata(0.0));
        //解释: nameof(Y)是基于哪一个属性  typeof(double):当前属性的数据类型   typeof(MyControl)当前属性属于哪一个类  new PropertyMetadata(0.0)); 给当前依赖属性的默认值   

        //取命注意 DependencyProperty 类型的名称必须Property结尾

       
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof(ICommand), typeof(MyControl), new PropertyMetadata(null));
        public ICommand Command
        {
            get
            {
                return (ICommand)GetValue(CommandProperty);
            }
            set
            {
                SetValue(CommandProperty, value);
            }
        }
    }
}

2 第二步在前端绑定触发命令的方法

<Window
    x:Class="WpfApp4.MainWindow"
    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:i="http://schemas.microsoft.com/xaml/behaviors"
    xmlns:local="clr-namespace:WpfApp4"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    Title="MainWindow"
    Width="800"
    Height="450"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d">
    <Grid>
        <local:MyControl
            Command="{Binding MyProperty}"
            X="200"
            Y="250" />
    </Grid>
</Window>

3 在视图中的ViewModel中 写下触发方法

using Prism.Commands;
using Prism.Mvvm;
using System.Windows.Input;

namespace WpfApp4
{
    public class MainWindowViewModel:BindableBase
    {
        public MainWindowViewModel()
        {

        }
     
        public ICommand MyProperty { get => new DelegateCommand<object>(L); }

        private void L(object s)
        {
            //触发到的方法
        }
    }
}

1.6 创建自定义控件的事件

        在MyControl 类中添加以下代码,注册一个鼠标点击触发事件,如果你想传递什么参数,可以参考1.7

  //protected 关键字受保护的  override  重写  
        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            //当前是鼠标点击控件就触发事件
        }

1.7 创建自定义控件的Command

创建自定义控件的command 就是实现各种事件的触发回调 ,传递参数

 情景:在值发生更改时,触发command绑定的方法,并传递当前对象到绑定的方法当中作为参数

1 先在 MyControl 类中添加如下代码

 public ICommand Command
        {
            get
            {
                return (ICommand)GetValue(CommandProperty);
            }
            set
            {
                SetValue(CommandProperty, value);
            }
        }
        public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( "Command", typeof(ICommand), typeof(MyControl), new PropertyMetadata(null));

2 在调用界面给command绑定方法  

 <Grid>
        <Button Height="20" VerticalAlignment="Bottom" />
        <local:MyControl
            Command="{Binding MyProperty}"
            X="200"
            Y="250" />
    </Grid>

绑定到的ViewModel 中添加

public class MainWindowViewModel:BindableBase
    {
        public MainWindowViewModel()
        {

        }
     
        public ICommand MyProperty { get => new DelegateCommand<object>(L); }

        private void L(object s)
        {
            //触发到的方法
        }
    }

3 在想触发绑定的命令处,调用命令。 

 public double X
        {
            get { return (double)GetValue(XProperty); }
            set { SetValue(XProperty, value); }
        }
        public static readonly DependencyProperty XProperty = DependencyProperty.Register(nameof(X), typeof(double), typeof(MyControl), new PropertyMetadata(0.0, Change));

        //当前 X 值 发生更改时触发当前方法
        private static void Change(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //command 触发命令 Execute方法 d为传递的参数
            (d as MyControl).Command?.Execute(d);
        }

4 运行后效果:

1.8 创建自定义控件的依赖事件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学软件开发的猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值