WPF 控件驅動控件 及 數據驅動控件(雙向綁定)

十年河東,十年河西,莫欺少年窮

學無止境,精益求精

最近在知乎,看了很多提問,涉及到就業,裁員,經濟等,不看不知道,越看越頭疼,知乎上很多人提問

畢業生就業如何難,2023年裁員如何嚴重,35歲的中年危機,程序員被裁員後找不到工作該,經濟如何差等話題

哎,這讓我這個35歲的老程序員感到莫大的壓力,我時常想,如果我離開了現在的公司,我能找到工作嗎?多久能找到工作?如果找不到工作,我能幹什麼?

35歲,本是經驗技術相對比較成熟的階段,更是上有老下有小的年齡段,也是花錢多的時候,如果在這個年齡段沒了收入,該多麼絕望......,但沒辦法,世界就是如此,它不會顧及你的感受,生存法則而已

言歸正傳,在開始正文之前,小夥伴們看下知乎上提的一個話題:35歲了,還有必要繼續卷技術嗎? 你們認爲呢?

本來鄙人也不打算繼續內捲了,但中年危機的壓迫感,迫使我不得不拿起手中的槍,繼續戰鬥!我本是做web開發的,但C#語言似乎CS開發崗位更多,而且似乎不受年齡限制,大不了40歲進廠做工控機開發唄,再說了,廠裏妹子不是多麼,挺好的

1、事件驅動模式

這種方式類似於winform,不推薦使用

新建如下頁面

<Window x:Class="WpfApp.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
        xmlns:local="clr-namespace:WpfApp" 
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="1080">
    <Window.Resources>
        <Style TargetType="Button" x:Key="baseStl">
            <Setter Property="Width" Value="200"/>
            <Setter Property="Height" Value="80"/>
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="FontSize" Value="22"/>

        </Style>
        <Style TargetType="Button" x:Key="Butn" BasedOn="{StaticResource baseStl}">
            <Setter Property="Content" Value="Btu"/>

        </Style>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <Slider x:Name="slider" Maximum="100" Minimum="0"  ValueChanged="Slider_ValueChanged" Margin="5" Foreground="red" ></Slider>
            <TextBox x:Name="textbox1" Margin="5" Height="30"  TextChanged="TextBox_TextChanged"/>
            <TextBox x:Name="textbox2"  Margin="5" Height="30" TextChanged="TextBox_TextChanged" />
            <Button x:Name="button" Style="{StaticResource Butn}"  Command="{Binding BtnCommand}" Width="100" Height="100" Content="點我" />
        </StackPanel>
    </Grid>
</Window>
View Code

注意:Slider_ValueChanged 事件 及 TextBox_TextChanged 事件

代碼如下:

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            textbox1.Text = slider.Value.ToString();
            textbox2.Text = slider.Value.ToString();
        }

        private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (double.TryParse(textbox1.Text, out double result))
            {
                slider.Value = result;
            } 
        } 
View Code

這種模式最大的缺點是前後端混合在一起,不方便維護。下面介紹第二種方式,控件驅動控件。

2、控件驅動控件

新建如下頁面

此時後臺事件代碼去掉,前端驅動事件去掉,xaml如下:

<Window x:Class="WpfApp.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
        xmlns:local="clr-namespace:WpfApp" 
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="1080">
    <Window.Resources>
        <Style TargetType="Button" x:Key="baseStl">
            <Setter Property="Width" Value="200"/>
            <Setter Property="Height" Value="80"/>
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="FontSize" Value="22"/>

        </Style>
        <Style TargetType="Button" x:Key="Butn" BasedOn="{StaticResource baseStl}">
            <Setter Property="Content" Value="Btu"/>

        </Style>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <Slider x:Name="slider" Maximum="100" Minimum="0"  Margin="5" Value="{Binding ElementName=textbox1,Path=Text,Mode=TwoWay}"  ></Slider>
            <TextBox x:Name="textbox1" Margin="5" Height="30" Text="{Binding ElementName=slider,Path=Value,Mode=TwoWay}" />
            <Button x:Name="button" Style="{StaticResource Butn}"  Command="{Binding BtnCommand}" Width="100" Height="100" Content="點我" />
        </StackPanel>
    </Grid>
</Window>
View Code

重點解讀

<Slider x:Name="slider" Maximum="100" Minimum="0"  Margin="5" Value="{Binding ElementName=textbox1,Path=Text,Mode=TwoWay}"  ></Slider>

<TextBox x:Name="textbox1" Margin="5" Height="30" Text="{Binding ElementName=slider,Path=Value,Mode=TwoWay}" />

Slider 的 value 的取值爲綁定模式,綁定的是元素Element的Name爲 textbox1,取的是textbox1的text值,Mode模式爲雙向綁定綁定,(WPF默認模式爲單向綁定模式)

TextBox 的 Text 的取值爲綁定模式,綁定的是元素Element的Name爲 slider,取的是slider的value值,Mode模式爲雙向綁定綁定,(WPF默認模式爲單向綁定模式)

