【问题标题】:Changing xaml property according to compare old value and new value根据比较旧值和新值更改 xaml 属性
【发布时间】:2020-03-26 23:39:13
【问题描述】:

我有一个 Xamarin Forms 应用程序。我正在使用 MVVM。 ContentPage 具有如下的 ListView。 ItemSource 从远程休息服务每 10 秒自动刷新一次。当旧值与新值不同时,我想更改 Label 的 TextColor 属性。最好的 XAML 方法是什么?提前谢谢你

<ListView HasUnevenRows="True" ItemsSource="{Binding Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <Grid>
                        <Label
                            Grid.Column="0"
                            Text="{Binding ValueA}"
                            TextColor="Black" />
                        <Label
                            Grid.Column="1"
                            Text="{Binding ValueB}"
                            TextColor="Black" />
                        <Label
                            Grid.Column="2"
                            Text="{Binding ValueC}"
                            TextColor="Black" />
                    </Grid>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

【问题讨论】:

  • 你真的需要修改你的虚拟机来支持这个。在 XAML 中要做的工作很少。

标签: xaml xamarin xamarin.forms


【解决方案1】:

编辑:哎呀,我看错了,以为您想要更改新项目的文本颜色。更新了以下内容,以便在新添加项目时更改项目背景颜色,如果自上次刷新后发生更改,则更改值的文本颜色。

您可能希望将 Label 的 TextColor 属性绑定到一个布尔值,以指示该值是否已更改,并且您需要使用 ValueConverter 将布尔值转换为颜色。

这是一个简单的例子(下面的大部分代码是模拟添加和更新列表中的项目,兴趣点是值转换器以及如何使用它们将绑定的布尔值转换为颜色):

MainPage.xaml.cs:(包括转换器和项目视图模型)

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Timers;
using Xamarin.Forms;

namespace ChangeTextColorForNewItemsInListView
{
    // Learn more about making custom code visible in the Xamarin.Forms previewer
    // by visiting https://aka.ms/xamarinforms-previewer
    [DesignTimeVisible(false)]
    public partial class MainPage : ContentPage
    {
        public ObservableCollection<ItemViewModel> Items { get; set; } = new ObservableCollection<ItemViewModel>();
        Timer _timer; 
        int itemNumber = 0;
        Random randomNumber = new Random(DateTime.Now.Millisecond);


        public MainPage()
        {
            InitializeComponent();
            BindingContext = this;
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            for (int i = 0; i < 10; i++)
            {
                Items.Add(new ItemViewModel
                {
                    ValueA = $"ValueA {++itemNumber}",
                    ValueB = $"ValueB {itemNumber}",
                    ValueC = $"ValueC {itemNumber}",
                    IsNew = true
                });
            }

            _timer = new Timer(2000);
            _timer.AutoReset = true;
            _timer.Elapsed += Timer_Elapsed;
            _timer.Start();
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            foreach (var item in Items)
            {
                item.IsNew = false;
                item.ValueA = item.ValueA.Replace(" new", "");
                item.ValueB = item.ValueB.Replace(" new", "");
                item.ValueC = item.ValueC.Replace(" new", "");
                item.ValueAChanged = false;
                item.ValueBChanged = false;
                item.ValueCChanged = false;

                int changeValue = randomNumber.Next(0, 15);
                switch (changeValue)
                {
                    case 0:
                        item.ValueA = item.ValueA.Replace(" new","") + " new";
                        break;
                    case 1:
                        item.ValueB = item.ValueB.Replace(" new", "") + " new";
                        break;
                    case 2:
                        item.ValueC = item.ValueC.Replace(" new", "") + " new";
                        break;
                    default:
                        break;

                }
            }

            for (int i = 0; i < randomNumber.Next(1,5); i++)
            {
                Items.Insert(randomNumber.Next(1, Items.Count -1)  ,new ItemViewModel
                {
                    ValueA = $"ValueA {++itemNumber}",
                    ValueB = $"ValueB {itemNumber}",
                    ValueC = $"ValueC {itemNumber}",
                    IsNew = true
                });
            }       
        }
    }

    public class ItemViewModel : INotifyPropertyChanged
    {
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        bool _isNew;
        public bool IsNew
        {
            get => _isNew;
            set
            {
                if (_isNew != value)
                {
                    _isNew = value;
                    OnPropertyChanged();
                }
            }
        }

