Scenario
I have Two Classes:
Fruithas two data membersFruitNameandFruitColorPresentationalso has two membersForeColorandFontName
A ListBox's ItemsSource property is set to List<Fruit>. And the fruits are listed.
However, I want to change FontFamily and Foreground of the TextBlock control, which should reflect immediately as I set the Presentation instance to the ListBox.
Problem
The problem is that
When I am calling the
btnChangeColor_Click(), I receive an exception "Object reference not set to an instance of an object". In theINotifyPropertyChanged()method. Exactly here...await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); });
I want to set ListBox with some Fruits object showing FruitName and FruitColor. I also want to change font names and the foreground of the TextBlock showing the FruitName and the FruitColor, so that changing the color and font name should reflect immediately
Code
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>
The 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); }
}
}
}
The 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); }
}
}
}
}