wpftoolkit
wpftoolkit copied to clipboard
PropertyGrid binding fails for many DbConnectionStringBuilder descendants
Consider the following test class, for configuring a hypothetical CSV-based database:
using System.ComponentModel;
namespace MyProject
{
public class CsvConfigurator : DbConnectionStringBuilder, INotifyPropertyChanged
{
public CsvConfigurator() { }
public CsvConfigurator(string conf) : this()
{
ConnectionString = conf;
}
[Category("CSV")]
[Description("The character used to separate CSV fields")]
[DefaultValue(',')]
public char Delimiter
{
get => GetChar(nameof(Delimiter), ',');
set => this[nameof(Delimiter)] = value;
}
[Category("CSV")]
[DisplayName("Auto-detect delimiter")]
[Description("If true, analyze the file to discover its delimiter rather than using the Delimiter property")]
[DefaultValue(true)]
public bool AutoDetectDelimiter
{
get => GetBool(nameof(AutoDetectDelimiter));
set => this[nameof(AutoDetectDelimiter)] = value;
}
[Category("CSV")]
[Description("If true, treat the first line of the file as a header")]
[DefaultValue(false)]
public bool UsesHeader
{
get => GetBool(nameof(UsesHeader));
set => this[nameof(UsesHeader)] = value;
}
[Category("CSV")]
[Description("If true, check columns for quoted data")]
[DefaultValue(true)]
public bool UsesQuotes
{
get => GetBool(nameof(UsesQuotes));
set => this[nameof(UsesQuotes)] = value;
}
[Category("CSV")]
[DisplayName("Quote character")]
[Description("The character used to quote an entire field")]
[DefaultValue('"')]
public char QuoteChar
{
get => GetChar(nameof(QuoteChar), '"');
set => this[nameof(QuoteChar)] = value;
}
[Category("CSV")]
[DisplayName("Escape character")]
[Description("The character used to escape quote marks inside a quote")]
[DefaultValue('\\')]
public char EscapeChar
{
get => GetChar(nameof(EscapeChar), '\\');
set => this[nameof(EscapeChar)] = value;
}
public event PropertyChangedEventHandler PropertyChanged;
public override object this[string key]
{
get => base[key];
set {
TryGetValue(key, out var existing);
if (existing == null) {
if (value == null) {
return;
}
}
else if (existing.Equals(value)) {
return;
}
base[key] = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(key));
}
}
protected string GetString(string key) => TryGetValue(key, out var value) ? (string)value : null;
protected bool GetBool(string key) => TryGetValue(key, out var value) ? Convert.ToBoolean(value) : false;
protected char GetChar(string key, char defaultValue)
{
var result = GetString(key);
return string.IsNullOrEmpty(result) ? defaultValue : result[0];
}
}
}
When trying to edit an instance of this class in PropertyGrid
, it fails to bind to the object's properties:
The same glitch can be seen for the connection string builders for Firebird and MySql:
For whatever reason, the ones for MS Sql Server and Postgres bind correctly:
Looking through the source, it appears that PropertyGrid
has no knowledge of ICustomTypeDescriptor
, which the DbConnectionStringBuilder
class (as well as several other things in .NET) uses for the express purpose of providing an interface to its properties for GUI editors such as this one. That might be part of the problem.
On a second look, it looks like there is some support for ICustomTypeDescriptor
in other files that are used by PropertyGrid
. It retrieves the PropertyDescriptor
s correctly from the custom type descriptor, but I can't see any place where it calls GetValue
or SetValue
to actually interact with the properties in the prescribed manner.