如何使用INotifyPropertyChanged

时间:2016-03-30 13:25:39

标签: c# xaml listbox win-universal-app uwp-xaml

方案

我有两个课程:

  • Fruit有两个数据成员FruitNameFruitColor
  • Presentation还有两位成员ForeColorFontName

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

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

问题

问题在于

  • 当我呼叫btnChangeColor_Click()时,我收到一个异常&#34; 对象引用未设置为对象的实例&#34;。在INotifyPropertyChanged()方法中。正好在这里......

    await dispatcher.RunAsync(CoreDispatcherPriority.Normal,()=&gt; {     PropertyChanged(this,new PropertyChangedEventArgs(propertyName)); });

我想设置ListBox,其中一些Fruits对象显示FruitName和FruitColor。我还想更改字体名称和显示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); }
            }
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您可以这样做:

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

如果Foreground属性位于代码隐藏中,则此方法有效。

您可以这样做:

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

如果Foreground属性位于视图模型中,则此方法有效。

你也可以这样做:

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

如果Foreground属性在您的模型中

,则此方法有效

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

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

这样您就可以将多个对象传递给任何ItemControl

有意义吗?祝你好运。