        bool _valueAChanged;
        public bool ValueAChanged
        {
            get => _valueAChanged;
            set
            {
                if (_valueAChanged != value)
                {
                    _valueAChanged = value;
                    OnPropertyChanged();
                }
            }
        }
        string _valueA;
        public string ValueA
        {
            get => _valueA;
            set
            {
                if (_valueA != value)
                {
                    _valueA = value;
                    ValueAChanged = true;
                    OnPropertyChanged();
                }
            }
        }

        bool _valueBChanged;
        public bool ValueBChanged
        {
            get => _valueBChanged;
            set
            {
                if (_valueBChanged != value)
                {
                    _valueBChanged = value;
                    OnPropertyChanged();
                }
            }
        }
        string _valueB;
        public string ValueB
        {
            get => _valueB;
            set
            {
                if (_valueB != value)
                {
                    _valueB = value;
                    ValueBChanged = true;
                    OnPropertyChanged();
                }
            }
        }

        bool _valueCChanged;
        public bool ValueCChanged
        {
            get => _valueCChanged;
            set
            {
                if (_valueCChanged != value)
                {
                    _valueCChanged = value;
                    OnPropertyChanged();
                }
            }
        }
        string _valueC;
        public string ValueC
        {
            get => _valueC;
            set
            {
                if (_valueC != value)
                {
                    _valueC = value;
                    ValueCChanged = true;
                    OnPropertyChanged();
                }
            }
        }
    }

    public class BoolToColorConverterNewItem : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Color.Yellow : Color.White;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException("No need to convert from color to bool");
        }
    }

    public class BoolToColorConverterChangedValue : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? Color.Red : Color.Black;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException("No need to convert from color to bool");
        }
    }
}

MainPage.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"
                xmlns:d="http://xamarin.com/schemas/2014/forms/design"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:local="using:ChangeTextColorForNewItemsInListView"
                mc:Ignorable="d"
                x:Class="ChangeTextColorForNewItemsInListView.MainPage"

                >
    <ContentPage.Resources>
        <ResourceDictionary>
            <local:BoolToColorConverterChangedValue x:Key="boolToColorCV" />
            <local:BoolToColorConverterNewItem x:Key="boolToColorNI" />
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout Margin="0,50,0,0">
        <!-- Place new controls here -->
        <ListView HasUnevenRows="True" ItemsSource="{Binding Items}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid BackgroundColor="{Binding IsNew, Converter={StaticResource boolToColorNI}}">
                            <Label
                                Grid.Column="0"
                                Text="{Binding ValueA}"
                                TextColor="{Binding ValueAChanged, Converter={StaticResource boolToColorCV}}" />
                            <Label
                                Grid.Column="1"
                                Text="{Binding ValueB}"
                                TextColor="{Binding ValueBChanged, Converter={StaticResource boolToColorCV}}" />
                            <Label
                                Grid.Column="2"
                                Text="{Binding ValueC}"
                                TextColor="{Binding ValueCChanged, Converter={StaticResource boolToColorCV}}" />
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </StackLayout>
</ContentPage>

【讨论】:

  • 首先感谢您的出色解决方案,但我不仅有 3 个 ItemSource 属性。计数大约是 25。自定义控制方法是否更适合?
  • 我不确定自定义控件将如何帮助您。您仍然需要一个可以绑定的项目视图模型,并且如果有可能更改 25 个属性中的任意数量,那么您需要为每个属性绑定一个单独的 bool 属性,以指示值是否已更改。您可以制作一个自定义控件,您可以将其设置为列表项的视图,但这不会消除对每个属性都有一个 bool 属性以指示它是否已更改的项视图模型的需要。跨度>
【解决方案2】:

您可以绑定 TextColor

的值

在xml中

<Label
     Grid.Column="1"
     Text="{Binding ValueB}"
     TextColor="{Binding TitleColor}" />

在模型中

public class MyModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    Color color;
    public Color TitleColor
    {
        get { return color; }

        set
        {

            if (color != value&& color != null)
            {
                color = value;
                NotifyPropertyChanged("TitleColor");
            }

        }
    }       

    private string valueB;
    public string ValueB
    {
        get { return valueB; }

        set
        {
            if (valueB != value)
            {
                valueB = value;

                TitleColor= Color.Red;  // change color here 

                NotifyPropertyChanged("ValueB");
            }
        }
    }

    //...other property
    
}

【讨论】:

    猜你喜欢
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 1970-01-01
    • 2019-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多