将列表框绑定到 ObservableCollection
Binding a Listbox to a ObservableCollection
所以我正在尝试绑定以下 ViewModel:
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<ListBoxItem> _PlacesOrCities;
public ObservableCollection<ListBoxItem> PlacesOrCities
{
get { return _PlacesOrCities; }
set { _PlacesOrCities = value; RaisePropertyChanged("PlacesOrCities"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ViewModel()
{
_PlacesOrCities = new ObservableCollection<ListBoxItem>();
}
}
以下xaml:
<ListBox Name="lbPlacesCity" ItemsSource="{Binding Path=(gms:MainWindow.ViewModel).PlacesOrCities, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate DataType="models:ListBoxItem">
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="{Binding Name}" Visibility="{Binding Visibility}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
在代码隐藏中:
public ViewModel ViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
ViewModel = new ViewModel();
DataContext = ViewModel;
}
并且在触发按钮单击事件时 - 我尝试使用内存列表设置可观察值 collection 的值:
private void StateProvince_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_CurrentSelectionPlaces = Canada.Provinces
.FirstOrDefault(x => x.Abbreviation == _SelectedStateProvince_ShortName)
.Place.OrderBy(x => x.Name).ToList();
foreach (var currentSelectionPlace in _CurrentSelectionPlaces)
{
ViewModel.PlacesOrCities.Add(currentSelectionPlace);
}
}
但似乎有 none 个项目被添加到 collection。我是不是绑定错了?
我已经尝试了很多解决方案,但其中 none 似乎改变了结果——列表中的任何项目都没有正确加载到 collection 中。
编辑:
可能值得注意的是 ViewModel
中看到的 ListBoxItem
是自定义模型:
public class ListBoxItem
{
[J("Name")] public string Name { get; set; }
[J("PostalCodes")] public string[] PostalCodes { get; set; }
public Visibility Visibility { get; set; } = Visibility.Visible;
}
您应该尝试适应 MVVM 模式,因此列表的填充应该出现在视图模型级别而不是视图的代码后面。
您提到您使用了点击事件,而不是这样做,尝试将按钮的命令 属性 绑定到视图模型中的命令,请参阅此 link 的解释几种类型的命令以及如何使用它们:https://msdn.microsoft.com/en-us/magazine/dn237302.aspx
另一方面,如果您已经在 window 构造函数中设置了数据上下文,要绑定 ListBox 项目源,您只需要绑定 属性 的名称,"PlacesOrCities":
<ListBox Name="lbPlacesCity" ItemsSource="{Binding Path=PlacesOrCities, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate DataType="models:ListBoxItem">
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="{Binding Name}" Visibility="{Binding Visibility}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
还建议尝试在没有任何模板的情况下加载列表中的项目,您可以使用 ListBox DisplayMemberPath 属性 来显示名称,一旦能够加载项目,就应用样式。
同样在您使用 ObservableCollection 的方式中,您实际上需要替换整个集合而不是添加到 fire RaisePropertyChanged,请尝试使用普通的 属性。
public ObservableCollection<ListBoxItem> PlacesOrCities {get;set;} = new ObservableCollection<ListBoxItem>();
修改集合会更新 UI,因此无论何时使用添加或清除,UI 都应该知道。
希望对您有所帮助。
所以我正在尝试绑定以下 ViewModel:
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<ListBoxItem> _PlacesOrCities;
public ObservableCollection<ListBoxItem> PlacesOrCities
{
get { return _PlacesOrCities; }
set { _PlacesOrCities = value; RaisePropertyChanged("PlacesOrCities"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ViewModel()
{
_PlacesOrCities = new ObservableCollection<ListBoxItem>();
}
}
以下xaml:
<ListBox Name="lbPlacesCity" ItemsSource="{Binding Path=(gms:MainWindow.ViewModel).PlacesOrCities, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate DataType="models:ListBoxItem">
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="{Binding Name}" Visibility="{Binding Visibility}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
在代码隐藏中:
public ViewModel ViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
ViewModel = new ViewModel();
DataContext = ViewModel;
}
并且在触发按钮单击事件时 - 我尝试使用内存列表设置可观察值 collection 的值:
private void StateProvince_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
_CurrentSelectionPlaces = Canada.Provinces
.FirstOrDefault(x => x.Abbreviation == _SelectedStateProvince_ShortName)
.Place.OrderBy(x => x.Name).ToList();
foreach (var currentSelectionPlace in _CurrentSelectionPlaces)
{
ViewModel.PlacesOrCities.Add(currentSelectionPlace);
}
}
但似乎有 none 个项目被添加到 collection。我是不是绑定错了?
我已经尝试了很多解决方案,但其中 none 似乎改变了结果——列表中的任何项目都没有正确加载到 collection 中。
编辑:
可能值得注意的是 ViewModel
中看到的 ListBoxItem
是自定义模型:
public class ListBoxItem
{
[J("Name")] public string Name { get; set; }
[J("PostalCodes")] public string[] PostalCodes { get; set; }
public Visibility Visibility { get; set; } = Visibility.Visible;
}
您应该尝试适应 MVVM 模式,因此列表的填充应该出现在视图模型级别而不是视图的代码后面。
您提到您使用了点击事件,而不是这样做,尝试将按钮的命令 属性 绑定到视图模型中的命令,请参阅此 link 的解释几种类型的命令以及如何使用它们:https://msdn.microsoft.com/en-us/magazine/dn237302.aspx
另一方面,如果您已经在 window 构造函数中设置了数据上下文,要绑定 ListBox 项目源,您只需要绑定 属性 的名称,"PlacesOrCities":
<ListBox Name="lbPlacesCity" ItemsSource="{Binding Path=PlacesOrCities, UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate DataType="models:ListBoxItem">
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="{Binding Name}" Visibility="{Binding Visibility}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
还建议尝试在没有任何模板的情况下加载列表中的项目,您可以使用 ListBox DisplayMemberPath 属性 来显示名称,一旦能够加载项目,就应用样式。
同样在您使用 ObservableCollection 的方式中,您实际上需要替换整个集合而不是添加到 fire RaisePropertyChanged,请尝试使用普通的 属性。
public ObservableCollection<ListBoxItem> PlacesOrCities {get;set;} = new ObservableCollection<ListBoxItem>();
修改集合会更新 UI,因此无论何时使用添加或清除,UI 都应该知道。
希望对您有所帮助。