Is it possible to implicitly cast to a wrapper for UI?

时间:2016-10-20 12:50:39

标签: c# xaml

I have a huge collection of objects of type Person, which I can not modify or inherit. This is person.cs

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

And I want to have additional Information in my Grid (Wpf Datagrid) which I have to lookup in a IValueConverter. But IValueConverters are a bad solution if you have a lot of Persons ( > 500 )

My idea was to create a wrapper like this:

public class PersonWrapper
{
    public Person Content { get; set; }

    public string GetAdditionalInfo
    {
        get { return Helper.GetMagicInfo(Content); }
    }
}

With this trick I can avoid having a IValueConverter.

Now comes my question:

Can I implicitly (with MarkupExtension or with TypeConverter) "wrap" my class for use in Binding?


Edit: I wrote a TypeConverter and used a TemplateSelector. The TypeConverter:

public class PersonTypeConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context,
        Type sourceType)
    {
        return sourceType == typeof(Person);
    }

    public override object ConvertFrom(ITypeDescriptorContext context,
        System.Globalization.CultureInfo culture, object value)
    {
        var s = value as PersonWrapper;
        if (s == null)
            return new Person();
        return s.Content;
    }

    public override bool CanConvertTo(ITypeDescriptorContext context,
        Type destinationType)
    {
        return destinationType == typeof(string);
    }

    public override object ConvertTo(ITypeDescriptorContext context,
        System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        return new PersonWrapper() {Content = value as Person};
    }
}

And added the Attribute to Person.cs

[TypeConverter(typeof(PersonTypeConverter))]

And I used it like this:

<Window.Resources>
    <DataTemplate x:Key="dt" DataType="{x:Type local:PersonWrapper}">
        <StackPanel>
            <Label Content="{Binding FirstName}" />
            <Label Content="{Binding LastName}" />
        </StackPanel>
    </DataTemplate>
    <local:CTemplateSelector DefaultTemplate="{StaticResource dt}" x:Key="CTemplateSelector" />
</Window.Resources>
<Grid>
    <ContentControl Content="{Binding OurText}" ContentTemplateSelector="{StaticResource CTemplateSelector}" />
</Grid>

The TemplateSelector:

public class CTemplateSelector : DataTemplateSelector
{
    /// <summary>When overridden in a derived class, returns a <see cref="T:System.Windows.DataTemplate" /> based on custom logic.</summary>
    /// <returns>Returns a <see cref="T:System.Windows.DataTemplate" /> or null. The default value is null.</returns>
    /// <param name="item">The data object for which to select the template.</param>
    /// <param name="container">The data-bound object.</param>
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        Debug.WriteLine(item?.GetType());
        return DefaultTemplate;
    }

    public DataTemplate DefaultTemplate
    {
        get ;
        set ; 
    }
}

But the TemplateSelector always prints out Person as type.

1 个答案:

答案 0 :(得分:1)

您应该能够从您的人物对象(例如

)中脱离
public class MyPerson : Person
{
    public string FirstLast
    { get { return string.Format( "{0} {1}", FirstName, LastName ); }}

    public string LastFirst
    { get { return string.Format( "{0}, {1}", LastName, FirstName ); }}

    public string YourOtherContext
    { get { return WhateverFunctionToGetContext( this ); }}
}

然后你有另一个函数返回你想要呈现的字符串。您的绑定获取人员结构的所有默认属性,并且您刚刚使用这些新属性进行了扩展而没有任何转换器。当网格绑定到它们时,它会像其他任何一个一样调用getter并返回该值。