jface databinding:重写doSetValue方法ComputedValue实现双向多对一的数据绑定

需求说明

如下是一个简单的测试对话框,我们希望当”起始日期”按钮为勾选时,数据对象dataBean的date属性为日期组件DateTime选择的值,否则为null.

先给出DateBean的类定义

    // 具备PropertyChangeSupport支持的JavaBean
    public class DateBean{
        private PropertyChangeSupport support=new PropertyChangeSupport(this);
        public void addPropertyChangeListener(PropertyChangeListener listener) {
            support.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            support.removePropertyChangeListener(listener);
        }

        public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
            support.firePropertyChange(propertyName, oldValue, newValue);
        }

        Date date;

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            System.out.printf("date=%s\n", date);
            firePropertyChange("date", this.date, this.date = date);
        }

ISideEffect

在这个场景中,是两个widget组件的状态绑定到一个数据对象的属性 实现上面的需求,参考我之前的博文《jface databinding:更简单的ISideEffect实现多目标单边数据绑定塈其原理分析》,可以很简单的实现。

    DateTime dateTime=new DateTime(container, SWT.BORDER);
    Button chkDateEnable=new Button(container, SWT.CHECK);
    //。。。。。
    DataBindingContext bindingContext = new DataBindingContext();
    // 创建dateTime日期组件的观察对象
    IObservableValue observeSelectionDateTimeObserveWidget = WidgetProperties.selection().observe(dateTime);
    // 创建chkDateEnable按钮的观察对象
    IObservableValue observeSelectionChkDateEnableObserveWidget = WidgetProperties.selection().observe(chkDateEnable);
    // 创建ISideEffect实现dateTime+chkDateEnable->dateBean.date的单向数据绑定
    ISideEffect.create(()->{
        return (boolean)observeSelectionChkDateEnableObserveWidget.getValue()?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
    }, dateBean::setDate);

ComputedValue

但是,上面的代码只是实现了单向的数据绑定,如果希望在上图中按”恢复缺省值”时,dateBean.date修改后,界面的chkDateEnable和dateTime组件也同步更新,就不能使用ISideEffect了。

我们知道ComputedValue也可以实现单向的多对一数组绑定,

关于ComputedValue,我在另一篇博文中有更详细的介绍《jface databinding:延迟计算–ComputedValue和WritableList使用的例子》

但ComputedValue并没有实现doSetValue方法,所以如果对ComputedValue对象执行setValue方法会抛出UnsupportedOperationException异常,所以ComputedValue是单向的绑定。但是如果我们实现了doSetValue方法,就可以实现双向的数据绑定。

    DateTime dateTime=new DateTime(container, SWT.BORDER);
    Button chkDateEnable=new Button(container, SWT.CHECK);
    //。。。。。
    DataBindingContext bindingContext = new DataBindingContext();
    // 创建dateTime日期组件的观察对象
    IObservableValue observeSelectionDateTimeObserveWidget = WidgetProperties.selection().observe(dateTime);
    // 创建chkDateEnable按钮的观察对象
    IObservableValue observeSelectionChkDateEnableObserveWidget = WidgetProperties.selection().observe(chkDateEnable);
    // 创建ComputedValue对象
    IObservableValue<Date> observableDate = new ComputedValue<Date>(){
        // 重写doSetValue,
        // 当value为null时,chkDateEnable不勾选,dateTime设置为disable
        // value不为null时,chkDateEnable勾选,dateTime设置为enable,并将dateTime组件的日期设置为value的日期
        @Override
        protected void doSetValue(Date value) {
            chkDateEnable.setSelection(null!=value);
            dateTime.setEnabled(null!=value);
            if(null!=value){
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(value);
                dateTime.setDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONDAY), calendar.get(Calendar.DAY_OF_MONTH));
            }                   
        }

        @Override
        protected Date calculate() {
            // 根据chkDateEnable的selection状态,返回Date对象
            // chkDateEnable.selection为true时,返回dateTime的值,设置dateTime为enable
            // chkDateEnable.selection为false时,返回null,设置dateTime为disable
            boolean selection = (boolean)observeSelectionChkDateEnableObserveWidget.getValue();
            dateTime.setEnabled(selection);
            return selection?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
        }

    };
    // 对observableDate对象与dateBean.date属性进行数据绑定
    bindingContext.bindValue(observableDate, dateDateBeanObserveValue, null, null);

