我正在使用 RelativeSource 绑定(bind) 为 Collection View 中的框架绑定(bind) 背景颜色。但是 Collection View 中所有框架的背景颜色都在变化。我需要仅为我选择的框架设置背景颜色。
这是我的 xaml 代码
<StackLayout Padding="10">
<CollectionView x:Name="list" ItemsSource="{Binding samplelist}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" HorizontalItemSpacing="10" VerticalItemSpacing="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="CommonStates">
<VisualState Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Green" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Frame CornerRadius="10" HasShadow="False" BackgroundColor="{Binding BackgroundTest,Mode=TwoWay, Converter={StaticResource colorConverter}}" HeightRequest="75" Margin="5,0,0,0" >
<StackLayout Orientation="Vertical">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference test}, Path=BindingContext.TriggerScene}"
CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
这是我在 Viewmodel
中的代码public bool FrameColorChange=true;
private Color _backgroundTest;
public Color BackgroundTest
{
get { return _backgroundTest; }
set
{
if (value == _backgroundTest)
return;
_backgroundTest = value;
OnPropertyChanged(nameof(BackgroundTest));
}
}
private async void TriggerScene(Scene scene)
{
if (FrameColorChange==true)
{
BackgroundTest = Color.Gray;
FrameColorChange = false;
}
else
{
BackgroundTest = Color.White;
FrameColorChange = true;
}
}
我已经完成了一些修复,例如
how to access child elements in a collection view?
但没有任何帮助。我也尝试了 SelectionChanged 事件。但是 SelectionChanged 的问题是它没有正确触发,因为我的框架中有 TapGestureRecognizer。我希望在我的 TriggerScene 命令 中为所选帧设置颜色绑定(bind) 我的 viewmodel 中的 TapGestureRecognizer。我不想在后面使用代码。我不知道如何解决这个问题有什么建议吗?
最佳答案
我已经在另一个答案中发布了解决您问题的一种方法,现在我想提供一个更简单的解决方案(尽管我不会声称它是最好的)。
注意,在这个解决方案中,与我的其他答案相反,您不需要向 Collection View 中的对象添加多余的属性,但新属性直接定义在ViewModel。
解决问题的一种方法是:
- 在您的 ViewModel 中定义一个名为
SelectedItem
的属性:这将跟踪当前选定的项目。 - 然后你将 Frame 的
BackgroundColor
绑定(bind)到新属性:SelectedItem
,为此你需要一个 ValueConverter 接受SelectedItem
和ConverterParameter
:当前 Frame。 - 在 Frame 内,在 StackLayout 中有 good old TapGestureRecognizer,其处理程序在调用时将设置所选项目。
- 设置 SelectedItem 时,会调用 OnPropertyChanged 并为 CollectionView 中的每个项目调用 ValueConverter。转换器然后检查 Frame 的 BindingContext(它绑定(bind)到的项目!)是否与 SelectedItem 相同,如果是,则将其颜色设置为 Gray(选中!)
当然,下面我添加了一个完整的最小工作示例。随意复制粘贴并使用它。
Page1.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="App1.Page1"
x:Name="test"
xmlns:local="clr-namespace:App1">
<ContentPage.BindingContext>
<local:ViewModel/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<local:SelectedToColorConverter x:Key="selectedToColorConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout Padding="10">
<CollectionView ItemsSource="{Binding samplelist}">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2" HorizontalItemSpacing="10" VerticalItemSpacing="10" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame x:Name="frame" CornerRadius="10"
HasShadow="False"
BackgroundColor="{Binding Source={x:Reference test}, Path=BindingContext.SelectedItem, Converter={x:StaticResource selectedToColorConverter}, ConverterParameter={x:Reference frame}}"
HeightRequest="75"
Margin="5,0,0,0" >
<StackLayout Orientation="Vertical">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={x:Reference test}, Path=BindingContext.TriggerSceneCommand}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<Label Text="{Binding Text}"/>
<Label Text="{Binding Description}"/>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
ViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace App1
{
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
samplelist = new List<item>
{
new item { Text = "Uno", Description = "Uno Description bla bla" },
new item { Text = "Dos", Description = "Dos Description bla bla" },
new item { Text = "Tres", Description = "Tres Description bla bla" }
};
TriggerSceneCommand = new Command<item>(TriggerScene);
}
public List<item> samplelist { get; set; }
private item _selectedItem;
public item SelectedItem
{
get => _selectedItem;
set
{
_selectedItem = value;
OnPropertyChanged();
}
}
public Command TriggerSceneCommand { get; set; }
private void TriggerScene(item newSelectedItem)
{
SelectedItem = newSelectedItem;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string name = "")
{
var propertyChanged = PropertyChanged;
propertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class item
{
public String Text { get; set; }
public String Description { get; set; }
}
public class SelectedToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Color result = Color.White;
if (value != null && parameter != null && ((Frame)parameter).BindingContext != null && (item)value == (item)((Frame)parameter).BindingContext)
{
result = Color.Gray;
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}
为什么不,让我们在这里放一个奖金。
您可以在 TapGestureRecognizer 的事件处理程序中添加两行代码,以便在一段时间(可能是三秒?)后返回原始颜色。
只需将 ViewModel 中的 TriggerScene
方法更改如下(参见代码注释):
private void TriggerScene(item newSelectedItem)
{
// Highlight selection!
SelectedItem = newSelectedItem;
// Sit and wait...
await Task.Delay(3000);
// Go back to normal!
SelectedItem = null;
}
关于c# - 如何在 Xamarin 表单中使用 MVVM 仅为 Collection View 中的选定框架设置颜色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69388564/