internal List <ControlInformation> GetControlsInformation() { if (IsStub) { return(_stub.GetControlsInformation()); } else { List <ControlInformation> controlsInfo = new List <ControlInformation>(Owner !.Children.Count); foreach (IArrangedElement element in Owner.Children) { if (element is Control c) { ControlInformation controlInfo = new ControlInformation(); // We need to go through the PropertyDescriptor for the Name property // since it is shadowed. PropertyDescriptor?prop = TypeDescriptor.GetProperties(c)["Name"]; if (prop is not null && prop.PropertyType == typeof(string)) { controlInfo.Name = prop.GetValue(c); } controlInfo.Row = GetRow(c); controlInfo.RowSpan = GetRowSpan(c); controlInfo.Column = GetColumn(c); controlInfo.ColumnSpan = GetColumnSpan(c); controlsInfo.Add(controlInfo); } } return(controlsInfo); } }
protected override void RemoveSortCore() { isSorted = false; propertyDescriptor = base.SortPropertyCore; listSortDirection = base.SortDirectionCore; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); }
/// <summary> /// Creates a new ExtenderProvidedPropertyAttribute. /// </summary> internal static ExtenderProvidedPropertyAttribute Create(PropertyDescriptor?extenderProperty, Type?receiverType, IExtenderProvider?provider) { return(new ExtenderProvidedPropertyAttribute { ExtenderProperty = extenderProperty, ReceiverType = receiverType, Provider = provider }); }
public int Compare(object?obj1, object?obj2) { PropertyDescriptor?a1 = obj1 as PropertyDescriptor; PropertyDescriptor?a2 = obj2 as PropertyDescriptor; if (a1 is null && a2 is null) { return(0); }
/// <summary> /// Gets the description of the property with the specified name. /// </summary> public virtual PropertyDescriptor?Find(string name, bool ignoreCase) { lock (_internalSyncObject) { PropertyDescriptor?p = null; if (_cachedFoundProperties == null || _cachedIgnoreCase != ignoreCase) { _cachedIgnoreCase = ignoreCase; if (ignoreCase) { _cachedFoundProperties = new Hashtable(StringComparer.OrdinalIgnoreCase); } else { _cachedFoundProperties = new Hashtable(); } } // first try to find it in the cache // object?cached = _cachedFoundProperties[name]; if (cached != null) { return((PropertyDescriptor)cached); } // Now start walking from where we last left off, filling // the cache as we go. // for (int i = 0; i < Count; i++) { if (ignoreCase) { if (string.Equals(_properties[i].Name, name, StringComparison.OrdinalIgnoreCase)) { _cachedFoundProperties[name] = _properties[i]; p = _properties[i]; break; } } else { if (_properties[i].Name.Equals(name)) { _cachedFoundProperties[name] = _properties[i]; p = _properties[i]; break; } } } return(p); } }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { if (PropertyComparer.CanSort(prop.PropertyType)) { ((List <T>)Items).Sort(new PropertyComparer(prop, direction)); _sortDirection = direction; _sortProperty = prop; _isSorted = true; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); } }
protected virtual void TableCollectionChanged(object?sender, CollectionChangeEventArgs e) { PropertyDescriptor?NullProp = null; OnListChanged( e.Action == CollectionChangeAction.Add ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorAdded, new DataTablePropertyDescriptor((System.Data.DataTable)e.Element !)) : e.Action == CollectionChangeAction.Refresh ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, NullProp) : e.Action == CollectionChangeAction.Remove ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorDeleted, new DataTablePropertyDescriptor((System.Data.DataTable)e.Element !)) : /*default*/ null ! // TODO: This is very likely wrong ); }
void IDictionary.Remove(object key) { if (key is string) { PropertyDescriptor?pd = this[(string)key]; if (pd != null) { ((IList)this).Remove(pd); } } }
public void Remove(PropertyDescriptor?value) { if (_readOnly) { throw new NotSupportedException(); } int index = IndexOf(value); if (index != -1) { RemoveAt(index); } }
/// <summary> /// Sorts the members of this PropertyDescriptorCollection. Any specified NamedSort arguments will /// be applied first, followed by sort using the specified IComparer. /// </summary> protected void InternalSort(string[]?names) { if (_properties.Length == 0) { return; } InternalSort(_comparer); if (names != null && names.Length > 0) { List <PropertyDescriptor?> propList = new List <PropertyDescriptor?>(_properties); int foundCount = 0; int propCount = _properties.Length; for (int i = 0; i < names.Length; i++) { for (int j = 0; j < propCount; j++) { PropertyDescriptor?currentProp = propList[j]; // Found a matching property. Here, we add it to our array. We also // mark it as null in our array list so we don't add it twice later. // if (currentProp != null && currentProp.Name.Equals(names[i])) { _properties[foundCount++] = currentProp; propList[j] = null; break; } } } // At this point we have filled in the first "foundCount" number of propeties, one for each // name in our name array. If a name didn't match, then it is ignored. Next, we must fill // in the rest of the properties. We now have a sparse array containing the remainder, so // it's easy. // for (int i = 0; i < propCount; i++) { if (propList[i] != null) { _properties[foundCount++] = propList[i] !; } } Debug.Assert(foundCount == propCount, "We did not completely fill our property array"); } }
/// <summary> /// Normal constructor used when constructing PropertyInformation objects for properties. /// </summary> /// <param name="target">target object being shown in the property grid</param> /// <param name="property">the property around which we are constructing this PropertyInformation object</param> /// <param name="propertyName">the property name for the property that we use in the binding in the case of a non-dependency property</param> /// <param name="propertyDisplayName">the display name for the property that goes in the name column</param> public PropertyInformation(object target, PropertyDescriptor?property, string propertyName, string propertyDisplayName) { this.Target = target; this.property = property; this.displayName = propertyDisplayName; if (property is not null) { // create a data binding between the actual property value on the target object // and the Value dependency property on this PropertyInformation object Binding binding; var dp = this.DependencyProperty; if (dp is not null) { binding = new Binding(); binding.Path = new PropertyPath("(0)", new object[] { dp }); if (dp == FrameworkElement.StyleProperty || dp == FrameworkContentElement.StyleProperty) { binding.Converter = NullStyleConverter.DefaultInstance; binding.ConverterParameter = target; } } else { binding = new Binding(propertyName); } binding.Source = target; binding.Mode = property.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay; try { BindingOperations.SetBinding(this, ValueProperty, binding); } catch (Exception) { // cplotts note: // warning: i saw a problem get swallowed by this empty catch (Exception) block. // in other words, this empty catch block could be hiding some potential future errors. } } this.Update(); this.isRunning = true; }
public static PropertyDescriptor?GetImageListProperty(PropertyDescriptor currentComponent, ref object instance) { if (instance is object[]) //multiple selection is not supported by this class { return(null); } PropertyDescriptor?imageListProp = null; object? parentInstance = instance; if (currentComponent.TryGetAttribute(out RelatedImageListAttribute? relatedAttribute)) { string[] pathInfo = relatedAttribute.RelatedImageList.Split('.'); for (int i = 0; i < pathInfo.Length; i++) { if (parentInstance is null) { Debug.Fail("A property specified in the path is null or not yet instantiated at this time"); break; // path is wrong } PropertyDescriptor?prop = TypeDescriptor.GetProperties(parentInstance)[pathInfo[i]]; if (prop is null) { Debug.Fail("The path specified to the property is wrong"); break; // path is wrong } if (i == pathInfo.Length - 1) { // we're on the last one, look if that's our guy if (typeof(ImageList).IsAssignableFrom(prop.PropertyType)) { instance = parentInstance; imageListProp = prop; break; } } else { parentInstance = prop.GetValue(parentInstance); } } } return(imageListProp); }
protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction) { List <T> itemsList = (List <T>)Items; Type propertyType = prop.PropertyType; if (!comparers.TryGetValue(propertyType, out var comparer)) { comparer = new PropertyComparer <T>(prop, direction); comparers.Add(propertyType, comparer); } comparer.SetPropertyAndDirection(prop, direction); itemsList.Sort(comparer); propertyDescriptor = prop; listSortDirection = direction; isSorted = true; OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1)); }
/// <summary> /// Tries to set an attribute in the project file for the item. /// </summary> public async Task <bool> TrySetAttributeAsync(string name, string value) { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); GetItemInfo(out IVsHierarchy hierarchy, out uint itemId, out _); int hr = hierarchy.GetProperty(itemId, (int)__VSHPROPID.VSHPROPID_BrowseObject, out object?browseObject); // First try if the attribute name exist in the Property Descriptor Collection if (ErrorHandler.Succeeded(hr)) { // Inspired by this sample: https://stackoverflow.com/a/24538728 string cleanName = Regex.Replace(name, @"\s+", ""); // remove whitespace PropertyDescriptorCollection propertyDescriptors = TypeDescriptor.GetProperties(browseObject); PropertyDescriptor? customToolDescriptor = propertyDescriptors?.Find(cleanName, true); if (customToolDescriptor != null) { string?invariantValue = customToolDescriptor.Converter.ConvertToInvariantString(value); customToolDescriptor.SetValue(browseObject, invariantValue); IVsUIShell?shell = await VS.Services.GetUIShellAsync(); // Refresh the Property window if (customToolDescriptor.Attributes[typeof(DispIdAttribute)] is DispIdAttribute dispId) { ErrorHandler.ThrowOnFailure(shell.RefreshPropertyBrowser(dispId.Value)); } return(true); } } // Then write straight to project file else if (hierarchy is IVsBuildPropertyStorage storage) { ErrorHandler.ThrowOnFailure(storage.SetItemAttribute(itemId, name, value)); return(true); } return(false); }
public override string HelpKeyword => "vs.properties"; // do not localize. #pragma warning disable CA1725 // Parameter names should match base declaration - publicly shipped API public override PropertyDescriptor?GetDefaultProperty(object obj) #pragma warning restore CA1725 { PropertyDescriptor?defaultProperty = base.GetDefaultProperty(obj); if (defaultProperty is null) { PropertyDescriptorCollection?properties = GetProperties(obj); if (properties is not null) { for (int i = 0; i < properties.Count; i++) { if ("Name".Equals(properties[i].Name)) { defaultProperty = properties[i]; break; } } } } return(defaultProperty); }
public ListChangedEventArgs(ListChangedType listChangedType, PropertyDescriptor?propDesc) { ListChangedType = listChangedType; PropertyDescriptor = propDesc; }
/// <summary> /// Retrieves a collection containing a set of standard values for the data type this validator is designed for. /// </summary> /// <param name="context"> /// An <see cref="ITypeDescriptorContext" /> that provides a format context, which can be used to extract /// additional information about the environment this type converter is being invoked from. /// This parameter or properties of this parameter can be <see langword="null" />. /// </param> /// <returns> /// A collection that holds a standard set of valid index values. /// If no image list is found, this collection will contain a single object with a value of -1. /// This returns <see langword="null" /> if the data type doesn't support a standard set of values. /// </returns> public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext?context) { if (context is not null && context.Instance is not null) { object?instance = context.Instance; PropertyDescriptor?imageListProp = ImageListUtils.GetImageListProperty(context.PropertyDescriptor, ref instance); while (instance is not null && imageListProp is null) { PropertyDescriptorCollection props = TypeDescriptor.GetProperties(instance); foreach (PropertyDescriptor prop in props) { if (typeof(ImageList).IsAssignableFrom(prop.PropertyType)) { imageListProp = prop; break; } } if (imageListProp is null) { // We didn't find the image list in this component. See if the // component has a "parent" property. If so, walk the tree... PropertyDescriptor?parentProp = props[ParentImageListProperty]; if (parentProp is not null) { instance = parentProp.GetValue(instance); } else { // Stick a fork in us, we're done. instance = null; } } } if (imageListProp is not null) { ImageList?imageList = (ImageList?)imageListProp.GetValue(instance); if (imageList is not null) { // Create array to contain standard values object[] values; int nImages = imageList.Images.Count; if (IncludeNoneAsStandardValue) { values = new object[nImages + 1]; values[nImages] = ImageList.Indexer.DefaultIndex; } else { values = new object[nImages]; } // Fill in the array for (int i = 0; i < nImages; i++) { values[i] = i; } return(new StandardValuesCollection(values)); } } } if (IncludeNoneAsStandardValue) { return(new StandardValuesCollection(new object[] { ImageList.Indexer.DefaultIndex })); } else { return(new StandardValuesCollection(Array.Empty <object>())); } }
/// <summary> /// Retrieves a collection containing a set of standard values for the data type this validator is designed for. /// </summary> /// <param name="context"> /// An object that provides a format context, which can be used to extract additional /// information about the environment this type converter is being invoked from. /// This parameter or its properties can be <see langword="null" />. /// </param> /// <returns> /// A collection that holds a standard set of valid index values.If no image list is found, /// this collection contains a single object with a value of -1. This method returns<see langword="null" /> /// if the data type doesn't support a standard set of values. /// </returns> public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext?context) { if (context is not null && context.Instance is not null) { object instance = context.Instance; ImageList?imageList = null; PropertyDescriptorCollection listViewItemProps = TypeDescriptor.GetProperties(instance); PropertyDescriptor? listViewProp = listViewItemProps["ListView"]; if (listViewProp is not null) { // Grab the ListView property off of the TreeNode. object?listViewInstance = listViewProp.GetValue(instance); if (listViewInstance is not null) { // Get the ImageList property from the ListView and set it to be the currentImageList. PropertyDescriptorCollection listViewProps = TypeDescriptor.GetProperties(listViewInstance); PropertyDescriptor? listViewImageListProperty = listViewProps["StateImageList"]; if (listViewImageListProperty is not null) { imageList = (ImageList?)listViewImageListProperty.GetValue(listViewInstance); } } } if (imageList is not null) { // Create array to contain standard values object[] values; int nImages = imageList.Images.Count; if (IncludeNoneAsStandardValue) { values = new object[nImages + 1]; values[nImages] = ImageList.Indexer.DefaultIndex; } else { values = new object[nImages]; } // Fill in the array for (int i = 0; i < nImages; i++) { values[i] = i; } return(new StandardValuesCollection(values)); } } if (IncludeNoneAsStandardValue) { return(new StandardValuesCollection(new object[] { ImageList.Indexer.DefaultIndex })); } else { return(new StandardValuesCollection(Array.Empty <object>())); } }
/// <summary> /// Initializes a new instance of the <see cref="RuntimeArgument"/> class. /// </summary> /// <param name="name">The name.</param> /// <param name="argumentType">Type of the argument.</param> /// <param name="direction">The direction.</param> /// <param name="isRequired">if set to <c>true</c> [is required].</param> /// <param name="overloadGroups">The overload groups.</param> /// <param name="bindingProperty">The binding property.</param> /// <param name="propertyOwner">The property owner.</param> internal RuntimeArgument(string name, Type argumentType, ArgumentDirection direction, bool isRequired, List <string> overloadGroups, PropertyDescriptor bindingProperty, object propertyOwner) : this(name, argumentType, direction, isRequired, overloadGroups) { this.bindingProperty = bindingProperty; this.bindingPropertyOwner = propertyOwner; }
/// <summary> /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in /// any release. You should only use it directly in your code with extreme caution and knowing that /// doing so can result in application failures when updating to a new Entity Framework Core release. /// </summary> protected override void RemoveSortCore() { _isSorted = false; _sortProperty = null; }
/// <summary> /// Retrieves the object that directly depends on this value being edited. This is /// generally the object that is required for the PropertyDescriptor's GetValue and SetValue /// methods. If 'null' is passed for the PropertyDescriptor, the ICustomComponent /// descriptor implementation should return the default object, that is the main /// object that exposes the properties and attributes, /// </summary> object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor?pd) => this;
/// <summary> /// Gets the best matching ctor for a given binding and fills it out, based on the /// state of the Binding and the optimal ctor. /// </summary> private static InstanceDescriptor GetInstanceDescriptorFromValues(Binding b) { // The BindingFormattingDialog turns on Binding::FormattingEnabled property. // however, when the user data binds a property using the PropertyBrowser, Binding::FormattingEnabled is set to false // The Binding class is not a component class, so we don't have the ComponentInitialize method where we can set FormattingEnabled to true // so we set it here. b.FormattingEnabled = true; bool isComplete = true; int lastItem = ConstructorParameterProperties.Length - 1; for (; lastItem >= 0; lastItem--) { // null means no prop is available, we quit here. if (ConstructorParameterProperties[lastItem] is null) { break; } // get the property and see if it needs to be serialized. var constructorParameterProperty = ConstructorParameterProperties[lastItem]; if (constructorParameterProperty is null) { break; } PropertyDescriptor?prop = TypeDescriptor.GetProperties(b)[constructorParameterProperty]; if (prop is not null && prop.ShouldSerializeValue(b)) { break; } } // now copy the type array up to the point we quit. Type[] ctorParams = new Type[lastItem + 1]; Array.Copy(ConstructorParamaterTypes, 0, ctorParams, 0, ctorParams.Length); // Get the ctor info. ConstructorInfo?ctor = typeof(Binding).GetConstructor(ctorParams); Debug.Assert(ctor is not null, "Failed to find Binding ctor for types!"); if (ctor is null) { isComplete = false; ctor = typeof(Binding).GetConstructor(new Type[] { typeof(string), typeof(object), typeof(string) }); } // now fill in the values. object?[] values = new object[ctorParams.Length]; for (int i = 0; i < values.Length; i++) { object?val = null; switch (i) { case 0: val = b.PropertyName; break; case 1: val = b.DataSource; break; case 2: val = b.BindingMemberInfo.BindingMember; break; default: var constructorParameterProperty = ConstructorParameterProperties[i]; if (constructorParameterProperty is not null) { val = TypeDescriptor.GetProperties(b)[constructorParameterProperty]?.GetValue(b); } break; } values[i] = val; } return(new InstanceDescriptor(ctor, values, isComplete)); }
/// <summary> /// The GetPropertyOwner method returns an instance of an object that /// owns the given property for the object this type descriptor is representing. /// An optional attribute array may be provided to filter the collection that is /// returned. Returning null from this method causes the TypeDescriptor object /// to use its default type description services. /// </summary> public virtual object?GetPropertyOwner(PropertyDescriptor?pd) => _parent?.GetPropertyOwner(pd);
public ListSortDescription(PropertyDescriptor?property, ListSortDirection direction) { PropertyDescriptor = property; SortDirection = direction; }
public ListChangedEventArgs(ListChangedType listChangedType, int newIndex, PropertyDescriptor?propDesc) : this(listChangedType, newIndex) { PropertyDescriptor = propDesc; OldIndex = newIndex; }
object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor?pd) { return(this); }
internal void SetupBinding(Activity owningElement, bool createEmptyBinding) { if (this.bindingProperty != null) { var argument = (Argument)this.bindingProperty.GetValue(this.bindingPropertyOwner); if (argument == null) { Fx.Assert(this.bindingProperty.PropertyType.IsGenericType, "We only support arguments that are generic types in our reflection walk."); argument = (Argument)Activator.CreateInstance(this.bindingProperty.PropertyType); argument.WasDesignTimeNull = true; if (createEmptyBinding && !this.bindingProperty.IsReadOnly) { this.bindingProperty.SetValue(this.bindingPropertyOwner, argument); } } Argument.Bind(argument, this); } else if (!this.IsBound) { var properties = TypeDescriptor.GetProperties(owningElement); PropertyDescriptor?targetProperty = null; for (var i = 0; i < properties.Count; i++) { var property = properties[i]; // We only support auto-setting the property // for generic types. Otherwise we have no // guarantee that the argument returned by the // property still matches the runtime argument's // type. if (property.Name == this.Name && property.PropertyType.IsGenericType) { if (ActivityUtilities.TryGetArgumentDirectionAndType(property.PropertyType, out var direction, out var argumentType)) { if (this.Type == argumentType && this.Direction == direction) { targetProperty = property; break; } } } } Argument?argument = null; if (targetProperty != null) { argument = (Argument)targetProperty.GetValue(owningElement); } if (argument == null) { if (targetProperty != null) { if (targetProperty.PropertyType.IsGenericType) { argument = (Argument)Activator.CreateInstance(targetProperty.PropertyType); } else { argument = ActivityUtilities.CreateArgument(this.Type, this.Direction); } } else { argument = ActivityUtilities.CreateArgument(this.Type, this.Direction); } argument.WasDesignTimeNull = true; if (targetProperty != null && createEmptyBinding && !targetProperty.IsReadOnly) { targetProperty.SetValue(owningElement, argument); } } Argument.Bind(argument, this); } Fx.Assert(this.IsBound, "We should always be bound when exiting this method."); }
public virtual void ApplyResources(object value, string objectName, CultureInfo?culture) { if (value == null) { throw new ArgumentNullException(nameof(value)); } if (objectName == null) { throw new ArgumentNullException(nameof(objectName)); } if (culture == null) { culture = CultureInfo.CurrentUICulture; } // The general case here will be to always use the same culture, so optimize for // that. The resourceSets hashtable uses culture as a key. It's value is // a sorted dictionary that contains ALL the culture values (so it traverses up // the parent culture chain) for that culture. This means that if ApplyResources // is called with different cultures there could be some redundancy in the // table, but it allows the normal case of calling with a single culture to // be much faster. // // The reason we use a SortedDictionary here is to ensure the resources are applied // in an order consistent with codedom deserialization. SortedList <string, object?>?resources; if (_resourceSets == null) { _resourceSets = new Hashtable(); resources = FillResources(culture, out _); _resourceSets[culture] = resources; } else { resources = (SortedList <string, object?>?)_resourceSets[culture]; if (resources == null || (resources.Comparer.Equals(StringComparer.OrdinalIgnoreCase) != IgnoreCase)) { resources = FillResources(culture, out _); _resourceSets[culture] = resources; } } BindingFlags flags = BindingFlags.Public | BindingFlags.GetProperty | BindingFlags.Instance; if (IgnoreCase) { flags |= BindingFlags.IgnoreCase; } bool componentReflect = false; if (value is IComponent) { ISite?site = ((IComponent)value).Site; if (site != null && site.DesignMode) { componentReflect = true; } } foreach (KeyValuePair <string, object?> kvp in resources) { // See if this key matches our object. string key = kvp.Key; if (IgnoreCase) { if (string.Compare(key, 0, objectName, 0, objectName.Length, StringComparison.OrdinalIgnoreCase) != 0) { continue; } } else { if (string.CompareOrdinal(key, 0, objectName, 0, objectName.Length) != 0) { continue; } } // Character after objectName.Length should be a "." or a '-', or else we should continue. int idx = objectName.Length; if (key.Length <= idx || (key[idx] != '.' && key[idx] != '-')) { continue; } // Bypass type descriptor if we are not in design mode. TypeDescriptor does an attribute // scan which is quite expensive. string propName = key.Substring(idx + 1); if (componentReflect) { PropertyDescriptor?prop = TypeDescriptor.GetProperties(value).Find(propName, IgnoreCase); if (prop != null && !prop.IsReadOnly && (kvp.Value == null || prop.PropertyType.IsInstanceOfType(kvp.Value))) { prop.SetValue(value, kvp.Value); } } else { PropertyInfo?prop; try { prop = value.GetType().GetProperty(propName, flags); } catch (AmbiguousMatchException) { // Looks like we ran into a conflict between a declared property and an inherited one. // In such cases, we choose the most declared one. Type?t = value.GetType(); do { prop = t.GetProperty(propName, flags | BindingFlags.DeclaredOnly); t = t.BaseType; } while (prop == null && t != null && t != typeof(object)); } if (prop != null && prop.CanWrite && (kvp.Value == null || prop.PropertyType.IsInstanceOfType(kvp.Value))) { prop.SetValue(value, kvp.Value, null); } } } }
public int IndexOf(PropertyDescriptor?value) => Array.IndexOf(_properties, value, 0, Count);