【问题标题】:XAML markup binding to dictionary with key of type TypeXAML 标记绑定到具有类型键的字典
【发布时间】:2012-03-11 09:41:40
【问题描述】:

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

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

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

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

【问题讨论】:

  • 不要绑定到字典和其他值,而是在视图模型上公开一个为您工作的属性。

标签: .net wpf xaml markup-extensions


【解决方案1】:

如果索引器具有特定类型,则应自动完成转换,这样应该可以:

{Binding theDictionary[ns:OnePrettyType]}

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

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

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

理论上是这样,但所有这些都行不通。首先,如果您使用采用路径的Binding 构造函数,则转换将被忽略,因为它以某种方式使用PropertyPath 的某个构造函数。你也会得到一个绑定错误:

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

您需要通过类型转换器构造PropertyPath,避免Binding 构造函数:

{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}}}

【讨论】:

  • 谢谢,H.B. - 你让我吃惊。似乎距离您通过 10k 仅几个月时间,现在您已接近 40k。感谢您提供的所有这些高质量的答案。这看起来不错,我可能会在尝试后将其标记为已回答。
  • 天哪,看看我做了什么。我一直认为'绑定不可扩展'。 This 感觉很接近。
  • @MarkusHütter:我在这个网站上花了太多时间。我不知道你可以在标记扩展中有多个构造函数参数,谢谢,这是一种有趣的内联方式。我之前尝试过使用params,但不幸的是编译器没有得到它,本来是完美的。虽然不知道传递绑定,但我认为它使它更难阅读,我会坚持在Path 中使用它,例如{Binding Path={me:ParameterPath [(0)], ...}}
  • 我认为您对可读性的看法是正确的,我可能会使用带有参数的添加构造函数来解决您的问题
  • 只在视图模型上公开一个属性不是更有意义吗?即public OnePrettyType TheType { get { return TheDictionary[0]; } } //Error check it as well
【解决方案2】:

更新:我将其留作参考以扩展绑定

<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.为了启发这个

【讨论】:

    猜你喜欢
    • 2017-08-28
    • 1970-01-01
    • 2017-06-03
    • 2011-11-04
    • 2012-04-02
    • 2018-11-05
    • 1970-01-01
    • 2018-12-09
    • 2015-12-22
    相关资源
    最近更新 更多