如何将 ListView 绑定到 WPF 中单个 ViewModel 中存储的多个集合?

发布于 2024-10-25 05:29:01 字数 2356 浏览 1 评论 0原文

我有 2 个集合,我想绑定到 ListView 中的单独 GridViewColumn

public class EffectView : INotifyPropertyChanged
{

    ObservableCollection<Effect> effects;
    public ObservableCollection<Effect> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "Effects" );
        }
    }

    ObservableCollection<EffectDescription> descriptions;
    public ObservableCollection<EffectDescription> Descriptions
    {
        get { return this.descriptions; }
        set
        {
            this.descriptions = value;
            this.RaisePropertyChanged ( "Descriptions" );
        }
    }
}

我可以这样做:

<ListView ItemsSource="{Binding EffectView.Effects}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding ?}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

但是所有内容的范围都在 EffectView.Effects >,但我希望默认范围为 EffectView,这样我就可以轻松地将多个集合分配给 ListView

比如:

<ListView ItemsSource="{Binding EffectView}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effects Path=Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effects Path=Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Descriptions Path=Usage}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

有什么办法可以做到这一点吗?

I have 2 collections I want to bind to a separate GridViewColumn in a ListView:

public class EffectView : INotifyPropertyChanged
{

    ObservableCollection<Effect> effects;
    public ObservableCollection<Effect> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "Effects" );
        }
    }

    ObservableCollection<EffectDescription> descriptions;
    public ObservableCollection<EffectDescription> Descriptions
    {
        get { return this.descriptions; }
        set
        {
            this.descriptions = value;
            this.RaisePropertyChanged ( "Descriptions" );
        }
    }
}

I can do this:

<ListView ItemsSource="{Binding EffectView.Effects}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding ?}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

But then everything is scoped to EffectView.Effects, but I want the default scope to be EffectView so I can easily assign multiple collections to the ListView.

Something like:

<ListView ItemsSource="{Binding EffectView}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effects Path=Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effects Path=Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Descriptions Path=Usage}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

Any way to accomplish this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

乖乖兔^ω^ 2024-11-01 05:29:02

ListView 的 ItemsSource 是其项目将出现在列表中的集合。因此,请考虑一下您要求 ListView 执行的操作:

  • 作为源集合,使用不是集合但包含它们的内容
  • 对于列表中的每一行,显示一个集合中的一项,以及一个项来自其他集合

请注意第二点:每一行都必须显示 Events 集合中的某些项目和 Descriptions 集合中的某些项目。

它应该从每个项目中选择哪个项目?这两个集合中的项目之间的关系是什么?

看来您真正需要的是一个同时包含事件和描述的对象集合。然后,您可以绑定到该集合以显示两个实体的元素。大致如下:

public class EffectView : INotifyPropertyChanged
{

    ObservableCollection<EffectsAndDescriptions> effects;
    public ObservableCollection<EffectAndDescriptions> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "EffectsAndDescriptions" );
        }
    }

}

internal class EffectsAndDescriptions
{
    public Effect Effect { get; set; }
    public Description Description { get; set; }
}

现在您可以绑定到 EffectsAndDescriptions 集合(请注意,这假设 ListView 的 parent 的 DataContext 是 EffectView

<ListView ItemsSource="{Binding EffectsAndDescriptions}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effect.Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effect.Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Description.Usage}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>

The ItemsSource of a ListView is the collection whose items will appear in the list. So think for a moment about what you're asking the ListView to do:

  • As a source collection, use something that isn't a collection, but contains them
  • For each row in the list, display an item from one collection, and an item from the other collection

Pay attention to that second point: every row must display some item from the Events collection and some item from the Descriptions collection.

Which item shall it pick from each? What's the relationship between the items in the two collections?

It appears that what you really need is a collection of objects that contains both an Event and a Description. You can then bind to that collection to display elements of both entities. Roughly, something like this:

public class EffectView : INotifyPropertyChanged
{

    ObservableCollection<EffectsAndDescriptions> effects;
    public ObservableCollection<EffectAndDescriptions> Effects
    {
        get { return this.effects; }
        set
        {
            this.effects = value;
            this.RaisePropertyChanged ( "EffectsAndDescriptions" );
        }
    }

}

internal class EffectsAndDescriptions
{
    public Effect Effect { get; set; }
    public Description Description { get; set; }
}

Now you can bind to the EffectsAndDescriptions collection (note this assumes the DataContext of the ListView's parent is EffectView)

<ListView ItemsSource="{Binding EffectsAndDescriptions}">
    <ListView.View>
        <GridView>
            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effect.Name}"
                            Header="Name" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Effect.Opacity}"
                            Header="Opacity" />

            <GridViewColumn Width="Auto"
                            DisplayMemberBinding="{Binding Description.Usage}"
                            Header="Description" />
        </GridView>
    </ListView.View>
</ListView>
懒的傷心 2024-11-01 05:29:02

这实际上是不可能的。 ItemsSource 期望传递至少实现 IEnumerable 的内容。即使您在 EffectView 上实现了 IEnumerable,您也需要将 Effect 和 EffectDescription 包装到单个对象中才能返回。

您可以将 ListView 绑定到 Effects 集合,然后使用自定义 IValueConverter 获取 Effect 并返回描述。但我不确定这是否适合您的情况。

最好的选择是包含一个包装对象(即 EffectWithDescription),其中包含您的 Effect 和 EffectDescription。然后公开 EffectWithDescription 对象的集合。不过,您需要确保这个新集合与其他集合保持同步。

That's not really possible. ItemsSource expects to be passed something that, at a minimum, implements IEnumerable. Even if you implemented IEnumerable on your EffectView, you would need to wrap Effect and EffectDescription into a single object to return.

You could bind your ListView to your Effects collection, then use a custom IValueConverter to take the Effect and return a description. But I'm not sure this would fit your situation.

Your best bet would be to include a wrapper object (i.e. EffectWithDescription) that includes both your Effect and your EffectDescription. Then expose a collection of EffectWithDescription objects. You'd need to ensure that this new collection is keep in sync with the other collections though.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文