Providing Property Change Notifications


The CLR does not provide a generic way for an object to notify its clients that one of its properties has changed. Nevertheless, a dynamic binding requires such notifications so that the binding can propagate changed property values to the target dynamic property. Longhorn introduces the IPropertyChange interface to allow an object to signal when one of its properties changes value. Note that the interface defines a single event of type PropertyChangedEventHandler and that the event handler can retrieve the name of the changed property using the PropertyName property of the second parameter to the handler.

 interface  IPropertyChange  { 
event PropertyChangedEventHandler PropertyChanged;
}

delegate void PropertyChangedEventHandler (object sender,
PropertyChangedEventArgs e);

class PropertyChangedEventArgs : EventArgs {
public virtual string PropertyName { get ;}
}

In the following code, I ve rewritten the Person class from earlier in the chapter to support changing the Name and Age properties and to fire the appropriate events when such changes occur.

 namespace MyNamespace { 
public class Person : IPropertyChange {
private string m_name;
private int m_age;
public event PropertyChangedEventHandler PropertyChanged;

public string Name {
get { return m_name; }
set {
if (m_name != value) {
m_name = value;
RaisePropertyChangeEvent ("Name");
}
}
}
public int Age {
get { return m_age; }
set {
if (m_age != value) {
m_age = value;
RaisePropertyChangeEvent ("Age");
}
}
}

private void RaisePropertyChangedEvent (string propertyName) {
if (PropertyChanged != null)
PropertyChanged (this, new PropertyChangedEventArgs (propertyName));
}

public Person (string name, int age) {
m_name = name; m_age = age;
}
}
}

Your object implements this interface by calling the PropertyChanged delegate whenever one of its interesting properties changes value. Note that you need to invoke the delegate only when a property used in a dynamic binding changes value. Your object can have properties for which you do not fire change notifications.

For performance reasons, you should fire the change notifications only when the property has really changed value. When the object doesn t know which property changed value, it can request that all bindings to any property on itself be updated, or it can pass String.Empty for the changed property name.

The Data Source Item

Longhorn provides a set of built-in data sources, which enables you to easily and declaratively get data into the application asynchronously and without blocking UI.

A data source item is any object that implements the IDataSource interface.

 interface IDataSource { 
public virtual Object Data { get; }
public virtual void Refresh()
}

This interface has a Data property that lets the binding get the data from the data source item. The Refresh method allows the binding to request that the data source item retrieve its data when it s not available. Longhorn provides a number of data source classes, and you ll see some of them shortly.

Generally, a data source implementation also provides a strongly typed property that returns the native API of the data provider. For example, the SqlDataSource and XmlDataSource classes provide the DataSet and Document properties, respectively:

 class SqlDataSource : IDataSource,  { 

DataSet DataSet { get; }

}
class XmlDataSource : IDataSource, {

XmlDocument Document { get; }

}

Therefore, if you really have to, you can directly access the underlying data provider.

Using Any CLR Object as a Data Source

The ObjectDataSource class allows you to create an instance of a specified type as a data source item. Commonly, you ll use XAML and declare your data sources as resources in your markup. For example, assume that I have the following definition of a Person class in an assembly called MyAssembly and that I d like to use an instance of this class as a data source item:

 namespace MyNamespace { 
public class Person {
private string m_name;
private int m_age;

public string Name { get { return m_name; } }
public int Age { get { return m_age; } }

public Person (string name, int age) {
m_name = name; m_age = age;
}
}
}

The Person class doesn t need any additional support to be a data source item. I can use an instance of the ObjectDataSource class as the data source item and inform it that the underlying data provider should be an instance of the Person class. To do this, I can use markup to declare an instance of an ObjectDataSource as a XAML resource.

 <DockPanel> 
<DockPanel.Resources>
<ObjectDataSource def:Name ="source1"
TypeName="MyNamespace.Person, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0123456 789abcdef"
Parameters="Brent, 0x30" />
</DockPanel.Resources>
</DockPanel>

As always, XAML element names represent Framework class names . Therefore, the ObjectDataSource element says to create an instance of the ObjectDataSource class. The value of the def:Name attribute is the name of this resource ( source1 in the preceding example).

The ObjectDataSource instance will create a new instance of the class referred to by TypeName either by calling its default constructor or, when you specify the Parameters attribute, by calling the constructor that best matches the signature of the value of the Parameter attribute.

Recall that markup is equivalent to code, so the preceding markup is the same as the following code:

 ObjectDataSource source1 = new ObjectDataSource(); 
source1.TypeName = "MyNamespace.Person, MyAssembly, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=0123456789abcdef";
source1.Parameters = "Brent, 0x30";

The ObjectDataSource class also provides mechanisms to call methods on objects and refer to existing objects in addition to simply instantiating a new object.

Using a Data Source with Data Binding

One can declare a data source as a resource in the Resources property of an element or the application level resources. Any data source declared in the Application resources can be used across the application in any page. A data source defined in the resources of an element can be used only within the scope of the element.

 <DockPanel 
<DockPanel.Resources>
<ObjectDataSource def:Name="source1"
TypeName="MyNamespace.Person, MyAssembly, "
Parameters="Brent, 0x30" />
</DockPanel.Resources>

<Button Text="*Bind(Path=Name ; BindType= OneWay; DataSource = {source1}"/>
<Button DataContext="*Bind(DataSource={source1})" Text="*Bind(Path=Name)"/>

</DockPanel>

In the example just shown, the data binding binds the data source called source1. You can set the DataSource attribute to the resource ID of a XAML Resource. When the resource implements the IDataSource interface, the runtime will set the Source property of the Bind instance to the object returned by the Data property of the specified DataSource resource. When the resource does not implement the IDataSource interface, the runtime sets the Source property of the binding to the resource object itself.

In the prior example, the DataSource attribute references an ObjectDataSource resource. Therefore, the binding requests the Data property from the ObjectDataSource . The data source, in turn , instantiates the Person class as specified in the markup.

In the first Button, the Source property of the Bind instance references this Person object instance. The path is simply Name , so the binding retrieves the Name property of the Person instance.

In the second Button, DataContext is bound to the ObjectDataSource . This action will set DataContext of the Button to the Person object so that any bindings on Button will use the Person object as the default source for their bindings.

One can similarly data-bind to any of the available data sources. Some of the other data sources shipped with Longhorn are mentioned in paragraphs that follow. Others, such as data sources to get data from Web services, will be coming online.

Using XML as a Data Source

The XmlDataSource class is a data source that uses an XML Document Object Model (DOM) as the underlying data provider. You can use markup to create the DOM from a Uniform Resource Locator (URL) referencing an XML stream. You can also create the DOM by supplying the XML inline with the markup as the following example demonstrates :

Using URI

 <DockPanel> 
<DockPanel.Resources>
<XmlDataSource def:Name="source2"
Source="http://www.wiseowl.com/People.xml"
XPath="/People/Person[@Age>21]" />

Using inline markup

 <XmlDataSource def:Nsme="source3" 
XPath="/People/Person[@Age>50]" >
<People>
<Person Name=


Introducing Microsoft WinFX
Introducing WinFX(TM) The Application Programming Interface for the Next Generation of Microsoft Windows Code Name Longhorn (Pro Developer)
ISBN: 0735620857
EAN: 2147483647
Year: 2004
Pages: 83
Authors: Brent Rector

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net