无论如何设置ListView列共享的行的'DataContext'?

时间:2010-11-22 03:55:56

标签: c# wpf listview datacontext

这是我能想到的最好的方式来表达我的问题,这是场景:我有一个ListView绑定到一个对象的集合。每个对象都有一个属性UserID,它只是User对象的引用ID。在我的ListView中,我希望显示对象和User的多个属性。为此,我创建了一个实现MultiValueConverter的类,用作用户对象的查找表。所以我使用了一个multibinding,它传递了值转换器UserID和一个由底层ViewModel公开的字典查找表。

除了我希望有一种方法可以设置DataContextListView列共享的“行”之外,这一切都很好用。通过这种方式,我可以将我的值转换器更改为仅返回User对象而不是用户对象的特定属性。然后我可以绑定到DataContext的属性。我不想为我希望公开的每个User属性创建一个新的值转换器。我能想到的另一种方法是将属性名称传递给值转换器并使用反射。

有什么想法吗?我意识到我梦寐以求的DataContext是绑定到ListView的{​​{1}}的数据对象的工作,但也许我还可以使用其他东西。附加属性似乎解决了我所遇到的每个WPF问题所以我认为解决方案与使用ItemsSource创建这个'datacontext'

有关

我确信有人会告诉我从数据对象本身公开User对象,而不是使用一些使用用户ID和查找表的向后方法,但是,我这样做是有原因的。感谢。

AttachedProperty

转换器:

<ListView.View>
    <GridView>
        <GridViewColumn>
            <GridViewColumn.Header>User</GridViewColumn.Header>
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock MinWidth="120">
                        <TextBlock.Text>
                            <MultiBinding Converter="{StaticResource UserIDConverter}">
                                <Binding Path="UserID" />
                                <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=UserControl}" Path="DataContext.Users"/>
                            </MultiBinding>
                        </TextBlock.Text>
                    </TextBlock>
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
    </GridView>
</ListView.View>

2 个答案:

答案 0 :(得分:0)

如果您可以使用PhoneUser填充数据对象,而不仅仅是ID,那么就更容易了,那么您可以这样做:

<DataTemplate>
  <StackPanel>
    <TextBlock MinWidth="120" Text="{Binding Path="User.FirstName}">
    </TextBlock>
    <TextBlock MinWidth="120" Text="{Binding Path="User.LastName}">
    </TextBlock>
  </StackPanel>
</DataTemplate>

类结构看起来像这样:

public class myDataObject //The data object you already have.
{
    public string value1;
    public string value2;
    public PhoneUser User; //currently you have "UserID" here.
}

public class PhoneUser
{
    public string FirstName;
    public string LastName;
}

如果在首次加载数据对象时不适合检索所有用户数据,则可以使用“延迟加载”策略,如下所示:

public class myDataObject //The data object you already have.
{
    public string UserID;
    public string value2;
    private PhoneUser _User; 
    public PhoneUser User
    {
        get
        {
            if(_User==null)
                _User = getUserFromDatabase(UserID);
            return _User;
        }
    }
}

我相信你可以在不改变代码结构的情况下做到这一点。

答案 1 :(得分:0)

因此,如果我理解正确,您希望转换器只返回整个PhoneUser对象,然后让每列确定要抓取PhoneUser的哪个属性?

如果您真的要坚持使用这种复杂的方法,我认为您的反思意见(将属性名称传递给转换器并使用反射来返回值)将是最好的。


那就是说,我无法拒绝给出你不想听到的答案(即使它对你没有帮助,也可能对别人有所帮助)。这是我真正建议你做的......

  1. 创建一个结合当前对象(比如名为Foo)和PhoneUser的类。

    public class FooPhoneUser
    {
        Foo Foo { get; set; }
        PhoneUser User { get; set; }
    }
    
  2. 使用LINQ将这两个类组合在一起:

    var FooPhoneUsers = 
        from
            f in Foos
        join
            pu in PhoneUsers on f.UserId equals pu.Id
        select
            new FooPhoneUser { Foo = f, User = pu };
    
  3. GridViewColumn中删除所有绑定标记,然后输入这样的内容:

    <TextBlock MinWidth="120" Text={Binding User.LastName} />
    

    <TextBlock MinWidth="120" Text={Binding Foo.SomeOtherProp} />