v 1.0 programming iii. automatic notifications (…changed, inofitypropertychanged,...
Post on 01-Jan-2016
226 Views
Preview:
TRANSCRIPT
V 1.0
Programming III.
Automatic notifications (…Changed, INofityPropertyChanged, ObservableCollection<T>)
Data formattersData conversions
Resources
V 1.0 ÓE-NIK, 2014
Automatic notifications
• For the bindings to work, the binding target must change its value if the source changes its value– If we use the ElementName binding as a source, then it is pre-
programmed into the source UI element…• E.g. Slider.Value was the source, Label.Content was the target
– … or we used the UI elements as pure input fields, so the source object (DataContext) was only changed by the UI element values, and not the other way around
• If we use our own classes as binding sources, then (by default) the changes in the properties will not be reflected in the target UI elements!
2
V 1.0 ÓE-NIK, 2014
Example
• The person’s name is in the label (via DataContext), the button changes the name
• XAML code:
3
public MainWindow(){ InitializeComponent(); currentPerson = new Person("Piros Péter"); this.DataContext = currentPerson;}
<Label Content="{Binding Name}"/>
V 1.0 ÓE-NIK, 2014
Example
• The Click event handler of the button:
• The console shows the new value…
• … but the label still shows the old name!4
private void Button_Click(object sender, RoutedEventArgs e){ currentPerson.Name = "Kék Péter"; Console.WriteLine(currentPerson.Name); }
V 1.0 ÓE-NIK, 2014
Automatic notifications
• Módszerek:1. Dependency properties are capable of sending automatic
notifications on their own. So it works if the source class’s data property is not a normal property, but a dependency property! (we are not discussing this)
2. Raise the …Changed event if the property changes3. Implement the INotifyPropertyChanged interface to
report property changes through an universal event
5
V 1.0 ÓE-NIK, 2014
Notification – …Changed event• If the property changes, we should fire a …Changed
event (…=the name of the property)• Subscription to the event is automatic if a binding is
defined onto that property
6
public event EventHandler NameChanged;public string Name{ get { return name; } set { name = value; EventHandler nameChanged = NameChanged; if (nameChanged != null) nameChanged(this, EventArgs.Empty); }}
V 1.0 ÓE-NIK, 2014
Notification – INotifyPropertyChanged• The class should implement the
INotifyPropertyChanged interface (System.ComponentModel)• This interface only contains one event:
– public event PropertyChangedEventHandler PropertyChanged;• This event should be fired in the setter, the property
name is transmitted in the EventArgs
7
public string Name{ get { return name; } set { name = value; PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs("Name")); }}
V 1.0 ÓE-NIK, 2014
Notification – INotifyPropertyChanged• Advantage: fewer events• Usually we also implement a helper/caller method:
OnPropertyChanged()
8
private void OnPropertyChanged(string propertyName){ PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));}
public string Name{ get { return name; } set { name = value; OnPropertyChanged(“Name"); }}
V 1.0 ÓE-NIK, 2014
Notifications – Problems with collections
• With collections, we usually do not have a public setter
• Even if we had, the setter’s OnPropertyChanged will only be called if the whole list is re-created
• This will not detect:– If we replace one of the sub-items– Add()/Remove()/Insert()…– If a property of one of the sub-items changes
9
public List<Subscriptions> NewsletterSubscriptions{ get { return newsletterSubscriptions; } set {
newsletterSubscriptions = value; OnPropertyChanged(“NewsletterSubscriptions"); //??? }}
V 1.0 ÓE-NIK, 2014
Notifications – Problems with collections
10
List<Subscription> uj = new List<Subscription>();uj.Add(new Subscription("gyereknevelés", true));currentPerson.NewsletterSubscriptions = uj; //setter called event called currentPerson.NewsletterSubscriptions[0] = new Subscription("gyereknevelés", true); //not calledcurrentPerson.NewsletterSubscriptions.Add( new Subscription("gyereknevelés", true)); //not called
currentPerson.NewsletterSubscriptions[0].Active = false; //not called
V 1.0 ÓE-NIK, 2014
Notifications – ObservableCollection<T>• Exactly the same methods as List<T>
– System.Collections.ObjectModel
• Will send a notification:– If one of the sub-items is changed– Add()/Remove()/Insert()– NOT if a property of a sub-item changes!
• Implements INotifyCollectionChanged
11
private ObservableCollection<Subscription> newsletterSubscriptions;public ObservableCollection<Subscription> NewsletterSubscriptions{ get { return newsletterSubscriptions; } set {
newsletterSubscriptions = value; OnPropertyChanged(“NewsletterSubscriptions"); //??? Just skip the setter }}
V 1.0 ÓE-NIK, 2014
Állapotértesítés – ObservableCollection<T>
12
List<Subscription> uj = new List<Subscription>();uj.Add(new Subscription("gyereknevelés", true));currentPerson.NewsletterSubscriptions = uj; //setter called event called currentPerson.NewsletterSubscriptions[0] = new Subscription("gyereknevelés", true); //listbox refreshedcurrentPerson.NewsletterSubscriptions.Add( new Subscription("gyereknevelés", true)); //listbox refreshed
currentPerson.NewsletterSubscriptions[0].Active = false; //nothing happens
V 1.0 ÓE-NIK, 2014
Notifications – Problems• ToString() outputs will never refresh/change…
– In WPF, we rather avoid relying on ToString() only!– Instead: use a content manager (e.g. Grid) in the Content
property, and then use separate UI elements for the different properties, and use Data Binding for each of them
– Use DataTemplates if there are many UI elements with same content arrangments
– If we use ListBox UI elements, then use DataTemplates or use a self-made user control…
13
V 1.0 ÓE-NIK, 2014
Notifications – Problems• Changes in a property of a property
– Assign the main property to the DataContext of a content manager or a DataTemplate; then assign the sub-properties to the UI elements inside
– Or use complex Path: {Binding Path=Animal.IsDangerous}– Very often: create a customized the user control …
• Changes in a property of an item in a collection– Usually DataTemplate, customized properties…– If we want to detect it in the code, use BindingList<T>
• For every solution, we have to:– Implement the INotifyPropertyChanged interface in EVERY
class that participates in the data binding– Use ObservableCollection<T> instead of the other
collections14
V 1.0 ÓE-NIK, 2014
Notifications – Changes in a property of a property
• The DataContext of the Window is a Person instance
15
<Label Content="{Binding Name}"/><Grid DataContext="{Binding Animal}"> <Label Content="{Binding Name}"/> <Label Content="{Binding IsDangerous}"/></Grid>
class Person : INotifyPropertyChanged { … private Animal animal; public Allat Animal { get { return animal; } set { animal = value; OnPropertyChanged(“Animal"); } }}
V 1.0 ÓE-NIK, 2014
Notification – Detect changes in a property of sub-items
16
class Person : INotifyPropertyChanged{ … private ObservableCollection<Subscriptions> newsletterSubscriptions; public ObservableCollection<Subscriptions> NewsletterSubscriptions { get { return newsletterSubscriptions; } set {
newsletterSubscriptions = value; OnPropertyChanged(“NewsletterSubscriptions"); } } //+the Subscription class also implements} //the INotifyPropertyChanged interface<ListBox ItemsSource="{Binding NewsletterSubscriptions}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Label Content="{Binding Topic}"/> <Label Content="{Binding Active}"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate></ListBox>
ItemsControl ItemTemplate, ContentControl ContentTemplate, Grid CellTemplate
V 1.0 ÓE-NIK, 2014
Data Formatters, conversions• Sometimes we do not want the source property’s
value to be used directly, many times we want to change the look or the type of the source value
• Formatters:– Easiest: …StringFormat properties
• ContentControl: ContentStringFormat (only if the Content is a string)• ItemsControl: ItemStringFormat (only if there is no complex DataTemplate)• When using data binding, IF the target type is string (e.g. TextBox.Text), then
we can use the StringFormat inside the {Binding}– Usually it is similar to string.Format
17
<ListBox.ItemTemplate> <DataTemplate> <StackPanel> <Label ContentStringFormat=“Newsletter topic: {0}" Content="{Binding Topic}"/> <Label ContentStringFormat=“Subscription active: {0}" Content="{Binding Active}"/> </StackPanel> </DataTemplate></ListBox.ItemTemplate>
V 1.0 ÓE-NIK, 2014
Data Formatters, conversions• Data conversions:
– Very often it is automatic!• E.g.: BorderBrush from the string elements inside the ListBox
– If we want a custom converter, we have to create a class that implements the IValueConverter interface (System.Windows.Data)
– Two methods: Convert(), ConvertBack()• Convert(): source target• ConvertBack(): target source (not always used)• The Convert() method is automatically called after a ConvertBack() – due to
the change that happens in the source value.18
<ListBox x:Name="listBoxColors" BorderBrush="{Binding ElementName=listBoxColors, Path=SelectedItem}” .../>
V 1.0 ÓE-NIK, 2014
Data Formatters, conversions• Person class:
– Name (string)– Age (int)
• Binding: person.Age label.Content
19
<Window ... xmlns:current="clr-namespace:WpfApplication9” ... > <Grid> <Grid.Resources> <current:AgeConverter x:Key=“AgeConverter"/> </Grid.Resources> <Label Content="Személy neve:" .../> <Label Content="Személy kora kb.:" .../> <Label Content="{Binding Name}” .../> <Label Content="{Binding Age, Converter={StaticResource AgeConverter}}” ... /> </Grid></Window>
Import the .NET namespace
Import the converter class
Assign the converter to the Binding
V 1.0 ÓE-NIK, 2014
Data Formatters, conversions• Converter class
– Since the target is a Label, we do not need the ConvertBack
20
class AgeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { int age = (int)value; if (age < 18) return “child"; else if (age < 30) return “young"; else if (age < 50) return “middle aged"; else if (age < 65) return “getting old"; else return “old"; }
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } }
V 1.0 ÓE-NIK, 2014
Resources• Resources are objects that we can use/reuse in various
places of our application• Types:
– object resources: created in the XAML (window/control xaml OR app.xaml)
– Binary resources: images, icons, tables, etc• Every resource will be imported into the resource
dictionary using a unique name (x:Key)– Resources property (in FrameworkElement descendants)
• Sub-elements will receive the resources of their conatiners• Use in XAML or Application.Current.Resources[“resource_name"]
21
<Window ... <Grid> <Grid.Resources> <current:AgeConverter x:Key=“AgeConverter"/> </Grid.Resources> ... </Grid></Window>
This can be accessed in the grid as a static resource
V 1.0 ÓE-NIK, 2014
Resources• We can use object resources in other places:
– Brushes, colors, styles, Data Template elements, arrays, etc… – E.g. usage of a brush:
• Types:– StaticResource: is loaded once when the XAML is loaded, will not change– DynamicResource: can be loaded and changed dynamically
22
<Window ...> <Grid> <Grid.Resources> <SolidColorBrush x:Key=“MyColor" Color="Azure"/> </Grid.Resources> ... <Label Background="{StaticResource ResourceKey=MyColor}" Content="Szép színű" .../> <ListBox Background="{StaticResource ResourceKey=MyColor}" .../> </Grid></Window>
V 1.0 ÓE-NIK, 2014
<Image Source="LockScreen___0600_0337.jpg" />
Resources• Binary resources:
– Any file can be added to the project that the application might need
– We have to change the file’s properties in the solution explorer to allow their usage as a resource (Solution Explorer, Properties window – Build Action)
• Resource: the compiler will add the resource into the .NET assembly• Content: the file will be used separately – it can be changed or deleted
• In the caml, we can reference them using the file name
23
top related