• 如何建立一个“绑定友好的”usercontrol--wpf


    如何建立一个“绑定友好的”usercontrol--wpf

      这几天在打算将以前用winform写的工具程序重构到wpf,顺便学习理解看过的wpf的知识。

      因为程序设计到一个Excel文件的读取和操作,比较耗时,所以打算制作一个缓冲动画。该动画应该分为两个部分,一个部分是“一排一次排列的方块组成的渐变动画”,一部分是一个Label类的控件,用来显示后台操作Excel时候的进度。

      先放上渐变动画的Xaml,在usercontrol里面加上以下代码就行了。这个不是今天记录的重点。

    <Canvas  Margin="0,0,0,50">
            <Rectangle x:Name="r1" Fill="Black" Opacity="1" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="20" Canvas.Top="16"/>
            <Rectangle x:Name="r2" Fill="Black" Opacity="0.9" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="70" Canvas.Top="16"/>
            <Rectangle x:Name="r3" Fill="Black" Opacity="0.8" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="120" Canvas.Top="16"/>
            <Rectangle x:Name="r4" Fill="Black" Opacity="0.7" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="170" Canvas.Top="16"/>
            <Rectangle x:Name="r5" Fill="Black" Opacity="0.6" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="220" Canvas.Top="16"/>
            <Rectangle x:Name="r6" Fill="Black" Opacity="0.5" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="270" Canvas.Top="16"/>
            <Rectangle x:Name="r7" Fill="Black" Opacity="0.4" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="320" Canvas.Top="16"/>
            <Rectangle x:Name="r8" Fill="Black" Opacity="0.3" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="370" Canvas.Top="16"/>
            <Rectangle x:Name="r9" Fill="Black" Opacity="0.2" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="420" Canvas.Top="16"/>
            <Rectangle x:Name="r10" Fill="Black" Opacity="0.1" HorizontalAlignment="Left" Height="30" Stroke="Black" VerticalAlignment="Top" Width="30" Canvas.Left="470" Canvas.Top="16"/>
            <Canvas.Triggers>
                <EventTrigger RoutedEvent="Canvas.Loaded">
                    <BeginStoryboard >
                        <Storyboard RepeatBehavior="Forever">
                            <DoubleAnimation Storyboard.TargetName="r1" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r2" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.08" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r3" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.16" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r4" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.24" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r5" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.32" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r6" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.40" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r7" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.48" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r8" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.56" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r9" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.64" To="0"/>
                            <DoubleAnimation Storyboard.TargetName="r10" Storyboard.TargetProperty="Opacity" AutoReverse="True" Duration="0:0:0.08" BeginTime="0:0:0.72" To="0"/>
                        </Storyboard>
    
                    </BeginStoryboard>
                </EventTrigger>
            </Canvas.Triggers>
        </Canvas>
    

      现在重点来说说label类控件显示进度描述的,因为打算在自定义控件中利用binding来进行实时的通知,所以这个usercontrol必须是一个绑定友好的控件。

      网上也查找了不少,也问了问同事,著名的“老赵”(不敢妄加评论大神,勿怪)和同事都是为usercontrol配一个viewmodle来实现binding的友好,但是这种不是我想要的,总觉得给一个控件配一个viewmodle不太舒服。就想实现普通类似:

    <TextBlock Text="{Binding Name}" Height="30"/>
    

      如上代码的binding。

      继续百度+看书,确认可以使用依赖属性来暴露出usercontrol的一个属性,利用这个属性来实现bind。

      这里我重新制作了一个usercontrol,核心是两个TextBlock,对第二个TextBlock中的text部分设置进行一个属性暴露的操作。

      代码如下xmal:

    <UserControl x:Class="MetroTest.LoaclControl.DoubleTextBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="150" d:DesignWidth="300">
    <Grid>
        <StackPanel>
            <Label Content="A"></Label>
            <TextBox x:Name="txtBox1" Text="试一试" Height="30" Margin="5"/>
            <Label Content="B"></Label>
            <TextBox x:Name="txtBox2"  Height="30" Margin="5"/>
        </StackPanel>
    </Grid>
    </UserControl>
    

       这个usercontrol对应的后台代码:

        /// <summary>
    /// DoubleTextBox.xaml 的交互逻辑
    /// </summary>
    public partial class DoubleTextBox : UserControl
    {
        public DoubleTextBox()
        {
            InitializeComponent();
        }
    
        public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("TempName", typeof(string),
            typeof (DoubleTextBox),new PropertyMetadata("TextBlock",new PropertyChangedCallback(OnTextChanged)));
    
        private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DoubleTextBox dtb = (DoubleTextBox) d;
            dtb.txtBox2.Text = (string) e.NewValue;
        }
    
        public string TempName
        {
            get { return (string) GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
    }
    

      这里使用DependencyProperty定义一个依赖属性ValueProperty,利用register操作进行注册,
    说一下各个参数的含义:

      1:暴露出来的属性名称,这里为“TempName”,可以如下使用

     <localControl:DoubleTextBox Height="200" TempName="{Binding Name}"></localControl:DoubleTextBox>
    

      2:暴露出的属性的类型,这里是字符串string

      3:属性所有者的名字,看前面的定义,“Temp”是“DoubleTextBox”的一个公开属性,所以名字就是DoubleTextBox

      4:用来处理属性改变时候的操作,回调函数参数1:就是依赖属性的默认值,随便给一个string类型都可以 2、具体处理方法

      如上,一个bind友好的控件就制作完了,可以在此基础上继续改造升级。

      放一个简单的使用demo(不包含渐变动画):

      建立一个testWindow,在里面使用控件(命名中的拼写错误请忽略)

    <Window x:Class="MetroTest.Test"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localControl="clr-namespace:MetroTest.LoaclControl"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        Title="Test" Height="300" Width="594">
    <StackPanel>
        <localControl:DoubleTextBox Height="200" TempName="{Binding Name}"></localControl:DoubleTextBox>
        <Button  Command="{Binding OpenFileCommand}">Submit</Button>
        <TextBlock Text="{Binding Name}" Height="30"/>
    </StackPanel>
    </Window>
    

      这其中,xmlns:localControl="clr-namespace:MetroTest.LoaclControl"是我自定义控件所放置的文件夹的路径。

      界面组成:1、定义好的uercontrol 2、一个button 3、一个Textblock

      分别用处:1、不用说了 2、导向一个vm中的command用来更新bind的内容 3、检查是不是bind更新成功的

      写一个简单的VieModle(忽略command的命名,copy的其他工程的)

    class TextViewModle:ViewModleBase
    {
         private string _name;
    
        public string Name
        {
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
            get { return _name; }
        }
    
        private int count = 1;
        //定义一个命令
        public ICommand OpenFileCommand { get { return new RelayCaommand(OpenFileExecute, CanOpenFileExecute); } }
    
        private bool CanOpenFileExecute()
        {
            return true;
        }
    
        private void OpenFileExecute()
        {
            Name = count.ToString();
            count++;
        }
    }
    

      记得给TestWindow的datacontent进行绑定。(命名中的拼写错误请忽略)

        /// <summary>
    /// Test.xaml 的交互逻辑
    /// </summary>
    public partial class Test : Window
    {
        public Test()
        {
            InitializeComponent();
            this.DataContext = new TextViewModle();
        }
    
    }
    

      到此,一个简单的例子就完成了,水平浅陋,希望对大家有帮助。。

      顺便推销个人博客:http://www.dingshuo89.top

  • 相关阅读:
    Python的条件判断和循环
    Python分支和循环结构的练习
    Python的变量和运算符
    Python简介
    Git的使用及网络编程多线程多进程
    函数面向对象编程及文件的读取
    函数模块字符串列表
    python变量运算符分支结构循环结构及例题
    集合
    三级菜单
  • 原文地址:https://www.cnblogs.com/tilv37/p/4745693.html
Copyright © 2020-2023  润新知