C# 形式:IValueConverter只工作一次
我试图通过更改选定标签的颜色来控制标签的背景色。我遵循MVVM模式,我的实现方式如下:C# 形式:IValueConverter只工作一次,c#,xaml,xamarin,mvvm,xamarin.forms,C#,Xaml,Xamarin,Mvvm,Xamarin.forms,我试图通过更改选定标签的颜色来控制标签的背景色。我遵循MVVM模式,我的实现方式如下: 在该模型中,我创建了一个带有get和set的布尔值,它必须检测是否选中了listview中的某个项选定的公共布尔值{get;set;} 在我看来,我将background color属性绑定到布尔值,并将IValueConverter设置为转换器 在ViewModel中,我实现了get和set 它似乎只检查一次,因为背景色始终为白色。我用转换器中的断点检查了它,它只在列表启动时被调用,而在项目更新时不会被调用
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>
我已经为转换器添加了
让我们看看您的视图
<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>
为了简单起见,我制作了StandingsListSource
a,以消除跟踪其重新分配的需要
现在,由于ListView.SelectedItem
也已绑定,我们需要某种方式通知ListView
所选项目已从代码隐藏中更新。输入前面提到的文档中的第二条建议:
如果项目本身的属性在运行时发生更改,则
集合中的项应实现INotifyPropertyChanged
使用
属性已更改
事件
这有两个含义:
应在其属性更改时通知,因为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; } }
类数据源:INotifyPropertyChanged { 公共ObservableCollection项{get;}=new ObservableCollection(); 公共历史标准数据选择编辑项 { //有关选择的信息存储在项本身中,请使用Linq查找单个匹配项 get=>Items.Where(x=>x.Selected).SingleOrDefault(); 设置 { //重置以前的选择 var item=SelectedItem; 如果(项!=null) item.Selected=false; //将新项目标记为选中,提升HistoricalStandingItem.PropertyChanged if(值!=null) value.Selected=true; //通知观察者SelectedItem已更改 PropertyChanged?.Invoke(这是新的propertychangedventargs(nameof(SelectedItem)); } } //从InotifyProperty更改 公共事件属性更改事件处理程序属性更改; 公共数据源() { //Helper ICommand用于将新项附加到HistoricalStandingData AddNew=new命令(()=> { var item2=new HistoricalStandingsData(DateTime.Now.ToString()); //追加,通知观察者集合已更改。 增加(第2项); //设置为已选择,重置以前的选择 选择editem=item2; }); } public ICommand AddNew{get;} }
AddNew
命令是可选的,我添加它是为了测试目的。对集合的选择跟踪通常通过CollectionView完成。请参阅我编写的旧MVVM简介中的第8点:我假设您的数据源需要实现“INotifyPropertyChanged”,以便在属性更新时通知burbs。@orhtej2:谢谢您的建议,但这不起作用:(@Hudhud的事情是,您所做的只是将绑定源代码更新到ListView作为一个整体,您需要做的是在HistoricalStandingsData
的各个属性上实现INotifyPropertyChanged
,因为这是您的转换器所绑定的。您应该使用一个baseViewModel来实现所有ViewModel,因为e是对的。这是使用baseViewModel最简单的方法:)
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;
}
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; }
}