|
//------------------------------------------------------------------------------
// <copyright file="BindToObject.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Windows.Forms {
using System;
using Microsoft.Win32;
using System.Diagnostics;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
internal class BindToObject {
private PropertyDescriptor fieldInfo;
private BindingMemberInfo dataMember;
private Object dataSource;
private BindingManagerBase bindingManager;
private Binding owner;
private string errorText = string.Empty;
private bool dataSourceInitialized = false;
private bool waitingOnDataSource = false;
private void PropValueChanged(object sender, EventArgs e) {
if(this.bindingManager != null) {
this.bindingManager.OnCurrentChanged(EventArgs.Empty);
}
}
private bool IsDataSourceInitialized {
get {
Debug.Assert(this.dataSource != null, "how can we determine if DataSource is initialized or not if we have no data source?");
if (this.dataSourceInitialized) {
return true;
}
ISupportInitializeNotification ds = this.dataSource as ISupportInitializeNotification;
if (ds == null || ds.IsInitialized) {
this.dataSourceInitialized = true;
return true;
}
// We have an ISupportInitializeNotification which was not initialized yet.
// We already hooked up the Initialized event and the data source is not initialized yet.
if (this.waitingOnDataSource) {
return false;
}
// Hook up the Initialized event.
ds.Initialized += new EventHandler(DataSource_Initialized);
this.waitingOnDataSource = true;
return false;
}
}
internal BindToObject(Binding owner, Object dataSource, string dataMember) {
this.owner = owner;
this.dataSource = dataSource;
this.dataMember = new BindingMemberInfo(dataMember);
CheckBinding();
}
private void DataSource_Initialized(object sender, EventArgs e) {
Debug.Assert(sender == this.dataSource, "data source should not change");
Debug.Assert(this.dataSource is ISupportInitializeNotification, "data source should not change on the BindToObject");
Debug.Assert(this.waitingOnDataSource);
ISupportInitializeNotification ds = this.dataSource as ISupportInitializeNotification;
// Unhook the Initialized event.
if (ds != null) {
ds.Initialized -= new EventHandler(DataSource_Initialized);
}
// The wait is over: DataSource is initialized.
this.waitingOnDataSource = false;
this.dataSourceInitialized = true;
// Rebind.
CheckBinding();
}
internal void SetBindingManagerBase(BindingManagerBase lManager) {
if (bindingManager == lManager)
{
return;
}
// remove notification from the backEnd
if (bindingManager != null && fieldInfo != null && bindingManager.IsBinding && !(bindingManager is CurrencyManager)) {
fieldInfo.RemoveValueChanged(bindingManager.Current, new EventHandler(PropValueChanged));
fieldInfo = null;
}
this.bindingManager = lManager;
CheckBinding();
}
internal string DataErrorText
{
get
{
return this.errorText;
}
}
// Returns any data error info on the data source for the bound data field in the current row
string GetErrorText(object value) {
IDataErrorInfo errorInfo = value as IDataErrorInfo;
string text = string.Empty;
if (errorInfo != null) {
// Get the row error if there is no DataMember
if (fieldInfo == null) {
text = errorInfo.Error;
}
// Get the column error if there is a DataMember.
// The DataTable uses its own Locale to lookup column names <sigh>.
// So passing the DataMember from the BindingField could cause problems.
// Pass the name from the PropertyDescriptor that the DataTable gave us.
// (If there is no fieldInfo, data binding would have failed already )
else {
text = errorInfo[fieldInfo.Name];
}
}
return text ?? string.Empty;
}
internal Object GetValue() {
object obj = bindingManager.Current;
// Update IDataErrorInfo text: it's ok to get this now because we're going to need
// this as part of the BindingCompleteEventArgs anyway.
this.errorText = GetErrorText(obj);
if (fieldInfo != null) {
obj = fieldInfo.GetValue(obj);
}
return obj;
}
internal Type BindToType {
get {
if (dataMember.BindingField.Length == 0) {
// if we are bound to a list w/o any properties, then
// take the type from the BindingManager
Type type = this.bindingManager.BindType;
if (typeof(Array).IsAssignableFrom(type))
type = type.GetElementType();
return type;
}
else
return fieldInfo == null ? null : fieldInfo.PropertyType;
}
}
internal void SetValue(Object value) {
object obj = null;
if (fieldInfo != null) {
obj = bindingManager.Current;
if (obj is IEditableObject)
((IEditableObject) obj).BeginEdit();
//(bug 112947) .. checkif the Column is readonly while pushing data...
if (!fieldInfo.IsReadOnly) {
fieldInfo.SetValue(obj, value);
}
}
else {
CurrencyManager cm = bindingManager as CurrencyManager;
if (cm != null)
{
cm[cm.Position] = value;
obj = value;
}
}
// Update IDataErrorInfo text.
this.errorText = GetErrorText(obj);
}
internal BindingMemberInfo BindingMemberInfo {
get {
return this.dataMember;
}
}
internal Object DataSource {
get {
return dataSource;
}
}
internal PropertyDescriptor FieldInfo {
get {
return fieldInfo;
}
}
internal BindingManagerBase BindingManagerBase {
get {
return this.bindingManager;
}
}
internal void CheckBinding() {
// At design time, don't check anything.
//
if (owner != null &&
owner.BindableComponent != null &&
owner.ControlAtDesignTime()) {
return;
}
// force Column to throw if it's currently a bad column.
//DataColumn tempColumn = this.Column;
// remove propertyChangedNotification when this binding is deleted
if (this.owner.BindingManagerBase != null &&
this.fieldInfo != null &&
this.owner.BindingManagerBase.IsBinding &&
!(this.owner.BindingManagerBase is CurrencyManager)) {
fieldInfo.RemoveValueChanged(owner.BindingManagerBase.Current, new EventHandler(PropValueChanged));
}
if (owner != null &&
owner.BindingManagerBase != null &&
owner.BindableComponent != null &&
owner.ComponentCreated &&
this.IsDataSourceInitialized) {
string dataField = dataMember.BindingField;
fieldInfo = owner.BindingManagerBase.GetItemProperties().Find(dataField, true);
if (owner.BindingManagerBase.DataSource != null && fieldInfo == null && dataField.Length > 0) {
throw new ArgumentException(SR.GetString(SR.ListBindingBindField, dataField), "dataMember");
}
// Do not add propertyChange notification if
// the fieldInfo is null
//
// we add an event handler to the dataSource in the BindingManagerBase because
// if the binding is of the form (Control, ControlProperty, DataSource, Property1.Property2.Property3)
// then we want to get notification from Current.Property1.Property2 and not from DataSource
// when we get the backEnd notification we push the new value into the Control's property
//
if (fieldInfo != null &&
owner.BindingManagerBase.IsBinding &&
!(this.owner.BindingManagerBase is CurrencyManager)) {
fieldInfo.AddValueChanged(this.owner.BindingManagerBase.Current, new EventHandler(PropValueChanged));
}
}
else {
fieldInfo = null;
}
}
}
}
|