| File: System\Windows\Forms\Input\CursorConverter.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms\System.Windows.Forms.csproj (System.Windows.Forms) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.ComponentModel; using System.ComponentModel.Design.Serialization; using System.Globalization; using System.Reflection; namespace System.Windows.Forms; /// <summary> /// CursorConverter is a class that can be used to convert /// colors from one data type to another. Access this /// class through the TypeDescriptor. /// </summary> public class CursorConverter : TypeConverter { private StandardValuesCollection? _values; /// <summary> /// Determines if this converter can convert an object in the given source /// type to the native type of the converter. /// </summary> public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { if (sourceType == typeof(string) || sourceType == typeof(byte[])) { return true; } return base.CanConvertFrom(context, sourceType); } /// <summary> /// Gets a value indicating whether this converter can /// convert an object to the given destination type using the context. /// </summary> public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) { if (destinationType == typeof(InstanceDescriptor) || destinationType == typeof(byte[])) { return true; } return base.CanConvertTo(context, destinationType); } /// <summary> /// Converts the given object to the converter's native type. /// </summary> public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { if (value is string s) { string text = s.Trim(); PropertyInfo[] props = GetProperties(); foreach (var prop in props) { if (string.Equals(prop.Name, text, StringComparison.OrdinalIgnoreCase)) { return prop.GetValue(null, null); } } } if (value is byte[] bytes) { using MemoryStream ms = new(bytes); return new Cursor(ms); } return base.ConvertFrom(context, culture, value); } /// <summary> /// Converts the given object to another type. The most common types to convert /// are to and from a string object. The default implementation will make a call /// to ToString on the object if the object is valid and if the destination /// type is string. If this cannot convert to the destination type, this will /// throw a NotSupportedException. /// </summary> public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType) { if (value is Cursor cursor) { if (destinationType == typeof(string)) { if (cursor.CursorsProperty is string propertyName) { return propertyName; } else if (cursor.Handle == Cursors.Arrow.Handle) { // Arrow and Default cursors share the same HCURSOR. // Always return "Default" in this case. return nameof(Cursors.Default); } // We have a cursor that only has handle information. This can happen when the cursor was read via PInvoke. // Try to find an exact instance match to a known cursor from Cursors properties using HCURSOR equality (==). PropertyInfo[] props = GetProperties(); for (int i = 0; i < props.Length; i++) { PropertyInfo prop = props[i]; Cursor? knownCursor = (Cursor?)prop.GetValue(obj: null, index: null); if (knownCursor == cursor) { return prop.Name; } } // We throw here because we cannot meaningfully convert a custom // cursor into a string. In fact, the ResXResourceWriter will use // this exception to indicate to itself that this object should // be serialized through ISerializable instead of a string. throw new FormatException(SR.CursorCannotCovertToString); } else if (destinationType == typeof(InstanceDescriptor)) { PropertyInfo[] props = GetProperties(); foreach (PropertyInfo prop in props) { if (prop.GetValue(null, null) == value) { return new InstanceDescriptor(prop, null); } } } else if (destinationType == typeof(byte[])) { return cursor.GetData(); } } else if (destinationType == typeof(byte[]) && value is null) { return Array.Empty<byte>(); } return base.ConvertTo(context, culture, value, destinationType); } /// <summary> /// Retrieves the properties for the available cursors. /// </summary> private static PropertyInfo[] GetProperties() { return typeof(Cursors).GetProperties(BindingFlags.Static | BindingFlags.Public); } /// <summary> /// Retrieves a collection containing a set of standard values /// for the data type this validator is designed for. This /// will return null if the data type does not support a /// standard set of values. /// </summary> public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context) { if (_values is null) { List<object> list = []; PropertyInfo[] props = GetProperties(); for (int i = 0; i < props.Length; i++) { PropertyInfo prop = props[i]; object[]? tempIndex = null; Debug.Assert(prop.GetValue(null, tempIndex) is not null, $"Property {prop.Name} returned NULL"); if (prop.GetValue(null, tempIndex) is object item) { list.Add(item); } } _values = new StandardValuesCollection(list); } return _values; } /// <summary> /// Determines if this object supports a standard set of values /// that can be picked from a list. /// </summary> public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) { return true; } }