ObservableCollection未更新View

Dav*_*can 12 c# wpf observablecollection mvvm

我刚开始使用MVVM并遇到了障碍,我希望有人可以帮助我.我正在尝试使用2个列表框创建一个简单的视图.第一个列表框中的选择将填充第二个列表框.我创建了一个类,用于存储我想要绑定的信息.

MyObject类(Observable Object只是一个实现INotifyPopertyChanged的基类)

public class MyObject : ObservableObject
{
    String _name = String.Empty;
    ObservableCollection<MyObject> _subcategories;

    public ObservableCollection<MyObject> SubCategories
    {
        get { return _subcategories; }

        set
        {
            _subcategories = value;
            RaisePropertyChanged("SubCategories");
        }
    }

    public String Name
    {
        get { return _name; }
        set
        {
            _name = value;
            RaisePropertyChanged("Name");
        }
    }


    public MyObject()
    {
        _subcategories = new ObservableCollection<EMSMenuItem>();
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的viewmodel中,我创建了两个ObservableCollections

public ObservableCollection<EMSMenuItem> Level1MenuItems { get; set; }
public ObservableCollection<EMSMenuItem> Level2MenuItems { get; set; }
Run Code Online (Sandbox Code Playgroud)

在我的ViewModel的构造函数中,我有:

this.Level1MenuItems = new ObservableCollection<EMSMenuItem>();
this.Level2MenuItems = new ObservableCollection<EMSMenuItem>();
this.Level1MenuItems = LoadEMSMenuItems("Sample.Xml");
Run Code Online (Sandbox Code Playgroud)

这适用于Level1项目,它们在视图中正确显示.但是,当用户单击列表框中的项目时,我会调用一个命令,该命令具有以下内容:

Level2MenuItems = ClickedItem.SubCategories;
Run Code Online (Sandbox Code Playgroud)

由于某种原因,这不会更新第二个列表框的UI.如果我在这个位置放置一个断点,我可以看到Level2MenuItems中存储了正确的信息.如果我编写一个foreach循环并将它们单独添加到Level2MenuItems集合中,那么它会正确显示.

另外作为测试,我将以下内容添加到构造函数中:

Level2MenuItems = Level1MenuItems[0].SubCategories;
Run Code Online (Sandbox Code Playgroud)

而且更新正确.

那么为什么代码在构造函数中按预期工作,或者在循环时,而不是在用户单击列表框中的项目时?

aqw*_*ert 12

您需要在Level2MenuItems属性上提出更改通知.

而不是拥有

public ObservableCollection<EMSMenuItem> Level2MenuItems { get; set; }
Run Code Online (Sandbox Code Playgroud)

你需要

private ObservableCollection<EMSMenuItem> _level2MenuItems;
public ObservableCollection<EMSMenuItem> Level2MenuItems
{
    get { return _level2MenuItems; }
    set 
     {
        _level2MenuItems = value; 
        RaisePropertyChanged("Level2MenuItems");
     }
 }
Run Code Online (Sandbox Code Playgroud)

前者在构造函数中工作的原因是Binding还没有发生.但是,由于您通过命令执行更改引用,这在绑定之后发生,您需要告诉视图它已更改

  • 我有完全相同的问题,但即使在我添加 raisepropertychanged 之后,我的问题也没有更新 (4认同)

Sco*_*rod 6

您需要使 ObservableCollection 中的 poco 类实现 INotifyPropertyChanged。

例子:

<viewModels:LocationsViewModel x:Key="viewModel" />
.
.
.    
<ListView
    DataContext="{StaticResource viewModel}"
    ItemsSource="{Binding Locations}"
    IsItemClickEnabled="True"
    ItemClick="GroupSection_ItemClick"
    ContinuumNavigationTransitionInfo.ExitElementContainer="True">

    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Name}" Margin="0,0,10,0" Style="{ThemeResource ListViewItemTextBlockStyle}" />
                <TextBlock Text="{Binding Latitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="0,0,5,0"/>
                <TextBlock Text="{Binding Longitude, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Style="{ThemeResource ListViewItemTextBlockStyle}" Margin="5,0,0,0" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

public class LocationViewModel : BaseViewModel
{
    ObservableCollection<Location> _locations = new ObservableCollection<Location>();
    public ObservableCollection<Location> Locations
    {
        get
        {
            return _locations;
        }
        set
        {
            if (_locations != value)
            {
                _locations = value;
                OnNotifyPropertyChanged();
            }
        }
    }
}

public class Location : BaseViewModel
{
    int _locationId = 0;
    public int LocationId
    {
        get
        {
            return _locationId;
        }
        set
        {
            if (_locationId != value)
            {
                _locationId = value;
                OnNotifyPropertyChanged();
            }
        }
    }

    string _name = null;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            if (_name != value)
            {
                _name = value;
                OnNotifyPropertyChanged();
            }
        }
    }

    float _latitude = 0;
    public float Latitude 
    { 
        get
        {
            return _latitude;
        }
        set
        {
            if (_latitude != value)
            {
                _latitude = value;
                OnNotifyPropertyChanged();
            }
        }
    }

    float _longitude = 0;
    public float Longitude
    {
        get
        {
            return _longitude;
        }
        set
        {
            if (_longitude != value)
            {
                _longitude = value;
                OnNotifyPropertyChanged();
            }
        }
    }
}

public class BaseViewModel : INotifyPropertyChanged
{
    #region Events
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion

    protected void OnNotifyPropertyChanged([CallerMemberName] string memberName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(memberName));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)