3、數據驅動模式(數據上下文模式)

需求要求:進度條初始值爲20,點擊按鈕後,進度條的值變爲88,且彈框提示

3.1、按鈕點擊需要用到Wpf的Command命令

新建BaseCommand類,並實現接口 ICommand

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace WpfApp.Models
{
    public class BaseCommand : ICommand
    {
        public Action action;
        public BaseCommand(Action action)
        {
            this.action = action;

        }
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            action();
        }
    }
}
View Code

3.2、先建viewModel如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Windows.Input;
using System.Messaging;
using System.Windows;

namespace WpfApp.Models
{
    public class MainWindowModel : INotifyPropertyChanged
    { 
        public ICommand BtnCommand { get; set; }
        public MainWindowModel()
        {
            //進度條模式爲20
            this.wendu = 20;
            BtnCommand = new BaseCommand(DoBtnCommand);
        }

        public void DoBtnCommand()
        {
            this.wendu = 88;
            MessageBox.Show("進度條的值修改爲88,進度條向前歡動了。");
        }
        private ushort _wendu;
        public ushort wendu
        {
            get { return this._wendu; }
            set
            {
                this._wendu = value;
                this.OnPropertyChanged("wendu");
            }
        }
     
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this,  new PropertyChangedEventArgs(propertyName));
            }
        }


    }
}
View Code

3.3、修改xaml的數據上下文

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowModel(); 
        }

3.4、xaml如下

<Window x:Class="WpfApp.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:controls="clr-namespace:HandyControl.Controls;assembly=HandyControl"
        xmlns:local="clr-namespace:WpfApp" 
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="1080">
    <Window.Resources>
        <Style TargetType="Button" x:Key="baseStl">
            <Setter Property="Width" Value="200"/>
            <Setter Property="Height" Value="80"/>
            <Setter Property="Background" Value="Yellow"/>
            <Setter Property="FontSize" Value="22"/>

        </Style>
        <Style TargetType="Button" x:Key="Butn" BasedOn="{StaticResource baseStl}">
            <Setter Property="Content" Value="Btu"/>

        </Style>
    </Window.Resources>
    <Grid>
        <StackPanel>
            <Slider x:Name="slider" Maximum="100" Minimum="0"  Margin="5" Value="{Binding wendu}"  ></Slider>
            <TextBox x:Name="textbox1" Margin="5" Height="30" Text="{Binding wendu}" />
            <Button x:Name="button" Style="{StaticResource Butn}"  Command="{Binding BtnCommand}" Width="100" Height="100" Content="點我" />
        </StackPanel>
    </Grid>
</Window>
View Code

3.5、另一種實現模式(主要是Command實現類)

ICommand的實現類(通過屬性賦值Action委託,上面方法是通過構造函數賦值Action委託)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace WpfApp.Models
{
    /// <summary>
    /// 屬性賦值action模式
    /// </summary>
    public class CommandBase : ICommand
    {
        public event EventHandler CanExecuteChanged;

        /// <summary>
        /// 是否可執行
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            action.Invoke(parameter);
        }

        public Action<object> action { get; set; }
    }
}
View Code

viewModel如下

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace WpfApp.Models
{
    public class MainWindowMod : INotifyPropertyChanged
    {
        //新建按鈕點擊事件
        public ICommand BtnCommand { get; set; }

        public MainWindowMod()
        {
            this.wendu = 20; 
            //執行委託
            BtnCommand = new CommandBase() { action = new Action<object>(DoBtnCommand) };
        }

        public void DoBtnCommand(object obj)
        { 
            this.wendu = 88; 
            MessageBox.Show("進度條的值修改爲88,進度條向前歡動了。");
        }
        private ushort _wendu;
        public ushort wendu
        {
            get { return this._wendu; }
            set
            {
                this._wendu = value;
                this.OnPropertyChanged("wendu");
            }
        }
     

        /// <summary>
        /// 用於雙向綁定
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
View Code

優化如下:

如果每次都需要寫  "wendu" ,有可能會寫錯

 this.OnPropertyChanged("wendu");

優化代碼如下

    public class MainWindowMod : INotifyPropertyChanged
    {
        //新建按鈕點擊事件
        public ICommand BtnCommand { get; set; }

        public MainWindowMod()
        {
            this.wendu = 20; 
            //執行委託
            BtnCommand = new CommandBase() { action = new Action<object>(DoBtnCommand) };
        }

        public void DoBtnCommand(object obj)
        { 
            this.wendu = 88; 
            MessageBox.Show("進度條的值修改爲88,進度條向前歡動了。");
        }
        private ushort _wendu;
        public ushort wendu
        {
            get { return this._wendu; }
            set
            {
                this._wendu = value;
                this.OnPropertyChanged();
            }
        }
     

        /// <summary>
        /// 用於雙向綁定
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName="")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
View Code

 

@天才臥龍的波爾卡

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章