如何替换静态ObservableCollection,使其可以在MVVM方式的所有窗口上访问

本文关键字:方式 MVVM 访问 窗口 替换 何替换 静态 ObservableCollection | 更新日期: 2023-09-27 18:26:11

Atm我得到了一个带有静态ObservableCollection的类(somerandomclasss):

public static ObservableCollection<PersonViewModel> thepeoplelist = new ObservableCollection<PersonViewModem>();

然而,我正在将我的项目转换为MVVM,当然这不是填充我所有项目的好方法(主要是列表视图)。我有多个窗口以这种方式使用这个源代码。

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    lsvallthepeople.ItemSource = somerandomclasss.thepeoplelist;
}

列表视图将显示所有具有该信息的人。然而,我敢打赌,这不是MVVM的方式,而且我还没有找到一个在没有公共静态ObservableCollection的情况下工作的好方法,但是有一个窗口,你可以在其中获得一个列表视图,你可以编辑人员,他们在SQL数据库和PersonViewModel中得到更新(它得到了INotifyPropertyChanged)。

如果您需要更多信息,请随时询问:)。

如何替换静态ObservableCollection,使其可以在MVVM方式的所有窗口上访问

我相信您的问题是,"在MVVM中跨多个视图共享项目列表的最佳方式是什么?"所以我会这样回答这个问题。

假设您有一个服务,它提供了一种获取人员列表的方法。您称之为"PersonViewModel",但可能会将域实体与ViewModel混淆。在MVVM中,您有一个表示UI控件或屏幕的视图。然后您就有了一个ViewModel,它绑定到视图并将视图连接到数据/域模型。ViewModel可以有许多公共属性,View将绑定到这些属性,包括调用服务以从数据模型中填充这些属性的方法。在您的情况下,我会有一个View+ViewModel,而ViewModel有一个类为"Person"的ObservableCollection属性。

下面的代码是对它实际外观的一种解释。并不是所有的东西都实现了。

public class MyViewModel : INotifyPropertyChanged
{
    public ObservableCollection<Person> People { get; set; }
    public MyViewModel()
    {
        this.People = new ObservableCollection<Person>();
        this.LoadPeople();
    }
    private void LoadPeople()
    {
        this.People.Clear();
        // Have your logic here that loads the people collection
    }
}

至于管理单个列表,我建议将people集合缓存在某种静态类或视图模型可以访问的singleton中。然后上面的LoadPeople方法可以直接从缓存中提取。您甚至可以延迟加载缓存,以便它在第一次访问之前不会发出服务请求。

internal static class SystemContext
{
    private static ObservableCollection<Person> _people = null;
    public static ObservableCollection<Person> People
    {
        get
        {
            if( _people == null )
            {
                _people = new ObservableCollection<Person>();
                // load the list here from a service or something
            }
            return _people;
        }
    }
}

因此,在你的ViewModel中,LoadPeople会看起来像这样:

public void LoadPeople()
{
    this.People.Clear();
    foreach( Person person in SystemContext.People )
    {
        this.People.Add( person );
    }
}

然后,您的UI将看起来像这样:

<ListBox 
    ItemsSource={Binding Path=People, Mode=OneWay}
    SelectedItem={Binding Path=SelectedPerson, Mode=TwoWay}
    >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Vertical">
                <TextBlock Text="{Binding Path=PersonName, Mode=OneWay}" />
                <TextBlock Text="{Binding Path=DateOfBirth, Mode=OneWay}" />
                <!-- etc -->
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

您可以使用Static绑定来绑定ItemsSource,而不是在代码后面手动设置

<ListBox ItemsSource="{Binding Source={
    x:Static local:somerandomclasss.thepeoplelist}}" ... />

或者公开从ViewModel返回集合的属性,并绑定到该属性

public class MyViewModel
{
    public ObservableCollection<PersonViewModel> PersonList
    {
        get { return somerandomclasss.thepeoplelist; }
    }
    ...
}
<ListBox ItemsSource="{Binding PersonList}" ... />

您可能应该将其作为一个服务或存储库,将其注入到需要列表的每个视图模型中(作为抽象)。

由于您只想填充此列表一次,因此可以在服务/存储库实现的构造函数中执行此操作,也可以在服务GetList方法中使用缓存技术。

由于您总是希望将相同的实例传递给每个视图模型,因此您应该使用单例模式,或者如果使用IoC容器,则针对特定实例注册抽象(例如IPeopleRepository)。

由于这将是一个服务/存储库,您应该返回一个不依赖于表示技术的类型,即IEnumerable<T>IList<T>,并使用它在每个视图模型中创建可观察的集合。