我试图通过更改所选标签的颜色来控制标签的背景颜色。我遵循MVVM模式,我实现的方式如下:
在模型中,我创建了一个带有get和set的布尔值,它必须检测列表视图中的项是否被选中。 public boolean Selected {get; set;}
在我看来,我将背景颜色属性绑定到布尔值,并将IValueConverter设置为转换器
它似乎只检查一次,因为背景颜色总是白色。我在转换器中使用断点检查了它,并且只在启动列表时调用它,而不是在项目更新时调用。
的IValueConverter:
public class SelectedItemColorConverter : IValueConverter
{
#region IValueConverter implementation
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
if ((Boolean)value)
return Color.Red;
else
return Color.White;
}
return Color.White;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}
这是ListView:
<StackLayout x:Name="standingsStackLayout" IsVisible="False">
<ListView x:Name="standingsList" SeparatorColor="Black" ItemsSource="{Binding StandingsListSource}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label x:Name="TournamentNameLabel" Text="{Binding TournamentName}"
TextColor="{StaticResource textColor}" HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
BackgroundColor="{Binding Selected, Converter={StaticResource colorConvert}}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
ViewModel代码:
public HistoricalStandingsData _selectedItem;
public HistoricalStandingsData SelectedItem
{
get { return _selectedItem; }
set
{
if (_selectedItem != value)
{
if(_selectedItem != null)
_selectedItem.Selected = false;
_selectedItem = value;
if (_selectedItem != null)
_selectedItem.Selected = true;
TournamentLabelName = _selectedItem.TournamentName;
OnPropertyChanged(nameof(SelectedItem));
//OnPropertyChanged(nameof(_selectedItem.Selected));
}
}
}
我为转换器添加了<ContentPage.Resources>
答案 0 :(得分:1)
让我们看一下你的观点
<StackLayout x:Name="standingsStackLayout" IsVisible="False">
<ListView x:Name="standingsList" SeparatorColor="Black" ItemsSource="{Binding StandingsListSource}" SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label x:Name="TournamentNameLabel" Text="{Binding TournamentName}"
TextColor="{StaticResource textColor}" HorizontalTextAlignment="Center"
VerticalTextAlignment="Center"
BackgroundColor="{Binding Selected, Converter={StaticResource colorConvert}}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
我们可以看到这里发生了两个主要的数据绑定。首先,ListView
的{{1}}属性绑定到视图模型的ItemsSource
属性。有两件事可以改变这一点:StandingsListSource
作为整体指向的对象或集合内容。
有关绑定的官方文档包含following to say regarding binding ListView.ItemsSource
:
StandingsListSource
处理可能的更改非常复杂 动态发生在底层数据中,但只有在确定时才会发生 脚步。如果分配给ListView
属性的项集合 运行期间ItemsSource
更改的内容 - 即,是否可以添加项目 要从集合中删除,请使用ListView
类 这些物品。ObservableCollection
实现了ObservableCollection
界面,INotifyCollectionChanged
将安装ListView
事件的处理程序。
让我们这样做(我稍后将CollectionChanged
类用作DataSource
的完整实现:
BindingContext
为简单起见,我将public ObservableCollection<HistoricalStandingsData> StandingsListSource { get; } = new ObservableCollection<HistoricalStandingsData>();
设为C# 6.0 readonly auto property,以消除跟踪其重新分配的需要。
现在,由于StandingsListSource
也受到约束,我们需要一些方法来通知ListView.SelectedItem
所选项目是从后面的代码更新的。输入之前提到的文档中的第二条建议:
如果项目的属性在运行时自身发生变化,那么 集合中的项目应实现
ListView
接口和信号使用的变化到属性值INotifyPropertyChanged
事件。
这有两个含义:
PropertyChanged
应该在其属性发生变化时通知,因为HistoricalStandingsData
中的每一行都按ListView
绑定到此属性:
DataTemplate
查看模型类应实现public class HistoricalStandingsData : INotifyPropertyChanged
{
public HistoricalStandingsData(string name)
{
this.TournamentName = name;
}
private bool selected;
public bool Selected
{
get
{
return selected;
}
set
{
selected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Selected)));
}
}
public string TournamentName { get; }
// From INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
}
以通知属性,在这种情况下INotifyPropertyChanged
更改。
SelectedItem
class DataSource : INotifyPropertyChanged
{
public ObservableCollection<HistoricalStandingsData> Items { get; } = new ObservableCollection<HistoricalStandingsData>();
public HistoricalStandingsData SelectedItem
{
// Information on selection is stored in items themselves, use Linq to find the single matching item
get => Items.Where(x => x.Selected).SingleOrDefault();
set
{
// Reset previous selection
var item = SelectedItem;
if (item != null)
item.Selected = false;
// Mark new item as selected, raising HistoricalStandingItem.PropertyChanged
if (value != null)
value.Selected = true;
// Notify observers that SelectedItem changed
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SelectedItem)));
}
}
// From INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public DataSource()
{
// Helper ICommand used for appending new items to HistoricalStandingsData
AddNew = new Command(() =>
{
var item2 = new HistoricalStandingsData(DateTime.Now.ToString());
// Append, notifies observers that collection has changed.
Items.Add(item2);
// Set as selected, resetting previous selection
SelectedItem = item2;
});
}
public ICommand AddNew { get; }
}
命令是可选的,我将其添加用于测试目的。