如何使用 INotifyPropertyChanged 更新数据绑定列表框的 FontFamily 和前景

How can I update FontFamily and Foreground of a data bound ListBox using INotifyPropertyChanged

场景

我有两个类:

ListBox 的 ItemsSource 属性 设置为 List<Fruit>。并且列出了水果。

但是,我想更改 TextBlock 控件的 FontFamily 和 Foreground,当我将 Presentation 实例设置为 ListBox 时,这应该会立即反映出来。

问题

问题在于

我想用一些显示 FruitName 和 FruitColor 的 Fruits 对象设置 ListBox。我还想更改字体名称和显示 FruitName 和 FruitColor 的 TextBlock 的前景,以便更改颜色和字体名称应该立即反映

代码

TestingRealTimeUIUpdate.xaml

<Page
    x:Class="dataStorage_And_AppSettings.TestingRealTimeUIUpdate"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:dataStorage_And_AppSettings"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel>
            <ListBox x:Name="lstFruits" Height="400" Background="Aqua">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                            <TextBlock x:Name="lblFruitName" Text="{Binding Fruits.FruitName}" Foreground="{Binding Presentations.ForeColor}" FontFamily="{Binding Presentations.FontName}" />
                            <TextBlock x:Name="lblFruitColor" Text="{Binding Fruits.FruitColor}" Foreground="{Binding Presentations.ForeColor}" FontFamily="{Binding Presentations.FontName}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
            <ListBox x:Name="lstColors" Height="175" Background="Goldenrod" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock x:Name="lblFruitName" Text="FontColors And Font Name" Foreground="{Binding Presentation.ForeColor}" FontFamily="{Binding Presentation.FontName}" />
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <Button x:Name="btnReloadFruits" Content="ReloadBasket" Click="btnReload_Click" />
            <Button x:Name="btnChangeColor" Content="ChangeColor" Click="btnChangeColor_Click" />
        </StackPanel>
    </Grid>
</Page>

TestingRealTimeUIUpdate.CS

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace dataStorage_And_AppSettings
{
    public sealed partial class TestingRealTimeUIUpdate : Page
    {
        private Comp FruitBasket;
        private List<Presentation> PresentationForFruitBasket = new List<Presentation>
        {
            new Presentation { FontName = "Arial", ForeColor = new SolidColorBrush(Colors.Green) },
            new Presentation { FontName = "Verdana", ForeColor = new SolidColorBrush(Colors.Yellow) },
            new Presentation { FontName = "Times New roman", ForeColor = new SolidColorBrush(Colors.Brown) },
            new Presentation { FontName = "Tahoma", ForeColor = new SolidColorBrush(Colors.Red) },
        };

        private List<Fruit> FruitForFruitBasket = new List<Fruit>
        {
            new Fruit { FruitName= "Mango", FruitColor="Yellow" },
            new Fruit {FruitName = "Banana", FruitColor= "Yellow" },
            new Fruit { FruitName="Grapes", FruitColor="Green"},
            new Fruit {FruitName="Tomato", FruitColor="Red" }
        };

        public TestingRealTimeUIUpdate()
        {
            this.InitializeComponent();
        }

        private void btnReload_Click(object sender, RoutedEventArgs e)
        {
            List<Comp> lstFruitBasket = new List<Comp>();
            foreach( var item in FruitForFruitBasket)
            {
                FruitBasket = new Comp();
                FruitBasket.Fruits = item;
                FruitBasket.Presentations = PresentationForFruitBasket.ElementAt(2);
                lstFruitBasket.Add(FruitBasket);
            }   
            lstFruits.ItemsSource = lstFruitBasket;
        }

        private void btnChangeColor_Click(object sender, RoutedEventArgs e)
        {
            Random rnd = new Random();
            FruitBasket.Presentations = PresentationForFruitBasket.ElementAt(rnd.Next(0, 3));
        }
    }

    public class Comp : BindableBase
    {
        Fruit fruits = new Fruit();
        Presentation presentations = new Presentation();

        public Fruit Fruits
        {
            get { return fruits; }
            set { SetProperty(ref fruits, value); }
        }

        public Presentation Presentations
        {
            get { return presentations; }
            set { SetProperty(ref presentations, value); }
        }
    }

    public class Fruit:BindableBase
    {
        private string fruitname;
        private string fruitcolor;
        public string FruitName
        {
            get { return fruitname; }
            set { SetProperty(ref fruitname, value); }
        }
        public string FruitColor
        {
            get { return fruitcolor; }
            set { SetProperty(ref fruitcolor, value); }
        }
    }

    public class Presentation : BindableBase
    {
        private SolidColorBrush forecolor;
        private string fontname;
        public SolidColorBrush ForeColor
        {
            get { return forecolor; }
            set { SetProperty(ref forecolor, value); }
        }

        public string FontName
        {
            get { return fontname; }
            set { SetProperty(ref fontname, value); }
        }
    }
}

BindableBase.cs

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.UI.Core;

namespace IQ.Main.ViewModels
{
    public abstract class BindableBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private CoreDispatcher dispatcher;
        protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = "")
        {
            if (Object.Equals(storage, value))
            {
                return false;
            }
            storage = value;
            NotifyPropertyChanged(propertyName);
            return true;
        }

        internal virtual async void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                try
                {
                    await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
                    });
                }
                catch (Exception ex) { Debug.WriteLine(ex.Message); }
            }
        }
    }
}

你可以这样做:

<ListBox Foreground="{x:Bind Foreground}" />

This works if the Foreground property is in your code-behind.

你可以这样做:

<ListBox Foreground="{Binding Foreground}" />

This works if the Foreground property is in your view-model.

您也可以这样做:

<ListBox>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Text}" Foreground="{Binding Foreground}" />
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

This works if the Foreground property is in your model

请记住,您始终可以创建复合对象。像这样:

class MyObject
{
    public FruitObject Fruit { get; set; }
    public PresentationObject Presentation { get; set; }
}

This will let you pass in multiple objects to any ItemControl.

有道理吗?祝你好运。