【问题标题】:How do I append items to a ListBox without violating MVVM如何在不违反 MVVM 的情况下将项目附加到 ListBox
【发布时间】:2011-09-19 20:17:47
【问题描述】:

我已经为 WPF 应用程序设置了一个 MVVM 设计模式,我正在尝试考虑将列表框项附加到列表框的最佳方法,并假设这应该在视图模型中完成。如果是这样的话,那我就卡住了。我的主窗口包含一个内容控件,该控件将适当的视图作为用户控件拉入。我假设我必须将列表框的 itemssource 绑定到视图模型中的属性,但我不确定如何尝试此操作,因为我无权访问相机视图中的列表框。

动态数据是否应该只拉入用户控件构造函数中的项目(这似乎是错误的,但会起作用)。

有什么想法吗?

没有使用框架,自定义 MVVM 模式。

用户控制

<ListBox x:Name="CameraList" Background="#ff4c4c4c" BorderThickness="0" 
 ScrollViewer.CanContentScroll="False" TouchEnter="CameraList_TouchEnter" 
 TouchLeave="CameraList_TouchLeave" 
 ManipulationBoundaryFeedback="CameraList_ManipulationBoundaryFeedback"
 ItemContainerStyle="{DynamicResource ResourceKey=ListBoxItemStyle}" 
 PreviewTouchDown="CameraList_PreviewTouchDown" 
 PreviewTouchMove="CameraList_PreviewTouchMove" 
 PreviewTouchUp="CameraList_PreviewTouchUp" 
 HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <ListBox.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="/ResourceLibrary;component/User 
                 Controls/Slider.xaml">
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </ListBox.Resources>
</ListBox>

视图模型

class CameraListViewModel : WorkspaceViewModel
{
    #region Fields
    private readonly CameraRepository cameraRepository;
    #endregion


    #region Properties
    /// <summary>
    /// Gets and sets the cameras in the system.
    /// </summary>
    public ObservableCollection<CameraViewModel> Cameras { get; private set; }
    #endregion


    #region Constructors
    public CameraListViewModel(CameraRepository cameraRepository)
    {
        if (cameraRepository == null)
        {
            throw new ArgumentNullException("cameraRepository");
        }

        base.DisplayName = "CameraList";

        this.cameraRepository = cameraRepository;

        // Populate the CameraList collection with CameraViewModel.
        this.CreateCameras();
    }
    #endregion


    #region Internal Members
    /// <summary>
    /// Create all the cameras in the system.
    /// </summary>
    private void CreateCameras()
    {
        List<CameraViewModel> all =
            (from cam in cameraRepository.GetCameras()
             select new CameraViewModel(cam, cameraRepository)).ToList();

        foreach (CameraViewModel cvm in all)
        {
            cvm.PropertyChanged += this.OnCameraViewModelPropertyChanged;
        }

        this.Cameras = new ObservableCollection<CameraViewModel>(all);
        this.Cameras.CollectionChanged += this.OnCollectionChanged;
    }
    #endregion


    #region Events
    /// <summary>
    /// Handle changed collections.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null && e.NewItems.Count != 0)
        {
            foreach (CameraViewModel cvm in e.NewItems)
            {
                cvm.PropertyChanged += this.OnCameraViewModelPropertyChanged;
            }
        }

        if (e.OldItems != null && e.OldItems.Count != 0)
        {
            foreach (CameraViewModel cvm in e.OldItems)
            {
                cvm.PropertyChanged -= this.OnCameraViewModelPropertyChanged;
            }
        }
    }

    /// <summary>
    /// Handle property changes.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnCameraViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        string isSelected = "IsSelected";

        // Make sure that the property name we're referencing is valid.
        // This is a debugging technique, and does not execute in a Release build.
        (sender as CameraViewModel).VerifyPropertyName(isSelected);

        // When a camera is selected or unselected, we must let the system know
        // that properties have changed, so that it will be queried again for a new value.
        if (e.PropertyName == isSelected)
        {
            this.OnPropertyChanged("IsSelected");
        }
    }
    #endregion
}

目前这可以工作并将显示列表框,但是需要一种将 camerarepository 中的内容合并到列表框的好方法。

【问题讨论】:

  • 你是对的,这应该在视图模型中完成,但你没有提供足够的信息来回答你的问题。有很多方法可以做到这一点,但这在很大程度上取决于您如何设置系统,是否使用任何 MVVM 框架等。
  • 我在上面添加了一些逻辑来帮助澄清。
  • MVVM 是关于 Context...DataContext,在这种情况下。假设您的父视图将您的 ViewModel 作为 DataContext,那么任何子控件(甚至是 UserControls)也将具有相同的 DataContext(除非您专门将其设置为不同的东西)。您应该能够简单地将您的 ListBox ItemsSource 绑定到要显示的字符串集合。
  • 关于 EtherDragon 的响应,所以如果我的主窗口里面有用户控件,我应该能够在用户控件中检索 CameraList。那么我应该能够将相机列表中的项目源绑定到主窗口视图模型或相机列表视图模型中的项目源?

标签: c# wpf mvvm


【解决方案1】:

根据您提供的代码示例,您需要将以下内容添加到您的&lt;ListBox&gt;

<ListBox ItemsSource="{Binding Path=Cameras}" ...>

这假定您的CameraListViewModelUserControl 的数据上下文,或者可能是Window 的上下文。如果没有,则需要设置绑定的Source 属性。

如果您想知道您的 ViewModel 是否正确编码(构造函数加载相机),我会说它看起来很好,假设它可以工作。

我仍然不能 100% 确定你在问什么,所以我希望这能回答你的问题。

【讨论】:

  • 这正是我正在寻找的,我认为这是要走的路,但在我开始之前需要反馈。 :) 谢谢大家。
猜你喜欢
  • 1970-01-01
  • 2011-08-20
  • 2016-05-04
  • 2020-08-04
  • 1970-01-01
  • 1970-01-01
  • 2015-09-28
  • 2022-11-16
相关资源
最近更新 更多