WPF通过INotifyPropertyChanged增强双向绑定

2 篇文章 0 订阅

简介

重写D3dPotrace的UI界面, 要实现以下功能
1. 拖动滑条时右面的文本框随之变化
2. 修改参数时下面的图像随之变化
3. 通过按钮可以设置默认值

这里写图片描述

数据绑定的问题

数据绑定就使用VM模式, 举一个例子

// PotraceParams.cs
namespace PotraceUI
{
    class PotraceParams
    {
        public int IgnoreAreaPixels;
        public double Tolerance;
        public double CornerThreshold;
        public int Threshold;
        public int TurnPolicy;
        public bool Optimizing;

        // ...
    }

    class PotraceParamsVM
    {
        private PotraceParams obj = new PotraceParams();

        public string IgnoreAreaPixels
        {
            get { return obj.IgnoreAreaPixels.ToString(); }
            set {
                ConvertHelper.String2IntCheck(value, ref obj.IgnoreAreaPixels);
            }
        }

        // ...

    }
}
// MainWindow.xaml.cs
txtIgnoreArea.Binding(paramsVM, "IgnoreAreaPixels");
/// Utils.cs
namespace PotraceUI
{
    static public class BindingHelper
    {

        static public void Binding(this TextBox control, object obj, string property)
        {
            var _binding = new Binding
            {
                Source = obj,
                Path = new PropertyPath(property)
            };
            control.SetBinding(TextBox.TextProperty, _binding);
        }

        //...
    }
}

这样做有什么问题?
只使用控件来修改参数(单向绑定)时完全没有问题…要反过来很麻烦
1. 修改默认值, 控件的值不会显示
2. 滑动条和文本框不好联动

一开始只给滑动条右边的文本框绑定到数据源,滑动条使用Value="{Binding ElementName=txtThreshold,Path=Text}"来绑定到文本框元素,看起来挺棒的

设置为默认值的问题

设置为默认值真的很简单,只需要

class PotraceParams
{
    public void SetDefaultValues()
    {
        IgnoreAreaPixels = 2;
        Tolerance = 0.2;
        CornerThreshold = 1.0;
        Optimizing = true;
        TurnPolicy = 0;
        Threshold = 50;
    }
}

但这样变化传递不到UI控件上。
实现INotifyPropertyChanged接口即可

class PotraceParamsVM : INotifyPropertyChanged
{
    private PotraceParams obj = new PotraceParams();

    public event PropertyChangedEventHandler PropertyChanged;
    public void SetDefaultValues()
    {
        obj.SetDefaultValues();
        PropertyChanged(this, new PropertyChangedEventArgs("IgnoreAreaPixels"));
        PropertyChanged(this, new PropertyChangedEventArgs("Tolerance"));
        PropertyChanged(this, new PropertyChangedEventArgs("CornerThreshold"));
        PropertyChanged(this, new PropertyChangedEventArgs("Optimizing"));
        PropertyChanged(this, new PropertyChangedEventArgs("TurnPolicy"));
        PropertyChanged(this, new PropertyChangedEventArgs("Threshold"));
    }
}

将属性变化时间发送出去,UI接受后更新控件的值

随参数变化刷新预览

这是一个显然的Observer模式…

    public partial class MainWindow : Window
    {
        private PotraceParamsVM paramsVM = new PotraceParamsVM();

        public MainWindow()
        {
            InitializeComponent();
            InitializeControls();
            paramsVM.PropertyChanged += new PropertyChangedEventHandler(ParamsObserver);
        }

        private void ParamsObserver(object sender, PropertyChangedEventArgs e)
        {
            ((PotraceParamsVM)sender).ExportParams();
            RefreshImages();
        }

这样就搞定了

再来说滑动条数据绑定的问题

仍然在只给文本框绑定数据源的状态下:
要让预览刷新,添加一个事件监听

private void InitializeControls()
{
    sdThreshold.AddHandler(Slider.ValueChangedEvent, new RoutedEventHandler(SliderObserver), true);
}

private void SliderObserver(object sender, RoutedEventArgs e)
{
    paramsVM.ExportParams();
    RefreshImages();
}

拖动滑动条预览不断刷新,然而并没有什么用,图像根本就没有变化
滑动条的修改根本没有传递到数据源
上面的Binding方式,只有手动修改控件的值时才会传递给数据源(猜测可能是失焦事件触发),通过其他方式修改值并不会传递,需要再加一个数据绑定
删除之前在xaml中到元素的绑定,再进行修改

// PotraceParams.cs
        public string Threshold
        {
            get { return obj.Threshold.ToString(); }
            set {
                ConvertHelper.String2IntCheck(value, ref obj.Threshold, 0, 100);
                PropertyChanged(this, new PropertyChangedEventArgs("Threshold"));
                PropertyChanged(this, new PropertyChangedEventArgs("ThresholdInt"));
            }
        }

        public int ThresholdInt
        {
            get { return obj.Threshold; }
            set
            {
                obj.Threshold = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Threshold"));
                PropertyChanged(this, new PropertyChangedEventArgs("ThresholdInt"));
            }
        }
sdThreshold.Binding(paramsVM, "ThresholdInt");

要让滑动条和文本框一起活动,就要多增加一个通知事件了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值