【问题标题】:Binding a ListBox to an ObservableCollection of ViewModels将 ListBox 绑定到 ViewModel 的 ObservableCollection
【发布时间】:2012-12-16 09:53:52
【问题描述】:

使用 MVVM 将 ListBox 的项绑定到 ViewModel 时是否有约定?

在下面的 XAML 中,我正在创建一个按钮列表框。 ListBox 绑定到我的 ViewModel 中的一个可观察集合。然后我想将按钮的 Command 属性绑定到 ICommand。问题是当我添加该绑定时,我绑定的是数据对象,而不是 ViewModel。

我是否只是将 MyListOfDataObjects 属性更改为 ViewModel 列表?如果是这样,我在哪里实例化这些新对象?我更喜欢使用依赖注入,因为它们会有多个依赖项。我是否更改 GetData lambda?

总的来说:这里有什么好的做法?尽管我认为这种情况相当普遍,但我找不到任何示例。

我正在使用 MVVMLight 框架,但我愿意查看任何其他框架。

<Window x:Class="KeyMaster.MainWindow"
        DataContext="{Binding Main, Source={StaticResource Locator}}">

    <Window.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="MyDataTemplate">
                <Button Command="{Binding ButtonPressedCommand}"
                        CommandParameter="{Binding .}"
                        Content="{Binding Name}" />
            </DataTemplate>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <ListBox ItemsSource="{Binding MyListOfDataObjects}"
                 ItemTemplate="{StaticResource MyDataTemplate}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal"
                                IsItemsHost="True" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ListBox>
    </Grid>
</Window>

我正在使用标准的 MVVMLight ViewModel:

using GalaSoft.MvvmLight;
using KeyMaster.Model;
using System.Collections.ObjectModel;

namespace KeyMaster.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        private readonly IDataService _dataService;
        private ObservableCollection<MyData> _myListOfDataObjects;

        public MainViewModel(IDataService dataService)
        {
            _dataService = dataService;
            _dataService.GetData(
                (item, error) =>
                {
                    if (error != null)
                    {
                        return;
                    }

                    MyListOfDataObjects = new ObservableCollection<MyData>(item);
                });
        }

        public ObservableCollection<MyData> MyListOfDataObjects
        {
            get { return _myListOfDataObjects; }
            set
            {
                if (_myListOfDataObjects == value) return;

                _myListOfDataObjects = value;
                RaisePropertyChanged(() => MyListOfDataObjects);
            }
        }
    }
}

谢谢。

【问题讨论】:

  • “我绑定的是数据对象,而不是 ViewModel”是什么意思
  • @Blachshma 我的意思是按下按钮时调用的 ButtonPressedCommand 将是在 MyData 类中定义的,而不是在 MainViewModel 类中定义的。

标签: wpf xaml mvvm listbox


【解决方案1】:

在 MVVM 中,原始数据(也称为 Model)和 ViewModel 之间有明显的分离。 ViewModel 负责解析数据,甚至在将数据传递给 View 之前将其修改为所需的任何形式。

一个简单的例子是将模型作为 XML 并让 ViewModel 解析它,只从每个元素中获取特定属性(例如“Name”)并将它们添加到列表中。视图中只会显示此列表。

也就是说,我想你可以看到我要去的地方 - 命令应该在 ViewModel 中 而不是 在 Model 中。正如您自己所说,您应该将尽可能多的 UI 逻辑排除在 VM 和模型之外。

如果您有一个特定命令对某种类型的数据执行特定操作,您可以希望它在更“通用”类型的 ViewModel 中,您可以使用CanExectue 仅在特定情况下允许此命令。但是,该命令仍应位于 ViewModel 中。

在您的具体情况下,我认为 ViewModel 中的命令没有问题,并且当它被提出时,它将对您的数据执行任何您需要的操作。您不需要 ViewModel 的列表,您只需要一个。

【讨论】:

    【解决方案2】:

    我会说这取决于您想要按键功能的位置。如果它总是与 MyData 对象相关,那么(如果可能的话)将 Command 放在 MyData 对象中是否不合适? (ps。我不会因为您向它们添加命令属性而调用您的 MyData 对象 ViewModels,因为它们与视图无关)

    或者,如果您希望在 VM 中使用命令,则可以尝试使用窗口的数据上下文绑定命令。即类似的东西;

    <Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ButtonPressedCommand}"
                        CommandParameter="{Binding .}"
                        Content="{Binding Name}" />
    

    虽然我过去曾遇到过麻烦,但我还是将命令添加到各个对象。

    【讨论】:

    • 这会将 Command 绑定到 MainWindow 类,而不是 MainWindowViewModel。更改 DataContext.ButtonPressedCommand} 的路径可以解决这个问题。
    • 我对此进行了更多思考,也许这更像是我在 MVVM 中展示我的天真的一个实例,但我认为其中一个目标是尽可能多地保留 UI 逻辑的数据对象。为此,我在一个单独的项目中定义了数据类,该项目由应用程序的其他部分使用。将命令添加到此类后,我需要将项目的引用添加到 WPF。由于数据层也被 Web 服务使用,这看起来很不自然。
    • @Josh 感谢您指出更正。是的,我同意你的看法。如果它是一个只在一个视图中使用的命令,那么将它放在对象中就不好了。我想如果你绑定到 MainWindowViewModel 你会有一个方法,其中包含你集合中所有项目的 switch 语句,这也是不需要的。也许您可以专门为继承 MyData 对象的该集合创建一个新对象 - 这就是您在提到 ViewModel 列表时所暗示的吗?
    • 我认为您对从 MyData 继承的对象集合的想法与我一开始的想法相似。同样,我只是假设这个问题会有一个既定的模式。
    • @Josh 如果你找到了请告诉我
    猜你喜欢
    • 2014-09-28
    • 1970-01-01
    • 2018-09-11
    • 2013-12-31
    • 1970-01-01
    • 2018-05-10
    • 1970-01-01
    • 2013-10-15
    • 2015-08-04
    相关资源
    最近更新 更多