- Improved PropertyGrid.axaml formatting and control styles; ensured spinner buttons are always visible and ColorPicker layouts are flexible; disabled horizontal scrolling in property list. - Reformatted property editors and group/category display for clarity. - Made all value converters sealed, added XML docs, and updated ConvertBack to throw NotImplementedException where unsupported. - Enhanced search logic to use StringComparison.OrdinalIgnoreCase. - Minor code style fixes (e.g., char literals for string checks). - Removed default value assignment for _useProxy in AdvancedConfiguration.cs. - Updated Program.cs in examples to use sealed Program classes. - Added PropertyGrid.slnx to organize solution and projects.
398 lines
14 KiB
C#
398 lines
14 KiB
C#
using System;
|
|
using System.Globalization;
|
|
using Avalonia.Data.Converters;
|
|
|
|
namespace Avalonia.PropertyGrid.Controls;
|
|
|
|
/// <summary>
|
|
/// Converts indent level to left margin
|
|
/// </summary>
|
|
public sealed class IndentToMarginConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Converts indent level to left margin.
|
|
/// </summary>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is int indentLevel)
|
|
{
|
|
return new Thickness(indentLevel * 16, 0, 0, 0);
|
|
}
|
|
return new Thickness(0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not implemented.
|
|
/// </summary>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts enum type to list of enum values
|
|
/// </summary>
|
|
public sealed class EnumValuesConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Converts an enum type to an array of its values.
|
|
/// </summary>
|
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type enumType && enumType.IsEnum)
|
|
{
|
|
return Enum.GetValues(enumType);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not implemented.
|
|
/// </summary>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type is an enum
|
|
/// </summary>
|
|
public sealed class IsEnumConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the provided type is an enum.
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional parameter.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type is an enum, otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type)
|
|
{
|
|
return type.IsEnum;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type is a simple type (string, number, bool, etc.)
|
|
/// </summary>
|
|
public sealed class IsSimpleTypeConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the provided type is a simple type like string, number, DateTime, etc.
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional parameter.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type is a simple type, otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type)
|
|
{
|
|
return type == typeof(string) ||
|
|
type == typeof(int) || type == typeof(long) || type == typeof(short) ||
|
|
type == typeof(uint) || type == typeof(ulong) || type == typeof(ushort) ||
|
|
type == typeof(byte) || type == typeof(sbyte) ||
|
|
type == typeof(float) || type == typeof(double) || type == typeof(decimal) ||
|
|
type == typeof(DateTime) || type == typeof(TimeSpan) || type == typeof(Guid) ||
|
|
type == typeof(DateTimeOffset) || !type.IsEnum;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type matches the specified type name
|
|
/// </summary>
|
|
public sealed class TypeToBoolConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the type's name matches the specified parameter string.
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">The type name to match against.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type name matches, otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type && parameter is string typeName)
|
|
{
|
|
return type.FullName == typeName || type.Name == typeName;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts Color to/from hex string representation
|
|
/// </summary>
|
|
public sealed class ColorToStringConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Converts a Color to a hex string representation.
|
|
/// </summary>
|
|
/// <param name="value">The Color to convert.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional parameter.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>A hex string representation of the color (e.g., "#AARRGGBB").</returns>
|
|
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Media.Color color)
|
|
{
|
|
return $"#{color.A:X2}{color.R:X2}{color.G:X2}{color.B:X2}";
|
|
}
|
|
return value?.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Converts a hex string back to a Color.
|
|
/// </summary>
|
|
/// <param name="value">The hex string to convert.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional parameter.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>The parsed Color, or Black if parsing fails.</returns>
|
|
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is string hexString && !string.IsNullOrWhiteSpace(hexString))
|
|
{
|
|
try
|
|
{
|
|
hexString = hexString.Trim();
|
|
if (!hexString.StartsWith('#'))
|
|
hexString = "#" + hexString;
|
|
|
|
return Media.Color.Parse(hexString);
|
|
}
|
|
catch
|
|
{
|
|
// If parsing fails, return the original color or default
|
|
return Media.Colors.Black;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type is Color
|
|
/// </summary>
|
|
public sealed class IsColorTypeConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the provided type is Avalonia.Media.Color.
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional "Invert" parameter to invert the result.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type is Color (or inverted if parameter is "Invert"), otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type)
|
|
{
|
|
bool isColor = type == typeof(Media.Color);
|
|
|
|
// Support inverting the result
|
|
if (parameter is string param && param.Equals("Invert", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return !isColor;
|
|
}
|
|
|
|
return isColor;
|
|
}
|
|
|
|
// Default to showing TextBox (inverted result)
|
|
if (parameter is string param2 && param2.Equals("Invert", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type is numeric
|
|
/// </summary>
|
|
public sealed class IsNumericTypeConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the provided type is a numeric type (int, long, float, double, decimal, etc.).
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional "Invert" parameter to invert the result.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type is numeric (or inverted if parameter is "Invert"), otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type)
|
|
{
|
|
bool isNumeric = type == typeof(int) || type == typeof(long) || type == typeof(short) ||
|
|
type == typeof(byte) || type == typeof(uint) || type == typeof(ulong) ||
|
|
type == typeof(ushort) || type == typeof(sbyte) ||
|
|
type == typeof(float) || type == typeof(double) || type == typeof(decimal);
|
|
|
|
// Support inverting the result
|
|
if (parameter is string param && param.Equals("Invert", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return !isNumeric;
|
|
}
|
|
|
|
return isNumeric;
|
|
}
|
|
|
|
// Default to showing TextBox (inverted result)
|
|
if (parameter is string param2 && param2.Equals("Invert", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type is neither Color nor Numeric nor Boolean nor Enum (for fallback TextBox)
|
|
/// </summary>
|
|
public sealed class IsOtherTypeConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the type is not Color, Numeric, Boolean, or Enum (used for fallback TextBox editor).
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional parameter.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type is not a special type, otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type)
|
|
{
|
|
bool isColor = type == typeof(Media.Color);
|
|
bool isNumeric = type == typeof(int) || type == typeof(long) || type == typeof(short) ||
|
|
type == typeof(byte) || type == typeof(uint) || type == typeof(ulong) ||
|
|
type == typeof(ushort) || type == typeof(sbyte) ||
|
|
type == typeof(float) || type == typeof(double) || type == typeof(decimal);
|
|
bool isBool = type == typeof(bool);
|
|
bool isEnum = type.IsEnum;
|
|
|
|
// Return true if it's neither color nor numeric nor boolean nor enum
|
|
return !isColor && !isNumeric && !isBool && !isEnum;
|
|
}
|
|
|
|
return true; // Default to showing TextBox
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks if a type is boolean
|
|
/// </summary>
|
|
public sealed class IsBooleanTypeConverter : IValueConverter
|
|
{
|
|
/// <summary>
|
|
/// Checks if the provided type is boolean.
|
|
/// </summary>
|
|
/// <param name="value">The Type to check.</param>
|
|
/// <param name="targetType">The target type.</param>
|
|
/// <param name="parameter">Optional "Invert" parameter to invert the result.</param>
|
|
/// <param name="culture">Culture information.</param>
|
|
/// <returns>True if the type is boolean (or inverted if parameter is "Invert"), otherwise false.</returns>
|
|
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
if (value is Type type)
|
|
{
|
|
bool isBool = type == typeof(bool);
|
|
|
|
// Support inverting the result
|
|
if (parameter is string param && param.Equals("Invert", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return !isBool;
|
|
}
|
|
|
|
return isBool;
|
|
}
|
|
|
|
// Default to showing TextBox (inverted result)
|
|
if (parameter is string param2 && param2.Equals("Invert", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Not supported for this converter.
|
|
/// </summary>
|
|
/// <exception cref="NotImplementedException">This converter does not support ConvertBack.</exception>
|
|
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|