Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/267.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ListBox中大数据集的区域或项目资源_C#_Wpf_Prism_Mef_Prism 4 - Fatal编程技术网

C# ListBox中大数据集的区域或项目资源

C# ListBox中大数据集的区域或项目资源,c#,wpf,prism,mef,prism-4,C#,Wpf,Prism,Mef,Prism 4,在以下情况下,我很难找出最佳解决方案。我使用的是Prism 4.1、MEF和.NET4.0 我有一个对象项目,它可能有大量(~1000)个行对象。我正在决定是否最好从我的ProjectViewModel中公开一个ObservableCollection,然后在那里手动创建线视图模型,或者将列表框设置为它自己的区域并以这种方式激活视图 我仍然希望我的LineViewModel注入Prism的共享服务(IEventAggregator等),但我不知道在手动创建LineViewModel时如何做到这一

在以下情况下,我很难找出最佳解决方案。我使用的是Prism 4.1、MEF和.NET4.0

我有一个对象
项目
,它可能有大量(~1000)个
对象。我正在决定是否最好从我的
ProjectViewModel
中公开一个
ObservableCollection
,然后在那里手动创建线视图模型,或者将列表框设置为它自己的区域并以这种方式激活视图

我仍然希望我的
LineViewModel
注入Prism的共享服务(IEventAggregator等),但我不知道在手动创建
LineViewModel
时如何做到这一点。有什么建议或想法吗

编辑:我最初的想法:

项目:

