wpf: 绑定


需求:

  1.   滑动条拖动,文本框值变化

  2.  文本框值变,滑动条值也变化

实际上是一种控件双方绑定的需求。


靠事件的实现:

image.png

   /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

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

        private void txt1_TextChanged(object sender, TextChangedEventArgs e)
        {
            slider.Value = double.Parse(txt1.Text);
        }
    }
    <Grid>
        <StackPanel>
            <Slider x:Name="slider" Margin="5" ValueChanged="Slider_ValueChanged"/>
            <TextBox x:Name="txt1" Margin="5" Height="30" TextChanged="txt1_TextChanged"/>
            <TextBox x:Name="txt2" Margin="5" Height="30"/>
            <TextBox x:Name="txt3" Margin="5" Height="30"/>
        </StackPanel>
    </Grid>


靠事件的方式的缺点:

靠事件代码维持这种双向绑定的效果,实际上后台代码应该是处理工作逻辑,而不是进行这种控件事件的处理。


控件与控件的绑定

    <Grid>
        <StackPanel>
            <Slider x:Name="slider" Margin="5"/>
            <TextBox Text="{Binding ElementName=slider,Path=Value}"  Margin="5" Height="30"/>
            <TextBox Text="{Binding ElementName=slider,Path=Value}" Margin="5" Height="30"/>
            <TextBox Text="{Binding ElementName=slider,Path=Value}" Margin="5" Height="30"/>
        </StackPanel>
    </Grid>

此模式下就完成了双向绑定,有几个特点:

1。 注意此时后台不需要任何代码的,我们也删除了事件的方式,这种绑定完全是在xmal端完成的

2。 此时3个textbox不需要命名的。

3。 你也可以指定绑定模式

     Default    默认的双向绑定

     OneTime  绑定变化只反映出第一个值的变化

     OneWay   单方面模式,对于本例,只允许slider改变textbox,而反过来不允许

     OneWayToSource  就是OneWay倒过来,只允许Textbox改变slider

     TwoWay  双向绑定

image.png


控件与属性的绑定


指的是后台的某个类的属性做绑定关系。

    <Grid>
        <StackPanel>
         
            <TextBox Text="{Binding Name}"  Margin="5" Height="30"/>
          
        </StackPanel>
    </Grid>


注意DataContext这个是数据上下文。

有了它,上面xmal中的{Binding Name} 才真正有的意义。(没上下文就找不到数据源Name)

namespace WpfApp1
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MyData()
            {
                Name = "张三"
            };
        }

       
    }

    public class MyData
    {
        public string Name { get; set; }
    }

}


控件的Command


对一个按钮来说,虽然可以有一个点击事件然后后台书写代码。

但是可以使用高级的Command机制做响应点击的动作。

注意两者各有应用场合,并不是谁替代谁。


xmal代码:

        <StackPanel>

            <Button Command="{Binding ShowCommand}" Height="30" Width="30"/>

        </StackPanel>

C#代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

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

       
    }

    public class MainViewModel
    {
        public MainViewModel()
        {
            ShowCommand = new MyCommand(Show);
        }

        public MyCommand ShowCommand { get; set; }

        public void Show()
        {
            MessageBox.Show("Hello world");
        }
    }

    public class MyCommand : ICommand
    {
        Action _act;
        public event EventHandler CanExecuteChanged;

        public MyCommand(Action act)
        {
            this._act = act;
        }

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

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

}

image.png


控件更新通知


解决在Command代码中,更新Name属性,无法更新到控件上的问题。

只要继承 INotifyPropertyChanged接口,使用它提供的PropertyChanged事件即可完成更新。

image.png

image.png


Xmal代码:

注意{Binding Name} 这个绑定实际上就是做了订阅通知事件。


    <Grid>
        <StackPanel>
            <TextBlock Text="{Binding Name}"/>
            <Button Command="{Binding ShowCommand}" Height="30" Width="30"/>

        </StackPanel>
    </Grid>

后台代码:

public class MainViewModel: INotifyPropertyChanged
    {
        public MainViewModel()
        {
            ShowCommand = new MyCommand(Show);
            name = "刘备";
        }
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
            }
        }
        public MyCommand ShowCommand { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        public void Show()
        {
            Name = "刘备2";
         
            MessageBox.Show("Hello world");
        }
    }


优化代码,弄个基类,简化多属性情况下的使用麻烦问题。

几点说明:

1。 由基类NodifyBase做事件通知

2。 基类中的[CallerMemberName]特性,可以取得传入参数的值。这样我们就不用写传入值了。(写了也可以)

    public class MainViewModel: NodifyBase
    {
        public MainViewModel()
        {
            ShowCommand = new MyCommand(Show);
            name = "刘备";
        }
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                //PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
                OnPropertyChange();
            }
        }

        private string title;
        public string Title
        {
            get { return title; }
            set
            {
                title = value;
                //PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Title"));
                OnPropertyChange();
            }
        }

        public MyCommand ShowCommand { get; set; }

       // public event PropertyChangedEventHandler PropertyChanged;

        public void Show()
        {
            Name = "刘备2";
         
            MessageBox.Show("Hello world");
        }
    }


    public class NodifyBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public void  OnPropertyChange([CallerMemberName]string propertyName="")
        {
            PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }


MvvmLight框架


nuget安装 MvvmLight。

修改MainViewModel代码:

我们可以看到这个框架也实现上面Command和控件更新通知的效果。

   public class MainViewModel:ViewModelBase
    {
        public RelayCommand ShowCommand { get; }
        public MainViewModel()
        {
            ShowCommand = new RelayCommand(Show);
            name = "刘备";
            title = "windows";
        }
        private string name;
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                RaisePropertyChanged();
            }
        }

        private string title;
        public string Title
        {
            get { return title; }
            set
            {
                title = value;
                RaisePropertyChanged();
            }
        }

        public void Show()
        {
            Name = "刘备2";
            Title = "windows12";
            MessageBox.Show("Hello world");
        }
    }



本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:
本帖最后由 勇哥,很想停止 于 2024-06-10 10:49:52 编辑

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2025年4月    »
123456
78910111213
14151617181920
21222324252627
282930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864