XAML标记绑定到具有类型为的键的字典



我正试图通过xaml绑定到Dictionary<Type,string>

问题是,Binding标记扩展中的索引器[]将其内容解释为字符串。这种情况是否存在某种"unescape序列"?

<TextBox Text="{Binding theDictionary[{x:Type ns:OnePrettyType}]}" />

(绑定不起作用,因为{x:Type ns:OnePrettyType}以字符串形式发送)

如果索引器具有特定类型,则应自动进行转换,这样就可以工作:

{Binding theDictionary[ns:OnePrettyType]}

如果你需要一个明确的解释,你可以尝试这样的"演员阵容":

{Binding theDictionary[(sys:Type)ns:OnePrettyType]}

(其中sys当然映射到System命名空间)

这将是理论,但所有这些都不起作用。首先,如果使用采用路径的Binding构造函数,则将忽略强制转换,因为它以某种方式使用PropertyPath的某个构造函数。此外,您将得到一个绑定错误:

System.Windows.Data错误:40:BindingExpression路径错误:在"object"Dictionary"2"上找不到"[]"属性

您需要通过避免Binding构造函数来通过类型转换器使其构造PropertyPath

{Binding Path=theDictionary[(sys:Type)ns:OnePrettyType]}

现在,这很可能只是抛出一个异常:

{"路径索引器参数的值无法解析为指定的类型:'sys:type'"}

因此,不幸的是,没有进行默认的类型转换。然后,您可以在XAML中构造一个PropertyPath,并确保传入一个类型,但该类不应该在XAML中使用,如果尝试,会抛出异常,这也是非常不幸的。

一种解决方法是创建一个标记扩展来进行构建,例如

[ContentProperty("Parameters")]
public class PathConstructor : MarkupExtension
{
    public string Path { get; set; }
    public IList Parameters { get; set; }
    public PathConstructor()
    {
        Parameters = new List<object>();
    }
    public PathConstructor(string path, object p0)
    {
        Path = path;
        Parameters = new[] { p0 };
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return new PropertyPath(Path, Parameters.Cast<object>().ToArray());
    }
}

然后可以这样使用:

<Binding>
    <Binding.Path>
        <me:PathConstructor Path="theDictionary[(0)]">
            <x:Type TypeName="ns:OnePrettyType" />
        </me:PathConstructor>
    </Binding.Path>
</Binding>

或者像这个

{Binding Path={me:PathConstructor theDictionary[(0)], {x:Type ns:OnePrettyType}}}

更新:我将此留给扩展绑定的参考

<Grid Width="{my:ParameterBinding {Binding [(0)],Source={x:Static my:SettingsService.Current}, Mode=TwoWay},{x:Type my:LeftPanelWidthSetting}}"/>

这就是背后的代码

[ContentProperty( "Parameters" )]
public class ParameterBinding : MarkupExtension
{
    public Binding Binding { get; set; }
    public IList Parameters { get; set; }
    public ParameterBinding()
    {
        Parameters = new List<object>(); 
    }
    public ParameterBinding( Binding b, object p0 )
    {
        Binding = b;
        Parameters = new []{p0};
    }
    public override object ProvideValue( IServiceProvider serviceProvider )
    {
        Binding.Path = new PropertyPath( Binding.Path.Path, Parameters.Cast<object>().ToArray() );
        return Binding.ProvideValue(serviceProvider);
    }
}

这将是可扩展的,以支持更多具有额外构造函数的内联语法参数。我仍然保留了使用扩展元素语法添加许多参数的能力。

感谢H.B.激发了这个

最新更新