Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / PropertyGridInternal / MergePropertyDescriptor.cs / 1 / MergePropertyDescriptor.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//-----------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms.PropertyGridInternal {
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.ComponentModel;
using System.Diagnostics;
using System;
using System.IO;
using System.Collections;
using System.Globalization;
using System.Reflection;
using System.ComponentModel.Design;
using System.ComponentModel.Design.Serialization;
using System.Windows.Forms;
using System.Drawing;
using Microsoft.Win32;
internal class MergePropertyDescriptor : PropertyDescriptor {
private PropertyDescriptor[] descriptors;
private enum TriState {
Unknown,
Yes,
No
}
private TriState localizable = TriState.Unknown;
private TriState readOnly = TriState.Unknown;
private TriState canReset = TriState.Unknown;
private MultiMergeCollection collection;
public MergePropertyDescriptor(PropertyDescriptor[] descriptors) : base(descriptors[0].Name, null) {
this.descriptors = descriptors;
}
///
///
///
/// When overridden in a derived class, gets the type of the
/// component this property
/// is bound to.
///
///
public override Type ComponentType {
get {
return descriptors[0].ComponentType;
}
}
///
///
///
/// Gets the type converter for this property.
///
///
public override TypeConverter Converter {
get {
return descriptors[0].Converter;
}
}
public override string DisplayName {
get {
return descriptors[0].DisplayName;
}
}
///
///
///
/// Gets a value
/// indicating whether this property should be localized, as
/// specified in the .
///
///
public override bool IsLocalizable {
get {
if (localizable == TriState.Unknown) {
localizable = TriState.Yes;
foreach (PropertyDescriptor pd in descriptors) {
if (!pd.IsLocalizable) {
localizable = TriState.No;
break;
}
}
}
return (localizable == TriState.Yes);
}
}
///
///
///
/// When overridden in
/// a derived class, gets a value
/// indicating whether this property is read-only.
///
///
public override bool IsReadOnly {
get {
if (readOnly == TriState.Unknown) {
readOnly = TriState.No;
foreach (PropertyDescriptor pd in descriptors) {
if (pd.IsReadOnly) {
readOnly = TriState.Yes;
break;
}
}
}
return (readOnly == TriState.Yes);
}
}
///
///
///
/// When overridden in a derived class,
/// gets the type of the property.
///
///
public override Type PropertyType {
get {
return descriptors[0].PropertyType;
}
}
public PropertyDescriptor this[int index] {
get {
return descriptors[index];
}
}
///
///
///
/// When overridden in a derived class, indicates whether
/// resetting the will change the value of the
/// .
///
///
public override bool CanResetValue(object component) {
Debug.Assert(component is Array, "MergePropertyDescriptor::CanResetValue called with non-array value");
if (canReset == TriState.Unknown) {
canReset = TriState.Yes;
Array a = (Array)component;
for (int i = 0; i < descriptors.Length; i++) {
if (!descriptors[i].CanResetValue(GetPropertyOwnerForComponent(a, i))) {
canReset = TriState.No;
break;
}
}
}
return (canReset == TriState.Yes);
}
///
/// This method attempts to copy the given value so unique values are
/// always passed to each object. If the object cannot be copied it
/// will be returned.
///
private object CopyValue(object value) {
// null is always OK
if (value == null) {
return value;
}
Type type = value.GetType();
// value types are always copies
if (type.IsValueType) {
return value;
}
object clonedValue = null;
// ICloneable is the next easiest thing
ICloneable clone = value as ICloneable;
if (clone != null) {
clonedValue = clone.Clone();
}
// Next, access the type converter
if (clonedValue == null) {
TypeConverter converter = TypeDescriptor.GetConverter(value);
if (converter.CanConvertTo(typeof(InstanceDescriptor))) {
// Instance descriptors provide full fidelity unless
// they are marked as incomplete.
InstanceDescriptor desc = (InstanceDescriptor)converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(InstanceDescriptor));
if (desc != null && desc.IsComplete) {
clonedValue = desc.Invoke();
}
}
// If that didn't work, try conversion to/from string
if (clonedValue == null && converter.CanConvertTo(typeof(string)) && converter.CanConvertFrom(typeof(string))) {
object stringRep = converter.ConvertToInvariantString(value);
clonedValue = converter.ConvertFromInvariantString((string)stringRep);
}
}
// How about serialization?
if (clonedValue == null && type.IsSerializable) {
BinaryFormatter f = new BinaryFormatter();
MemoryStream ms = new MemoryStream();
f.Serialize(ms, value);
ms.Position = 0;
clonedValue = f.Deserialize(ms);
}
if (clonedValue != null) {
return clonedValue;
}
// we failed. This object's reference will be set on each property.
return value;
}
///
///
///
/// Creates a collection of attributes using the
/// array of attributes that you passed to the constructor.
///
///
protected override AttributeCollection CreateAttributeCollection() {
return new MergedAttributeCollection(this);
}
private object GetPropertyOwnerForComponent(Array a, int i) {
object propertyOwner = a.GetValue(i);
if (propertyOwner is ICustomTypeDescriptor) {
propertyOwner = ((ICustomTypeDescriptor) propertyOwner).GetPropertyOwner(descriptors[i]);
}
return propertyOwner;
}
///
///
///
/// Gets an editor of the specified type.
///
///
public override object GetEditor(Type editorBaseType) {
return descriptors[0].GetEditor(editorBaseType);
}
///
///
///
/// When overridden in a derived class, gets the current
/// value
/// of the
/// property on a component.
///
///
public override object GetValue(object component) {
Debug.Assert(component is Array, "MergePropertyDescriptor::GetValue called with non-array value");
bool temp;
return GetValue((Array)component, out temp);
}
public object GetValue(Array components, out bool allEqual) {
allEqual = true;
object obj = descriptors[0].GetValue(GetPropertyOwnerForComponent(components, 0));
if (obj is ICollection) {
if (collection == null) {
collection = new MultiMergeCollection((ICollection)obj);
}
else if (collection.Locked) {
return collection;
}
else {
collection.SetItems((ICollection)obj);
}
}
for (int i = 1; i < descriptors.Length; i++) {
object objCur = descriptors[i].GetValue(GetPropertyOwnerForComponent(components, i));
if (collection != null) {
if (!collection.MergeCollection((ICollection)objCur)){
allEqual = false;
return null;
}
}
else if ((obj == null && objCur == null) ||
(obj != null && obj.Equals(objCur))) {
continue;
}
else {
allEqual = false;
return null;
}
}
if (allEqual && collection != null && collection.Count == 0) {
return null;
}
return (collection != null ? collection : obj);
}
internal object[] GetValues(Array components) {
object[] values = new object[components.Length];
for (int i = 0; i < components.Length; i++) {
values[i] = descriptors[i].GetValue(GetPropertyOwnerForComponent(components, i));
}
return values;
}
///
///
///
/// When overridden in a derived class, resets the
/// value
/// for this property
/// of the component.
///
///
public override void ResetValue(object component) {
Debug.Assert(component is Array, "MergePropertyDescriptor::ResetValue called with non-array value");
Array a = (Array)component;
for (int i = 0; i < descriptors.Length; i++) {
descriptors[i].ResetValue(GetPropertyOwnerForComponent(a, i));
}
}
private void SetCollectionValues(Array a, IList listValue) {
try {
if (collection != null) {
collection.Locked = true;
}
// now we have to copy the value into each property.
object[] values = new object[listValue.Count];
listValue.CopyTo(values, 0);
for (int i = 0; i < descriptors.Length; i++) {
IList propList = descriptors[i].GetValue(GetPropertyOwnerForComponent(a, i)) as IList;
if (propList == null) {
continue;
}
propList.Clear();
foreach (object val in values) {
propList.Add(val);
}
}
}
finally {
if (collection != null) {
collection.Locked = false;
}
}
}
///
///
///
/// When overridden in a derived class, sets the value of
/// the component to a different value.
///
///
public override void SetValue(object component, object value) {
Debug.Assert(component is Array, "MergePropertyDescriptor::SetValue called with non-array value");
Array a = (Array)component;
if (value is IList && typeof(IList).IsAssignableFrom(PropertyType)) {
SetCollectionValues(a, (IList)value);
}
else {
for (int i = 0; i < descriptors.Length; i++) {
object clonedValue = CopyValue(value);
descriptors[i].SetValue(GetPropertyOwnerForComponent(a, i), clonedValue);
}
}
}
///
///
///
/// When overridden in a derived class, indicates whether the
/// value of
/// this property needs to be persisted.
///
///
public override bool ShouldSerializeValue(object component) {
Debug.Assert(component is Array, "MergePropertyDescriptor::ShouldSerializeValue called with non-array value");
Array a = (Array)component;
for (int i = 0; i < descriptors.Length; i++) {
if (!descriptors[i].ShouldSerializeValue(GetPropertyOwnerForComponent(a, i))) {
return false;
}
}
return true;
}
private class MultiMergeCollection : ICollection {
private object[] items;
private bool locked;
public MultiMergeCollection(ICollection original) {
SetItems(original);
}
///
///
/// Retrieves the number of items.
///
public int Count {
get {
if (items != null) {
return items.Length;
}
else {
return 0;
}
}
}
///
///
/// Prevents the contents of the collection from being re-initialized;
///
public bool Locked {
get {
return locked;
}
set {
this.locked = value;
}
}
object ICollection.SyncRoot {
get {
return this;
}
}
bool ICollection.IsSynchronized {
get {
return false;
}
}
public void CopyTo(Array array, int index) {
if (items == null) return;
Array.Copy(items, 0, array, index, items.Length);
}
public IEnumerator GetEnumerator(){
if (items != null) {
return items.GetEnumerator();
}
else {
return new object[0].GetEnumerator();
}
}
///
///
/// Ensures that the new collection equals the exisitng one.
/// Otherwise, it wipes out the contents of the new collection.
///
public bool MergeCollection(ICollection newCollection) {
if (locked) {
return true;
}
if (items.Length != newCollection.Count) {
items = new object[0];
return false;
}
object[] newItems = new object[newCollection.Count];
newCollection.CopyTo(newItems, 0);
for (int i = 0;i < newItems.Length; i++) {
if (((newItems[i] == null) != (items[i] == null)) ||
(items[i] != null && !items[i].Equals(newItems[i]))){
items = new object[0];
return false;
}
}
return true;
}
public void SetItems(ICollection collection) {
if (locked) {
return;
}
items = new object[collection.Count];
collection.CopyTo(items, 0);
}
}
private class MergedAttributeCollection : AttributeCollection {
private MergePropertyDescriptor owner;
private AttributeCollection[] attributeCollections = null;
private IDictionary foundAttributes = null;
public MergedAttributeCollection(MergePropertyDescriptor owner) : base((Attribute[])null) {
this.owner = owner;
}
public override Attribute this[Type attributeType] {
get {
return GetCommonAttribute(attributeType);
}
}
#if false
private void FullMerge() {
Attribute[][] collections = new Attribute[owner.descriptors.Length][];
for (int i = 0; i < owner.descriptors.Length; i++) {
AttributeCollection attrCollection = owner.descriptors[i].Attributes;
collections[i] = new Attribute[attrCollection.Count];
attrCollection.CopyTo(collections[i], 0);
Array.Sort(collections[i], GridEntry.AttributeTypeSorter);
}
ArrayList mergedList = new ArrayList();
// merge the sorted lists -- note that lists aren't fully sorted just by
// Attribute.TypeId
//
int[] posArray = new int[collections.Length];
for (int i = 0; i < collections[0].Length; i++) {
Attribute pivotAttr = collections[0][i];
bool match = true;
for (int j = 1; j < collections.Length; j++) {
if (posArray[j] >= collections[j].Length) {
match = false;
break;
}
// check to see if we're on a match
//
if (pivotAttr.Equals(collections[j][posArray[j]])) {
posArray[j] += 1;
continue;
}
int jPos = posArray[j];
Attribute jAttr = collections[j][jPos];
match = false;
// if we aren't on a match, check all the items until we're past
// where the matching item would be
while (GridEntry.AttributeTypeSorter.Compare(jAttr, pivotAttr) <= 0) {
// got a match!
if (pivotAttr.Equals(jAttr)) {
posArray[j] = jPos + 1;
match = true;
break;
}
// try again
jPos++;
if (jPos < collections[j].Length) {
jAttr = collections[j][jPos];
}
else {
break;
}
}
// if we got here, there is no match, quit for this guy
if (!match) {
posArray[j] = jPos;
break;
}
}
// do we have a match?
if (match) {
mergedList.Add(pivotAttr);
}
}
// create our merged array
Attribute[] mergedAttrs = new Attribute[mergedList.Count];
mergedList.CopyTo(mergedAttrs, 0);
}
#endif
private Attribute GetCommonAttribute(Type attributeType) {
if (attributeCollections == null) {
attributeCollections = new AttributeCollection[owner.descriptors.Length];
for (int i = 0; i < owner.descriptors.Length; i++) {
attributeCollections[i] = owner.descriptors[i].Attributes;
}
}
if (attributeCollections.Length == 0) {
return GetDefaultAttribute(attributeType);
}
Attribute value;
if (foundAttributes != null) {
value = foundAttributes[attributeType] as Attribute;
if (value != null) {
return value;
}
}
value = attributeCollections[0][attributeType];
if (value == null) {
return null;
}
for (int i = 1; i < attributeCollections.Length; i++) {
Attribute newValue = attributeCollections[i][attributeType];
if (!value.Equals(newValue)) {
value = GetDefaultAttribute(attributeType);
break;
}
}
if (foundAttributes == null) {
foundAttributes = new Hashtable();
}
foundAttributes[attributeType] = value;
return value;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DataGridViewSelectedCellCollection.cs
- ColumnHeaderConverter.cs
- LoadGrammarCompletedEventArgs.cs
- BufferedStream.cs
- DataGridViewCellMouseEventArgs.cs
- ObjectCloneHelper.cs
- IndexedEnumerable.cs
- wmiprovider.cs
- NativeMethods.cs
- TreeNodeBinding.cs
- WsatAdminException.cs
- DebuggerAttributes.cs
- Semaphore.cs
- SystemIcmpV4Statistics.cs
- JsonFormatWriterGenerator.cs
- EmissiveMaterial.cs
- CodeTypeParameterCollection.cs
- DefaultValueTypeConverter.cs
- FontFamilyValueSerializer.cs
- TextServicesHost.cs
- GridView.cs
- RequestFactory.cs
- StoryFragments.cs
- DataKeyCollection.cs
- CodeArgumentReferenceExpression.cs
- ImportFileRequest.cs
- XmlSchemaAttributeGroup.cs
- MenuItem.cs
- JsonStringDataContract.cs
- WebConfigurationHost.cs
- _CommandStream.cs
- ColorConvertedBitmapExtension.cs
- LoginView.cs
- Fonts.cs
- GeneralTransform2DTo3D.cs
- XmlILIndex.cs
- StrokeCollectionConverter.cs
- WebServiceEnumData.cs
- DataTransferEventArgs.cs
- FontStretchConverter.cs
- SafeTimerHandle.cs
- DbFunctionCommandTree.cs
- IdnElement.cs
- HtmlValidatorAdapter.cs
- IdleTimeoutMonitor.cs
- DefaultHttpHandler.cs
- XmlSerializationWriter.cs
- XmlArrayItemAttribute.cs
- PageThemeBuildProvider.cs
- VirtualPathUtility.cs
- IntranetCredentialPolicy.cs
- TemplateInstanceAttribute.cs
- DataViewManagerListItemTypeDescriptor.cs
- ClientBuildManagerCallback.cs
- InputQueue.cs
- _HelperAsyncResults.cs
- VoiceChangeEventArgs.cs
- PropertyInfo.cs
- OpCodes.cs
- WebReference.cs
- Int16Storage.cs
- LabelLiteral.cs
- httpstaticobjectscollection.cs
- assemblycache.cs
- ListViewCommandEventArgs.cs
- WindowsSpinner.cs
- ContractCodeDomInfo.cs
- DocumentPageTextView.cs
- XamlTreeBuilder.cs
- StatusBar.cs
- WarningException.cs
- CacheOutputQuery.cs
- DateTimePickerDesigner.cs
- TraceLevelStore.cs
- SafeBuffer.cs
- CollectionViewProxy.cs
- MimePart.cs
- ReadOnlyCollection.cs
- SecureEnvironment.cs
- OdbcFactory.cs
- XmlDataSourceView.cs
- DataGridViewColumnHeaderCell.cs
- TemplatingOptionsDialog.cs
- SignedPkcs7.cs
- CodePageEncoding.cs
- TablePatternIdentifiers.cs
- NativeWrapper.cs
- IndexedGlyphRun.cs
- QilCloneVisitor.cs
- CodeExpressionCollection.cs
- XmlSecureResolver.cs
- GeometryModel3D.cs
- Hex.cs
- TableCell.cs
- VerificationException.cs
- StaticContext.cs
- ProtectedConfigurationSection.cs
- TimeSpanValidator.cs
- ProtocolViolationException.cs
- DataGridToolTip.cs