简体   繁体   English

如何在不违反MVVM的情况下将项目追加到ListBox

[英]How do I append items to a ListBox without violating MVVM

I have set up a MVVM design pattern to the WPF application and I'm trying to think of the best way to append listbox items to a listbox and am assuming this should be done in the viewmodel. 我已经为WPF应用程序设置了MVVM设计模式,并且正在尝试考虑将列表框项追加到列表框的最佳方法,并假定应该在viewmodel中完成。 If this is the case, then i'm stuck. 如果是这样,那么我就被困住了。 My mainwindow holds a contentcontrol that pulls in the appropriate view as a usercontrol. 我的主窗口包含一个contentcontrol,它作为用户控件进入适当的视图。 I'm assuming I would have to bind the itemssource of the listbox to a property in the viewmodel but I'm not sure how to attempt this as I don't have access to the listbox in the camera view. 我假设我必须将列表框的itemssource绑定到viewmodel中的属性,但是我不确定如何尝试此操作,因为我没有访问相机视图中的列表框的权限。

Should the dynamic data just pull in the items in the user controls constuctor (this seems wrong but would work). 如果动态数据只是拉入用户控件构造器中的项目(这似乎是错误的,但可以使用)。

Any thoughts? 有什么想法吗?

No frameworks are used, custom MVVM pattern. 没有使用框架,自定义MVVM模式。

User Control 用户控制

<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>

ViewModel 视图模型

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
}

Currently this works and will display the listbox, however need a good way of merging what is in the camerarepository into the listbox. 目前,此方法有效,并且将显示列表框,但是需要一种很好的方式将camerarepository中的内容合并到列表框中。

Based on the code samples you provided you need to add the following to your <ListBox> : 根据您提供的代码示例,您需要将以下内容添加到您的<ListBox>

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

This assumes that your CameraListViewModel is the UserControl 's data context, or perhaps the Window 's context. 假设您的CameraListViewModelUserControl的数据上下文,或者是Window的上下文。 If not, you will need to set the Source attribute of the binding. 如果不是,则需要设置绑定的Source属性。

If you're wondering if you've coded your ViewModel properly (with the constructor loading the cameras), I would say that it looks fine assuming it works. 如果您想知道是否已经正确编码了ViewModel(构造函数正在加载相机),我想假设它可以正常工作就可以了。

I'm still not 100% sure what you're asking, so I hope this answers your question. 我仍然不确定您要问什么,所以我希望这能回答您的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM