在ViewModel中向实体类添加属性 [英] Add a Property to Entity Class in ViewModel

查看:123
本文介绍了在ViewModel中向实体类添加属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有ProfileUser的EntityCollection的配置文件。在此类中,我有一个Profile_ID,一个Profile关系和一个User_ID但没有USer关系,因为User在另一个数据库中。

I have a profile with a EntityCollection of ProfileUser. In this Class I have a Profile_ID ald a Profile relation and a User_ID but no USer relation, because User is in another Database.

在一个Datagrid中,我想通过User访问。用户名

In a Datagrid I want to access via User.Username

我尝试过此操作,但是ofc无效...

I tried this, but ofc it doesnt work...

public EntityCollection<ProfileUser> ProfileUsers
    {
        get
        {
            if (profile != null) return profile.ProfileUser;
            else return null;
        }
        set
        {
            profile.ProfileUser = value;
        }
    }

,这里是我的自定义类

public class ProfileUserExtended : ProfileUser
{
    public Operator User
    {
        get
        {
            return OperatorManager.GetByGuId(this.User_ID);
        }
    }
}

当然我不能构造由基类派生的类。但是我需要这个操作员成为我绑定的集合的一部分。

Of course I cannot construct the derived class by the base class. But I need this Operator be part of the collection I bind to...

希望您能理解我的问题并能为您提供帮助。

I hope you understand my problem and can help.

编辑:
这个转换器为我解决了这个问题:

edit: This Converter solved the Problem for me:

public class OperatorConverter:IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            if (!(value is Guid)) return null;
            if (!(parameter is string)) return null;

            var guid = (Guid)value;
            var par = (string)parameter;

            var op = OperatorManager.GetByGuId(guid);
            if (op == null) return null;

            var prop = op.GetType().GetProperty(par);
            if (prop == null) return null;

            return prop.GetValue(op, null);
        }
        catch (Exception e)
        {
            throw (e);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();

    }
}

在XAML中:

<DataGridTextColumn Header="Name" Binding="{Binding Path=User_ID,Converter={StaticResource ResourceKey=operatorConverter},ConverterParameter='Name'}" IsReadOnly="True" />


推荐答案

以下是实现类似于以下内容的几种绑定的三种方法

Here are three ways to achieve several bindings similar to what you need to do.

1)包装类:

public class ProfileUserWrapper : DependencyObject
{
    public ProfileUserWrapper(ProfileUser thebrain) { TheUser = thebrain; }

    public ProfileUser TheUser { get; private set; }

    public Operator User { get { if (_user != null)return _user; return _user = OperatorManager.GetByGuId(TheUser.User_ID); } }
    private Operator _user = null;
}

现在,而不是使用 public EntityCollection< ProfileUser> ; ProfileUsers ,您可能会暴露例如 IEnumerable< ProfileUserWrapper>

Now, instead of having a public EntityCollection<ProfileUser> ProfileUsers you may expose for example IEnumerable<ProfileUserWrapper>:

public EntityCollection<ProfileUser> ProfileUsers // your original code
{
    get{ if (profile != null) return profile.ProfileUser; else return null;}
    set { profile.ProfileUser = value; }
}

public IEnumerable<ProfileUserWrapper> ProfileUsers2
{
    get { return ProfileUsers.Select(user => new ProfileUserWrapper(user));
}

然后绑定到ProfileUsers2,并且您的某些绑定应从地址到 TheUser.Address,但这几乎肯定可以使用。

then bind to the ProfileUsers2, and some of your bindings should be changed from "Address" to "TheUser.Address", but this almost surely will work.

2)其次,是一个智能转换器,例如:

2) second, a smart-converter, for example:

public class OperatorPicker : IValueConverter
{
    public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var pu = value as ProfileUser;
        if (pu != null)
            return OperatorManager.GetByGuId(pu.User_ID);
        return null;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}

写起来几乎没有那么简单。现在,您可以在XAML绑定中使用转换器:

