jface databinding:输入无效数值时强制恢复初始值-updateModelToTarget
2016-12-27 15:11
411 查看
解决方案
Binding类中的updateModelToTarget方法,就是实现从数据对象到目标对象(比如Widget)的更新方法,只要调用这个方法就能强制让数据对象的内容同步到目标对象。如下是抽象方法updateModelToTarget的说明:/** * Updates the target's state from the model's state at the next reasonable * opportunity. There is no guarantee that the state will have been updated * by the time this call returns. * 在合适的机会将model状态更新到target,因为是异步更新,所以不保证当方法返回时target更新完成。 */ public abstract void updateModelToTarget();
问题描述
如下代码显示一个简单的对话框,Text文本框中初始是个浮点数0.5,当修改文本框中的内容不符合float数值格式时,左上角会提示出错。点击下面的”恢复初始值”按钮,希望能恢复初始值0.5。package testwb; 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.SWT; import org.eclipse.swt.widgets.Text; import org.eclipse.core.databinding.Binding; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.observable.value.IObservableValue; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.jface.databinding.swt.WidgetProperties; import org.eclipse.swt.widgets.Display; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.jface.databinding.fieldassist.ControlDecorationSupport; import org.eclipse.jface.databinding.swt.DisplayRealm; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; public class TestPojoBinding5 extends Dialog { private DataBindingContext m_bindingContext; // floatValue 初始值0.5f private final WritableValue<Float> floatValue = new WritableValue<Float>(Float.valueOf(0.5f), Float.class); // Text文本框对象 private Text floatValueText; private Binding bindValue; /** * Create the dialog. * @param parentShell */ public TestPojoBinding5(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); Button btnNewButton = new Button(container, SWT.NONE); // 点击“恢复初始值”按钮时,将floatValue重新设置为初始值 btnNewButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { floatValue.setValue(Float.valueOf(0.5f)); } }); btnNewButton.setBounds(38, 154, 80, 27); btnNewButton.setText("恢复初始值"); floatValueText = new Text(container, SWT.BORDER); floatValueText.setBounds(38, 27, 80, 23); 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(362, 298); } public static void main(String[] args) { Display display = Display.getDefault(); Realm.runWithDefault(DisplayRealm.getRealm(display), new Runnable() { public void run() { try { TestPojoBinding5 setting = new TestPojoBinding5(null); setting.open(); } catch (Exception e) { e.printStackTrace(); } } }); } protected DataBindingContext initDataBindings() { DataBindingContext bindingContext = new DataBindingContext(); // IObservableValue observeTextFloatValueTextObserveWidget = WidgetProperties.text(SWT.Modify).observe(floatValueText); // 将floatValueText和floatValue进行数据绑定 bindValue=bindingContext.bindValue(observeTextFloatValueTextObserveWidget, floatValue, null, null); // 创建验证错误提示组件(就是Text文本框左上角的红X号,数据验证出错时显示), ControlDecorationSupport.create(bindValue, SWT.TOP | SWT.LEFT); return bindingContext; } }
实际的结果是:
当修改Text文本框内容为一个合法的浮点数时,点击”恢复初始值”按钮Text显示内容的确可以恢复到初始值0.5,
但是当输入的内容无效,不是一个数字时,点击”恢复初始值”按钮也恢复不到初始值?
这是为什么呢?难道jface有bug?
问题溯源
通过跟踪代码搞清楚了原因:假设当前Text的内容是初始值0.5,然后修改Text的内容,
不论Text文本框的内容是否为有效数字,点击”恢复初始值”按钮时,
floatValue.setValue(Float.valueOf(0.5f));确实被执行了,
但区别是当输入Text文本框的内容为无效数字时,floatValue的内容并不会被修改,也就是还保持之前的值(0.5),此时再点击”恢复初始值”按钮时,设置的值还是0.5,floatValue并没有改变,所以没有触发Text的更新。
再做一个试验来验证上面的逻辑:
如果先将Text的内容从0.5改为另一个有效数字(比如0.9)—(此时floatValue被更新为0.9),然后再改为一个无效数字hello,然后点击”恢复初始值”按钮,则Text的内容正常恢复。
由此找出了问题的原因:当数据对象更新的值与原值相等时,setValue不能触发Widget组件的更新。
怎么解决呢?仔细研究了,
org.eclipse.core.databinding.ValueBinding代码中的数据更新的方法doUpdate,及其调用层次结构,由此就找到了本文开始的答案。
ValueBinding继承于抽象类Binding,Binding类中的updateModelToTarget方法,就是实现从数据对象到目标对象(比如Widget)的更新方法,只要调用这个方法就能强制让数据对象的内容同步到目标对象。
修改代码
所以解决这个问题的办法很简单,如下增加一行代码即可:// 点击“恢复初始值”按钮时,将floatValue重新设置为初始值 btnNewButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { floatValue.setValue(Float.valueOf(0.5f)); // 强制更新Text组件内容 bindValue.updateModelToTarget(); } });
当然仔细想想上面这样修改的确是简单,但在Text已经被更新的情况下,会多一次强制更新的动作,所以如果代码写得更仔细点,应该是这样:
// 点击“恢复初始值”按钮时,将floatValue重新设置为初始值 btnNewButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { // 判断floatValue是否等于初始值(0.5f),如果是的话,只做强制更新 if(floatValue.getValue()==0.5f) bindValue.updateModelToTarget(); else// 否则就更新floatValue,Text会自动更新。 floatValue.setValue(Float.valueOf(0.5f)); } });
相关文章推荐
- jface databinding:UpdateValueStrategy(数值更新策略)类详解
- jface databinding:构建一个改进版的通用型数值验证器StringToNumberValidator
- Sprinig.net 双向绑定 Bidirectional data binding and data model management 和 UpdatePanel
- SQL Server 2008 Entity Data Model 和 Linq to Entities
- Binding a Scalar Array to a Data Web Control
- Performing Data Access->Binding to Databases
- Performing Data Access->Binding to Objects
- eclipse超cool新特性--JFace Data Binding
- Asp.Net Mvc: Model Binding to Simple Types, Complex Types, Collections, Dictionaries, Etc
- 用 devenv.exe /resetuserdata 恢复Visual Studio 初始状态
- 【转载】LINQ to SQL (Part 2 - Defining our Data Model Classes)
- 对象的当前状态使该操作无效 or SPListItem Update Operation is not valid due to the current state of the object
- eclipse超cool新特性--JFace Data Binding
- Example chaining to logical file to write/update data
- 比较LINQ to SQL Diagram 和Entity Data Model
- 转:用 devenv.exe /resetuserdata 恢复Visual Studio 初始状态
- "Failed to update database "c:\inetpub\wwwroot\WebSite1\App_Data\ASPNETDB.MDF" because the database is read-only."的解决办法
- eclipse超cool新特性--JFace Data Binding
- LINQ to SQL (Part 2 - Defining our Data Model Classes)
- SPListItem Update Operation is not valid due to the current state of the object(对象的当前状态使该操作无效。)