public class Project
{
    public List<Line> Lines { get; set; }
}
[Export(typeof(ProjectViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class ProjectViewModel : NotificationObject, IRegionMemberLifetime
{
    private Project _localProject;

    /* 
        HERE WILL BE SOME PROPERTIES LIKE COST, PRICE THAT ARE CUMULATIVE FROM THE Lines 
     */

    public ObservableCollection<LineViewModel> Lines { get; private set; }

    private readonly IEventAggregator _eventAggregator;

    [ImportingConstructor]
    public ProjectViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        _eventAggregator.GetEvent<ProjectLoaded>().Subscribe(SetupProject, false);
        Lines = new ObservableCollection<LineViewModel>();
    }

    private void SetupProject(Project project)
    {
        _localProject = project;

        foreach(var l in _localProject.Lines)
        {
            LineViewModel lvm = new LineViewModel(l);
            lvm.PropertyChanged += // Some handler here
            Lines.Add(lvm);
        }
    }

    public bool KeepAlive
    {
        get { return false; }
    }
}
public class LineViewModel : NotificationObject
{
    private Line _localLine;

    public decimal Cost
    {
        get { return _localLine.Cost; }
        set
        {
            _localLine.Cost = value;
            RaisePropertyChanged(() => Cost);
        }
    }

    public LineViewModel(Line incoming)
    {
        _localLine = incoming;
    }
}

要使用Prism/MEF手动创建LineViewModels,可以使用容器解析依赖项,这就是它的用途

比如说,

LineViewModel line = container.GetExportedValue<LineViewModel>();
LineViewModel line=container.GetExportedValue();
请参阅此链接:

我有点担心您的设计,您的每一行是否真的需要有一个ViewModel,由容器创建并注入依赖项?是否可能有一个对象管理所有的行并具有这些注入的依赖项?也许某种类型的存储库模式可能会使您受益


如果要通过容器解析数千个对象,可能会有相当大的开销。Prism的书还提到这可能不是一个好主意

我在这里可能有点离谱,也许这太简单了,但这对你有帮助吗?我创建了一个快速项目,演示了一些基本知识。如果你需要更多的信息,也许我可以用它来帮助你

看法


谢谢你的回复。如果你不介意的话,我对我的设计有点困惑,所以我不确定我想做什么。如上所述,我有一个带有ProjectView/ViewModel的项目对象。这个项目有行,我想在列表框中显示。这些行需要能够通知ProjectViewModel属性更改,以便项目模型可以(例如)重新计算成本。项目对象来自反序列化的XML,并且已经包含了它的行。我有一些对象需要从XML文件中读取并放入列表中。该“列表”作为单个对象绘制在图形上,该列表还添加到列表框中,以创建一个图形图例,允许我配置表示列表的图形对象的可见性和颜色。因此,在我的例子中,对象是从XML读取的,可能存储在ObservableCollection中,ViewModel包含该集合并公开名称、颜色和可见属性(例如)。然而,在某些方面,我可能和你有相同的问题。我还没有解决这个问题,但是如果这些对象的属性可以更改,那么图表可能需要更新以反映这种更改。对于我来说,我将有一个代表整个列表的graph对象,我想该对象将需要处理CollectionChanged事件,并将事件处理程序连接/取消连接到应实现INotifyPropertyChanged的各个对象。然后,对象作为一个整体可以重新计算它需要什么,并更新自身。这可能是几千个事件处理程序,但也可以,因为只有少数事件处理程序会同时更改。无论如何,在我看来,您的行实际上可能更多地是您的模型,而不是ViewModel。我没有理由让容器解析我的对象,它们只是从文件中读取。正确,我的行是模型的一部分…它们在项目对象上。但是因为我将通过UI与行上的属性交互,所以我打算创建一个集合LineViewModel对象并将其绑定到ListBox。我只是不确定这样做是否正确。我的模型对象没有实现INotifyPropertyChanged,所以不管怎样,我都需要将它们包装到viewmodel中。这与我最初的设计非常接近。区别在于1)我的线条对象上没有事件,2)我的ProjectViewModel将是线条ObservableCollection的所有者。我仍然认为拥有一个LineViewModels集合对我有好处,每个集合都包含一个Line对象…它将充当Line对象的代理,因为该行没有任何事件或实现INotifyPropertyChanged。请考虑订单输入系统。您有一个订单,然后是行项目。订单具有某些属性,这些属性的计算基于行项目。行项目对象非常基本(只是一组自动属性;成本、价格、数量)。我认为一个新对象(LineViewModel)将保留一个行项目对象,并控制设置行项目的属性。我还认为“Order”(我的ProjectViewModel)对象应该拥有所有这些LineViewModels。另外,非常感谢您花时间编写一个示例应用程序。虽然这不完全是我想要的,但您能抽出时间帮助我真是太好了。@Ryan如果您的行没有实现INotifyPropertyChanged并且没有事件,那么当您将它们包装到ViewModel中时,您如何检测它们的更改?似乎你必须更新你的成本或其他什么。我添加了代码来进一步解释我是如何考虑设置这个的。啊,我明白了。看起来不错,也许你应该继续前进,看看结果如何。至于使用DI,只需将LineViewModel更改为具有Line属性,而不是将其传递到构造函数中。使用容器解析LineViewModel(从而获得注入的依赖项),然后设置LineViewModel.Line=l;你应该可以走了。
    <Window x:Class="WpfApplication1.LinesView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="LinesView" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="247" d:DesignWidth="348" SizeToContent="WidthAndHeight" Width="350" Height="250">
    <Window.Resources>
        <DataTemplate x:Key="LineView">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="Auto" MinWidth="50"/>
                </Grid.ColumnDefinitions>

                <TextBlock Grid.Row="0" Grid.Column="0" Text="Line: " />
                <TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Name}" />

                <TextBlock Grid.Row="1" Grid.Column="0" Text="X: " />
                <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding X}" />

                <TextBlock Grid.Row="2" Grid.Column="0" Text="Y: " />
                <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Y}" />
            </Grid>
        </DataTemplate>
    </Window.Resources>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="Total Cost" Margin="5" />
            <TextBlock Text="{Binding Cost}" Margin="5" />
        </StackPanel>
        <ContentControl Name="contentControl1" Content="{Binding ElementName=listBox1, Path=SelectedItem}" ContentTemplate="{StaticResource LineView}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="105" Margin="5" />
        <ListBox Height="234" 
                 HorizontalAlignment="Center"
                 Name="listBox1" 
                 VerticalAlignment="Center"
                 ItemsSource="{Binding Lines}"
                 ItemTemplate="{StaticResource LineView}" Width="152" Margin="5" />
    </StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WpfApplication1.Models;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace WpfApplication1
{
    public class LinesViewModel : INotifyPropertyChanged
    {
        public int Cost
        {
            get
            {
                return Lines.Sum(x => x.X + x.Y); 
            }
        }

        public ObservableCollection<Line> Lines
        {
            get;
            private set;
        }

        public LinesViewModel()
        {
            Lines = new ObservableCollection<Line>();
            Lines.Add(new Line()
            {
                Name = "Line1",
                X = 0,
                Y = 1
            });
            Lines.Add(new Line()
            {
                Name = "Line2",
                X = 1,
                Y = 1
            });
            Lines.Add(new Line()
            {
                Name = "Line3",
                X = 2,
                Y = 2
            });

            foreach(Line line in Lines)
            {
                line.XChanged += new EventHandler(lineChanged);
                line.YChanged += new EventHandler(lineChanged);
            }

            Lines.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Lines_CollectionChanged);
        }

        private void Lines_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null)
            {
                foreach (Line line in e.NewItems)
                {
                    line.XChanged += new EventHandler(lineChanged);
                    line.YChanged += new EventHandler(lineChanged);
                }
            }
            if (e.OldItems != null)
            {
                foreach (Line line in e.OldItems)
                {
                    line.XChanged -= new EventHandler(lineChanged);
                    line.YChanged -= new EventHandler(lineChanged);
                }
            }
        }

        private void lineChanged(object sender, EventArgs e)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("Cost"));
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace WpfApplication1.Models
{
    public class Line
    {
        private int x;
        private int y;

        public String Name { get; set; }

        public int X
        {
            get
            {
                return x;
            }
            set
            {
                x = value;
                XChanged(this, EventArgs.Empty);
            }
        }

        public int Y
        {
            get
            {
                return y;
            }
            set
            {
                y = value;
                YChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler XChanged = delegate { };
        public event EventHandler YChanged = delegate { };
    }
}