It almost couldn't be simplier to write. Now you can use the converter in the XAML binding:

<Window.Resources>
    <myextra:OperatorPicker x:Key="conv1" />
</Window.Resources>

<Grid>
    <ListBox x:Name="lbxFirst" ItemsSource="{Binding ProfileUsers}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Margin="5" Text="{Binding User_ID}" />
                    <TextBlock Margin="5" Text="{Binding Login}" />
                    <TextBlock Margin="5" Text="{Binding Address}" />
                    <TextBlock Margin="5" Text="{Binding Path=., Converter={StaticResource conv1}}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

但是这样,您将获得 Operator 自我反对。允许您绑定以这种方式返回的运算符的属性非常困难,因为Binding的路径已经固定为。,并且您不能更改它,因为必须向Converter传递一个ProfileUser实例。

But this way, you will get the Operator object it self. It will be hyper-hard to allow you to bind to the properties of operator returned in such way, as the Binding already has path fixed at ".", and you cannot change that, as the Converter must be passed a ProfileUser instance..

3)第三,最复杂但完全没有任何包装的工作是基于附加属性,转换器和两个绑定的,但是您可以在两个附加属性和一个更改回调上也执行此操作。我更喜欢前一种方式,所以在这里是这样:

3) third, most complex but completely working without any wrappers is based on an attached property, converter and a two bindings, but you could do it also on two attached properties and one change callback. I prefer the former way, so here it is:

public class DummyClass : DependencyObject
{
    public static readonly DependencyProperty TheOperatorProperty = DependencyProperty.RegisterAttached(
        "TheOperator", typeof(Operator), typeof(DummyClass),
        new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)
    );

    public static Operator GetTheOperator(DependencyObject elem) { return (Operator)elem.GetValue(TheOperatorProperty); }
    public static void SetTheOperator(DependencyObject elem, Operator value) { elem.SetValue(TheOperatorProperty, value); }
}

    ... xmlns:myextra="clr-namespace:...." ....

<Window.Resources>
    <myextra:OperatorPicker x:Key="conv1" />
</Window.Resources>

<Grid>
    <ListBox x:Name="lbxFirst" ItemsSource="{Binding ProfileUsers}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel x:Name="aparent" Orientation="Horizontal"
                            myextra:DummyClass.TheOperator="{Binding Path=., Converter={StaticResource conv1}}">
                    <TextBlock Margin="5" Text="{Binding User_ID}" />
                    <TextBlock Margin="5" Text="{Binding Login}" />
                    <TextBlock Margin="5" Text="{Binding Address}" />
                    <TextBlock Margin="5"
                               Text="{Binding Path=(myextra:DummyClass.TheOperator).OperatorCodename, ElementName=aparent}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

请注意,在StackPanel级别有一个新的绑定。可以任何地方将其放置在数据模板中,甚至可以放置在文本框本身上。注意它是如何通过转换器将ProfileUser转换为Operator的。 Path =。不是必需的,但是我添加了它,因此显示了绑定的确切含义。请注意最后一个文本框绑定是如何指定的:这是绑定到该附加属性(通过element-name)的绑定,而不是原始数据的绑定!

Please note that there is a new binding at the level of StackPanel. This one can be placed anywhere in the data template, even on the textbox itself. Note how it translates a ProfileUser into an Operator via a converter. The Path=. is not required, but I added it so the exact meaning of the binding is shown. Note how the last textbox binding is specified: it is a binding to that attached property (via element-name), not to the original data!

这一次,我已经测试了所有内容,它在我这边工作,在ProfileUser上没有DependencyObject继承。它对 DummyClass 继承感到满意。如果您尝试这样做,请照常给我留言:)

This time I've tested everything and it works on my side with no DependencyObject inheritance on the ProfileUser. it is satisfied by the DummyClass inheritance. If you try this, please drop me a note as usual :)

这篇关于在ViewModel中向实体类添加属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