完整示例代码

TestComputedValue2 .java

package testwb;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.Calendar;
import java.util.Date;

import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;


import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.sideeffect.ISideEffect;
import org.eclipse.core.databinding.observable.value.ComputedValue;
import org.eclipse.core.databinding.observable.value.IObservableValue;
import org.eclipse.jface.databinding.swt.DisplayRealm;
import org.eclipse.jface.databinding.swt.WidgetProperties;
import org.eclipse.core.databinding.beans.BeanProperties;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class TestComputedValue2 extends Dialog {
    private DataBindingContext m_bindingContext;
    public class DateBean{
        private PropertyChangeSupport support=new PropertyChangeSupport(this);
        public void addPropertyChangeListener(PropertyChangeListener listener) {
            support.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            support.removePropertyChangeListener(listener);
        }

        public void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
            support.firePropertyChange(propertyName, oldValue, newValue);
        }

        Date date;

        public Date getDate() {
            return date;
        }

        public void setDate(Date date) {
            System.out.printf("date=%s\n", date);
            firePropertyChange("date", this.date, this.date = date);
        }
    }
    private DateBean dateBean=new DateBean();
    private DateTime dateTime;
    private Button chkDateEnable;
    /**
     * Create the dialog.
     * @param parentShell
     */
    public TestComputedValue2(Shell parentShell) {
        super(parentShell);
    }

    /**
     * Create contents of the dialog.
     * @param parent
     */
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        container.setLayout(null);

        dateTime = new DateTime(container, SWT.BORDER);
        dateTime.setBounds(86, 95, 88, 24);

        chkDateEnable = new Button(container, SWT.CHECK);
        chkDateEnable.setBounds(10, 99, 70, 17);
        chkDateEnable.setText("起始日期");

        Button btnNewButton = new Button(container, SWT.NONE);
        btnNewButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                dateBean.setDate(new Date());
            }
        });
        btnNewButton.setBounds(10, 167, 80, 27);
        btnNewButton.setText("恢复缺省值");

        return container;
    }

    /**
     * Create contents of the button bar.
     * @param parent
     */
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
        m_bindingContext = initDataBindings();
    }

    /**
     * Return the initial size of the dialog.
     */
    @Override
    protected Point getInitialSize() {
        return new Point(450, 300);
    }
    protected DataBindingContext initDataBindings() {
        DataBindingContext bindingContext = new DataBindingContext();
        //
        IObservableValue observeSelectionDateTimeObserveWidget = WidgetProperties.selection().observe(dateTime);
        IObservableValue observeSelectionChkDateEnableObserveWidget = WidgetProperties.selection().observe(chkDateEnable);
        IObservableValue dateDateBeanObserveValue = BeanProperties.value("date").observe(dateBean);
        //bindingContext.bindValue(observeSelectionDateTimeObserveWidget, dateDateBeanObserveValue, null, null);
        /*IObservableValue<Date> observableDate = ComputedValue.create(()->{
            return chkDateEnable.getSelection()?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
        });*/
        // 创建ComputedValue对象
        IObservableValue<Date> observableDate = new ComputedValue<Date>(){
            // 重写doSetValue,
            // 当value为null时,chkDateEnable不勾选,dateTime设置为disable
            // value不为null时,chkDateEnable勾选,dateTime设置为enable,并将dateTime组件的日期设置为value的日期
            @Override
            protected void doSetValue(Date value) {
                chkDateEnable.setSelection(null!=value);
                dateTime.setEnabled(null!=value);
                if(null!=value){
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(value);
                    dateTime.setDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONDAY), calendar.get(Calendar.DAY_OF_MONTH));
                }                   
            }

            @Override
            protected Date calculate() {
                // 根据chkDateEnable的selection状态,返回Date对象
                // chkDateEnable.selection为true时,返回dateTime的值,设置dateTime为enable
                // chkDateEnable.selection为false时,返回null,设置dateTime为disable
                boolean selection = (boolean)observeSelectionChkDateEnableObserveWidget.getValue();
                dateTime.setEnabled(selection);
                return selection?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
            }

        };
        // 对observableDate对象与dateBean.date属性进行数据绑定
        bindingContext.bindValue(observableDate, dateDateBeanObserveValue, null, null);
        /*ISideEffect.create(()->{
            return (boolean)observeSelectionChkDateEnableObserveWidget.getValue()?(Date)observeSelectionDateTimeObserveWidget.getValue():null;
        }, dateBean::setDate);*/
        //
        return bindingContext;
    }
    public static void main(String[] args) {
        Display display = Display.getDefault();
        Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() {
            public void run() {
                try {
                    TestComputedValue2 setting = new TestComputedValue2(null);
                    setting.open();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菩提树下的杨过

Blend生成的TransformGroup如何引用?

很多时候,blend在制作动画时,会自动为对象生成如下代码: <Rectangle Fill="White" Stroke="Black" Horizontal...

1719
来自专栏菩提树下的杨过

温故而知新:设计模式之原型模式(Prototype)

原型模式个人以为最适合的场景:参照现有的某一个对象实例,快速得到多个完整的实例副本。(通常是深拷贝的副本) 深拷贝在c#中实现的最简单方式莫过于通过反序列化得到...

2185
来自专栏帘卷西风的专栏

关于cocos2dx之lua使用TableView

在手机游戏的开发中,滚动是一项非常重要的操作,而cocos2dx中使用的最广泛的就属于TableView了,不过由于cocos2dx的接口比较晦涩,所以需要一...

762
来自专栏木宛城主

庖丁解牛——深入解析委托和事件

这篇博文我不讲委托和事件的概念,因为大段的文字概念没有任何意义。 具体想了解,委托和事件的概念可以MSDN查阅。 我这篇文章的主题思路是委托如何一步步进化...

41610
来自专栏更流畅、简洁的软件开发方式

基类、接口的应用——表单控件:一次添加、修改一条记录,一次修改多条记录。(上)

好久没发帖子了,又加了不少的功能呀。(图片仅是测试,不代表什么表情。) 本来我也想写一个2007的总结的,但是看到很多人都写了,我就不凑热闹了,写点和代码有关...

1725
来自专栏程序你好

CSharp代码示例每日一讲: 在GDI+中使用填充Fill方法

572
来自专栏菩提树下的杨过

Flash/Flex学习笔记(34):AS3中的自定义事件

类似C#中自定义事件需要一个自定义的EventArgs子类一样,AS3也需要开发者自定义一个Event类的子类,这里我们假设一种场景:设计一个Person(人物...

1707
来自专栏草根专栏

设计模式学习(一):多用组合少用继承(C#)

《深入浅出设计模式》学习笔记第一章 原始需求和设计 事情是这样开始的,公司需要做一套程序,鸭子,设计如下: ? 一个鸭子父类,多个派生类,三个可override...

3244
来自专栏程序员的SOD蜜

使用泛型委托,构筑最快的通用属性访问器

最近做一个父类的属性向子类的属性赋值的小程序,用了下AutoMapper组件,感觉不错,想探究下它的原理,自己动手做一个例子试试看。实现这个功能,第一反应使用反...

2259
来自专栏编程之旅

数据结构——链表的游标实现(C语言)

上一篇博文我们用指针实现了链表,但是诸如BASIC和FORTRAN等许多语言都不支持指针。如果需要链表而又不能使用指针,这时我们可以使用游标(cursor)实现...

701

扫码关注云+社区