Xamarin形式:设置从ViewModel在ListView中选择的项的背景颜色 [英] Xamarin Forms: Set Background Color of Item Selected in ListView from ViewModel

查看:164
本文介绍了Xamarin形式:设置从ViewModel在ListView中选择的项的背景颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在ViewModel中的代码中完成选择后,我试图更改列表视图中所选项目的背景色.当用户通过操作(例如,点击)选择该项时,我发现了许多与更改背景颜色相关的帖子

I am trying to change the background color of a selected item in a list view when the selection is done in code from the ViewModel. I have found a number of posts associated to changing the background color when the item is selected by user action (i.e., Tapped)

Xamarin.Forms ListView:设置突出显示被点击项目的颜色

此解决方案-使用分接项适用于用户在列表中分接项时使用,但是在某些情况下,用户通过在表单的其他位置输入数据来选择ListView中的项目.

This solution - Using Item Taped works for when the user taps the item in the list but there are cases when an item in the ListView is selected by the user entering data elsewhere in the form.

我尝试为ListView上的ItemSelected添加处理程序

I tried adding a handler for the ItemSelected on the ListView

    private void ListView_OnItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        if ( e.SelectedItem == null ) return;  //The selection is set to null in some cases
        if ( !(sender is ListView listView) ) return;
        if ( !(listView.TemplatedItems[0] is ViewCell cell) ) return;

        SetCellColor(cell);
    }

    private void SetCellColor(ViewCell cell)
    {
        if ( _selectedCell != null )
        {
            _selectedCell.View.BackgroundColor = Color.Transparent;
        }

        cell.View.BackgroundColor = Color.LightGray;
        _selectedCell = cell;
    }

这似乎应该可以工作,但是TemplatedItems集合是一个内部Forms对象,不能按我期望的那样工作.我确实返回了ViewCell,但是它不会改变背景颜色.

Which seems like it should work but the TemplatedItems collection is an internal Forms object and does not work as I would expect. I do get a ViewCell returned but it does not change the background color.

本来想对CustomViewCell的OnAppearing事件做些事情,但是看不到在这种情况下如何知道选择了什么.我还尝试了一些使用渲染器的方法,但是这些方法似乎也没有提供知道所选项目的方法.

Looked into doing something with the OnAppearing event of the CustomViewCell but don't see how one would know what is selected in this case. I have also played around with some approaches using renderers but these also seem to not give a way to know an item is selected.

先谢谢了 -乔

推荐答案

我确实提出了一个我很满意并且不需要Renderer的解决方案.在我的自定义ViewCell中,我按照建议添加了SelectedBackgroundColor BindableProperty.

I did come up with a solution which I am happy with and requires no Renderer. In my custom ViewCell I have added the SelectedBackgroundColor BindableProperty as suggested.

        /// <summary>
    /// The SelectedBackgroundColor property.
    /// </summary>
    public static readonly BindableProperty SelectedBackgroundColorProperty =
        BindableProperty.Create("SelectedBackgroundColor", typeof(Color), typeof(SymbolViewCell), Color.Transparent, propertyChanged:SelectionColorChanged);

    public Color SelectedBackgroundColor
    {
        get => (Color)GetValue(SelectedBackgroundColorProperty);
        set => SetValue(SelectedBackgroundColorProperty, value);
    }

    private static void SelectionColorChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        if ( !(bindable is SymbolViewCell viewCell) ) return;

        var color = (Color) newvalue;

        viewCell.View.BackgroundColor = color;
    }

然后我使用自定义转换器.实际上,这是一个通用转换器,可在其他地方用于基于正确/错误的绑定值来设置值.

I then use a custom Converter. This is actually a generic Converter that is used elsewhere for setting values based on a true/false bound value.

public class ConfigurableBoolConverter<T> : IValueConverter
{
    public ConfigurableBoolConverter() { }

    public ConfigurableBoolConverter(T trueResult, T falseResult)
    {
        TrueResult = trueResult;
        FalseResult = falseResult;
    }

    public T TrueResult { get; set; }
    public T FalseResult { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (TrueResult == null || FalseResult == null) return !(bool)value;


        return value is bool b && b ? TrueResult : FalseResult;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (TrueResult == null || FalseResult == null) return !(bool)value;

        return value is T variable && EqualityComparer<T>.Default.Equals(variable, TrueResult);
    }
}

在Xaml中,我定义了Converter,并将True/False值设置为所需的背景色:

In Xaml I define the Converter and set my True/False values to the required background colors:

<converters:ConfigurableBoolConverter x:Key="BackgroundColorConverter"
                                  x:TypeArguments="x:String"
                                  TrueResult="Color.LightGray"
                                  FalseResult="Color.Transparent"/>

然后将Converter分配给自定义ViewCell.在自定义ViewCell中,使用Converter设置了SelectedBackgroundColor.请注意,SymbolViewCell已经存在,可以解决图像的另一个问题,该图像是项目的一部分,可以正确刷新

Then assign the Converter to the custom ViewCell. In the custom ViewCell the SelectedBackgroundColor was set using the Converter. As a note The SymbolViewCell already existed to solve a different issue with an image that was part of the item refreshing correctly

<DataTemplate>
     <views:SymbolViewCell 
          SelectedBackgroundColor="{Binding IsChecked, Converter={StaticResource 
                BackgroundColorConverter}}"/>
</DataTemplate>

IsChecked是ItemsDataSource的Item上的一个属性. ListView已经使用了Item对象的集合,并且该对象已经具有IsChecked属性.

IsChecked is a property on the Item of the ItemsDataSource. The ListView already used a a collection of Item objects and this object already had an IsChecked property.

将Item对象剥离到最低限度(BindableBase实现了IPropertyChanged接口):

Stripping down the Item object to the bare minimum (BindableBase implements the IPropertyChanged interface):

public class SymbolItem : BindableBase
{
    private bool? _isChecked;


    public SymbolItem(LegendInfo legendInfo, FeatureTemplate featureTemplate, ArcGISFeatureTable featureTable, IEnumerable<string> requiredFields)
    {
        IsChecked = false;
    }



    public bool? IsChecked
    {
        get => _isChecked;
        set => SetProperty(ref _isChecked, value);
    }
}

如果ItemsDataSource是字符串对象的集合,则此解决方案将不起作用,因为它确实需要其他属性,并且您需要绑定的SelectedItem属性作为触发IsChecked属性更改的位置.但是可以用名称和IsChecked属性绑定一个简单的对象.我个人认为添加的代码比编写Renderer处理事情要简单得多.

This solution would not work if the ItemsDataSource was a collection of string objects because it does require the additional property and you would need a bound SelectedItem property as a place to trigger the change in IsChecked property. But one could make a simple object with a name and IsChecked property to bind. Personally I think this added code is a lot simpler than writing a Renderer to handle things.

public SymbolItem SelectedSymbolItem
{
    get => _selectedSymbolItem;
    set
    {
        if ( _selectedSymbolItem != null ) _selectedSymbolItem.IsChecked = false;
        SetProperty(ref _selectedSymbolItem, value);
    }
}

这篇关于Xamarin形式:设置从ViewModel在ListView中选择的项的背景颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