UpdateSourceTrigger – DataBinding
Last week while working on two way binding, I discovered one very important settings for binding i.e. “UpdateSourceTrigger”. Before discovering this feature I faced problem in setting the value from target to source. Let me describe the problem I faced.
In my setup, I had no. of text boxes in window whose text property were bound to the property of object in collection. So in this case, source for me was property of the object in collection and target was the text property of textboxes.
I configured my binding object as below :
Binding binding = new Binding();
binding.Source = <source object from collection>;
binding.Path = new PropertyPath(<PropertyName>);
binding.Mode = BindingMode.TwoWay;
txtbox.SetBinding(TextBox.TextProperty, binding);
With above binding configuration, source –> target binding worked perfectly for me. But binding from target –> source (i.e. from text box to object’s property in collection) was not working for me. One thing which is important to mention here is, I was changing the text box’s text value in procedural code and not by entering the value in textbox.
It was beyond my understanding why binding was not working? I spent almost half a day trying to figure out this. I googled it but google disappointed me. So I took Adam Nathan’s “WPF Unleashed” book in my hand and started looking for some solution. Again this book came to my rescue. While going through the “Data Binding” chapter in this book, I learned about “UpdateSourceTrigger’ property of the binding object.
“UpdatesourceTrigger” property is very important in “TwoWayBinding” and “OneWayToSource” binding modes. It defines how and when source should get updated.
Value of UpdateSourceTrigger could be any of the value from UpdateSourceTrigger Enumeration. Enumeration values are
- PropertyChanged – The source is updated whenever the target property value
changes. - LostFocus – The source is updated when target property changes and target object looses focus.
- Explicit – The source is updated when explicit call is made to update using “BindingExpression.UpdateSource”.
Target controls have default values set for “UpdateSourceTrigger” for binding object. For text box control, default setting for this property is “LostFocus”. In my case, I was updating the textbox (i.e. target) through code and because of that textbox was not loosing focus. Hence my binding was not working. Then I changed above binding configuration to set the UpdateSourceTrigger property of binding object as following :
Binding binding = new Binding();
binding.Source = writeItemInfoList[index];
binding.Path = new PropertyPath("ItemValue");
binding.Mode = BindingMode.TwoWay;
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
txtbox.SetBinding(TextBox.TextProperty, binding);
And Binding from Target to source started working for me.
SQLBulkCopy
I was looking to copy some bulk data from one of the data table in memory to my SQL DB table. I tried using DBAdapter.Update but it didn’t work as in my source datatable none of the row was in updated/new stage. Then after searching a lot, I found “SQLBulkCopy”.
The SqlBulkCopy class can be used to write bulk data only to SQL Server tables. However, the data source is not limited to SQL Server; any data source can be used, as long as the data can be loaded to a DataTable instance or read with a IDataReader instance. To copy the source data to destination table in the sql server, need to set destination table name and execute “WriteToServer” method. Following code snippet
// create sqlBulkCopy object
SqlBulkCopy bulkCopy = new SqlBulkCopy(connString);// set destination table name for sqlBulkcopy object
bulkCopy.DestinationTableName = "[Table Name]";// write source data to destination sql table
bulkCopy.WriteToServer();
Performancewise using SQLBulkCopy is far better than using normal Insert/Update commands.
Reading csv file in datatable
Recently I had to work on one problem where I had to read the csv file and filling up the data table with the csv file data. I used the OLEDBAdapter to accomplish that with just few lines of code. Following is the code :
string query = "SELECT Symbol, [Name of Company], FROM [just file name with extension]";
string connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + [csv file path without file name] + ";" + "Extended Properties=’text;HDR=YES;’";//create dataadapter object
OleDbDataAdapter adapter = new OleDbDataAdapter(query, connStr);// create table
DataTable dtSymbolDetails = new DataTable("ScriptDetails");
dtSymbolDetails.Columns.Add("Symbol");
dtSymbolDetails.Columns.Add("Name of Company");// fill the table with data using adapter
adapter.Fill(dtDetails);
So above code fills up the details of the csv file in the data table for further use.
Also note the text in red above. If column name contains the space then in query the column name should be put between [ ]. I learned it in bit hard way. It shows I’m so poor in my sql knowledge.
Resources in WPF – II (Logical Resources)
Logical resources are arbitrary .net objects stored (and named) in element’s ResourceDictionary. Logical resource can be shared among multiple elements depending upon the scope at which it has been defined. Both FrameworkElement and FrameworkContentElement has ResourceDictionary defined in it, hence almost all UI elements inherit the ResourceDictionary. Typical logical resources are styles, bindings, etc.
Logical resources are of two types :
1) StaticResources
2) DynamicResources
How resources are searched?
StaticResource/DynamicResource markup extension accepts a key name as parameter. So this key is searched while looking up for resource. It is not mandatory that resource has to be defined on the element which is using it. Xaml looks for the resource at the element level first then to parent level and then to application level. Resource markup extension implements the ability to walk the logical tree to find the items upward in the logical tree so if resource is not found, it checks the parent element, its parent and so on until it reaches the root element. At this point, it checks the resources collection at the application level and system level subsequently. If the resource is not found anywhere, it throws “InvalidOperationException”.
Although it is advisable to have unique key associated with resource, however it is not mandatory. While looking up for the resource whatever resource is found first is assigned.
Static v/s. Dynamic Resources
|
Static Resources |
Dynamic Resources |
|
StaticResource is applied only once (first time when it is used). |
DynamicResource is applied every time when resource changes e.g. system colors can be changed using control panel. So if system colors has been used as resource, than update is required. DynamicResource will take care of such change in resource. |
|
StaticResource has lesser overhead as it is applied only once during the runtime of the application. |
DynamicResource has more overhead as it is applied whenever the resource value changes. In order to do this, DynamicResource has to keep tracking about the changes in the resource during runtime also. |
|
StaticResources always get loaded the first time window/page is loaded irrespective of its use during start up. |
DynamicResources are not loaded until it is actually used. So this results in better load time. |
|
StaticResources can be used for DependencyProperty as well as normal .net property. |
DynamicResource can only be used for DependencyProperty. |
| StaticResources has to be defined before it is used. Hence, StaticResources can not be forward referenced. | DynamicResources can use the forward references. |
Defining and Applying Resources from procedural code
At element level adding resources (at definition level, static/dynamic resource is not differentiated) is easy. The syntax is
<element>.Resources.Add(object key, object value);
Static Resource
If in xaml, resources are used as static resource as shown below (provided resource is already defined)
<Button BackGround={StaticResource backgraoundBrush}/>
then from procedural code, this resource can be used as
Button button = new Button();
button.BackGround = (Brush)button.FindResource(“backgroundBrush”);
If “FindResource” fails to find the resource, it throws “ResourceReferenceKeyNotfoundException”. To avoid this situation, “TryFindResoruce” method can be used which returns ‘null’ if the resource key is not found.
Dynamic Resource
in xaml, dynamic resource can be used as mentioned below :
<Button BackGround={DynamicResource backgraoundBrush}/>
however in procedural code this can be set using SetResourceReference method as shown below :
button.SetResourceReference(Button.BackgroundProperty, “backgroundbrush”);
Do remember that forward reference (i.e. defining the resource before using it) still remains invalid for Static Resource even with procedural code.
Accessing Resources from other assemblies
In many cases resources are defined in separate assembly for the sake of better maintainability. In that case resources can be accessed from different assembly in following way ;
<Button BackGround={DynamicResource {ComponentResourcekey TypeinTargetAssembly=”local:MyResources, ResourceID=backgroundBrush }}
Sometimes the other assembly in which the resource has been defined provides way to access the resource by defining property in class.
public object MyResourceKey
{
get {return (new ComponentResourcekey (this.GetType(), “backgroundBrush”);}
}
In such a case, resource can be accessed from xaml in following way :
<Button BackGround=”{DynamicResource {x:static local:MyResourceKey}}”
Accessing System Resources
Sysem Resources i.e. System Fonts, System colors etc. can be used in similar way as mentioned above.
<Button BackGround =”{DynamicResource {x:static SystemColors.Desktopcolor}}”
Resources in WPF – I (Binary Resources)
There are two types of resources in WPF :
1) Binary Resources
2) Logical Resources
In this post, I have described the details of the Binary resources.
Binary Resources : Binary resources could be logo/image files, AV files etc. Resource files which are added to project, can have the “Build Action” defined on it from the file properties windows.
Out of the various build actions defined by WPF only following two are important for binary resources :
-
Resource : Embeds resource into the assembly (or culture specific satellite assembly)
-
Content : this leaves resource as loose file and upon compilation this resource information is not embedded to assembly. Instead, it adds custom attribute to the assembly (AssemblyAssociatedContentFile) which records the existence and relative location of file.It is also possible to access the resource file without adding into the project however with this approach management of resource file becomes bit difficult. However, this approach is useful is resource file is generated dynamically using some runtime information. In such a case, resource file will not be available at compile time so can not be added to project.
What is the difference between the “Resource” and “Embedded Resource” build actions?
“Resource” and “Content” build actions are to access the WPF resources using the Uris. However “Embedded Resource” is for prior technologies. However both options embeds the resource in assembly but “Resource” option to be used for WPF.
URIs for accessing the binary resources
URI
Resource
“Logo.jpg”
- embedded in current assembly (using “Resource” as build action)
- loose resource however physical file is placed along with xaml file or assembly (if selected build action is “Content”)
“A/B/Logo.jpg” same as above but resource file is located in subfolder “A/B” “D:\Resource\Logo.jpg” resource path hard coded http://pinvoke.net/logo.jpg loose resource hosted at pinvoke.net website. ResourceDll;component/Logo.jpg this URI represents the resource embedded in assembly ResourceDLL.dll or ResourceDLL.exe ResourceDll;componen/tA/B/Logo.jpg same as above except resource is located in subfolder pack://siteOfOrigin:,,,/logo.jpg resource located at site of origin pack://siteOfOrigin:,,,/A/B/logo.jpg resource located at site of origin in sub folder
Site of Origin :
Site of origin at the runtime gets resolved in different ways depending upon the way in which the application has been deployed.
- For a full-trust application installed with Windows Installer, the site of origin is the application’s root folder.
- For a full-trust ClickOnce application, the site of origin is the URL or Universal Naming Convention (UNC) path from which the application was deployed.
- For a partial-trust XAML Browser Application (XBAP) or ClickOnce application, the site of origin is the URL or UNC path that hosts the application.
- For loose XAML pages viewed in Internet Explorer, there is no site of origin. Attempting to use it throws an exception.
Accessing resources from procedural code :
While accessing the resource from procedural code in WPF, triple comma syntax is used however above table for URIs remains still applicable except the last two rows with site of origin.
e.g. to read the embedded resource with “Resource” action “pack://application:,,,/logo.jpg’” can be used.Following code shows how to read the resource from procedural code :
Image image = new Image();
image.Source = new BitmapImage(new Uri(“pack://application:,,,/logo.jpg”))
There is one more aspect to binary resource and that is localization but I’m not covering it as of now.
retrieving command-line args for WPF application
Normally in winform applications, command line arguments are accessed from the string array argument in the main method. However in WPF main method is auto generated and can not be acceEditssed directly. So how to access the command line args with WPF application.
The answer is use “System.Environment.GetCommandLineArgs”. Calling this method returns command line arguments at any given point of time.
Attached Properties
Attached property is a special type of dependency property that is intended to be used as global property. One of the purpose of Attached property is to allow child elements to set different value for property which has been defined on parent element. Examples of Attached properties are DockPanel.Dock, Grid.Row, Grid.Column, Canvas.Left, Canvas.Top etc. The use of Attached property is similar to static property and it can not be accessed through instance object.
Attached properties don’t implement wrappers for property because Attached property may not be part of the clr namespaces for the instances on which it is set. However, attached property implementer provides the accessors to access the property value.
DockPanel dockPanel = new DockPanel();
Button myButton = new myButton();
dockPanel.Childern.Add(myButton);
DockPanel.SetDock(myButton, Dock.Left);
Defining attached property is almost same as defining the dependency property. The only change is during the registration instead of ‘Register’ use ‘RegisterAttached’ method of DependencyProperty. Also, don’t implement the property wrapper for the attached property. But instead of property wrapper implement the Get and Set accessor for the property.
Shared Dependency Property
Dependency property defined in one class can be shared between different classes e.g. TextBlock.FontFamily and Control.FontFamily share the dependency property defined in the TextElement class.
Dependency property can be shared with other classes by calling a ‘AddOwner’ method on dependency property which is being shared as shown below ;
TextBlock.FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock));
AddOwner method also has one overload which accepts the FrameWorkPropertyMetadata object. So using this metadeta object property metadata can be specified.
However, sharing dependency property can be misleading sometimes. Following example describes that scenario :
Class T1 derives from Textbox having dependency property ‘IntTestProperty"’ defined in it. Class T2 shares the “IntTestProperty” implementation with the class T1.
In xaml code, I have defined style where I’m setting the dependency property “IntTest” values for both T1 & T2 types.
code behind file :
// This class actually defines the Dependency property
public class T1 : TextBlock
{
// Definition of Dependency property
public static readonly DependencyProperty IntTestProperty = DependencyProperty.Register("IntTest", typeof(int), typeof(T1));public int IntTest
{
get { return (int)GetValue(IntTestProperty); }
set { SetValue(IntTestProperty, value); }
}
}// definition of class which uses the dependency property defined above
public class T2 : TextBlock
{
public static readonly DependencyProperty IntTestProperty = T1.IntTestProperty.AddOwner(typeof(T2));
public int IntTest
{
get { return (int)GetValue(IntTestProperty); }
set { SetValue(IntTestProperty, value);}
}
}
Xaml code :
// style definition to apply on object
<Style x:Key="TestStyle">
<Setter Property="dc:T1.IntTest" Value="5"/>
<Setter Property="dc:T2.IntTest" Value="10"/>
</Style><Canvas Left="300" Style="{StaticResource BigFontStyle}">
<dc:T1 x:Name="t1" Style="{StaticResource TestStyle}"/>
<dc:T2 x:Name="t2" Style="{StaticResource TestStyle}"/>
</Canvas>
After initialization, if we read the value of the “IntTest” property for object t1 and t2 then value of both will be 10. As per the style definition the value of t1 object’s “IntTest” property should 5 and t2 object’s “IntTest” property should be 10. But because t1 and t2 share the same dependency property infrastructure, code sets the value of dependency property twice and when value is read for the property it returns the latest value set on it. That is why value is read as 10 after initialization with above code.
Dependency Property
Dependency property is new property mechanism introduced by WPF. It is very much different from the normal .net properties but it is very important as many of the WPF’s advance features like styling, triggers, databindings, animations etc. can only work with dependency properties only. Dependency property derives it’s name from the fact that it depends on multiper providers to determine it’s value at any point of time. Dependency property is new property mechanism introduced by WPF.
Implementation :
Following code shows the implementation of dependency property “IsCancelProperty” inside the button control.
——————————————————————————————————————————————————————————————
public class Button : ButtonBase
{
// The dependency property
public static readonly DependencyProperty IsCancelProperty;
static Button()
{
// Register the property
Button.IsCancelProperty = DependencyProperty.Register(“IsCancel”,
typeof(bool), typeof(Button),
new FrameworkPropertyMetadata(false,
new PropertyChangedCallback(OnIsDefaultChanged)));
…
}
// A .NET property wrapper (not must)
public bool IsCancel{
get { return (bool)GetValue(Button.IsCancelProperty ); }
set { SetValue(Button.IsCancelProperty , value); }
}
// A property changed callback (not must)
private static void OnIsCancelChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e) { … }
…
}————————————————————————————————————————————————————————–
By convention, all the dependency properties are public, static and have “property” as suffix. Dependency properties are created by calling a static “DependecnyProperty.Register” method. “DependencyProperty.Register” method needs information like property name, property type, type of the class on which the property has been defined. Optionally, metadata and callback information can also be passed into the Register method.
In above code, traditional .net property(ISCancel) implements its accessor by calling a GetValue and SetValue methods(these methods inherits from System.Windows. DependencyObject). Calls like Button.GetValue(IsCancelProperty) / Button.SetValue(IsCancelProperty,true) is valid but implementing .net style property wrapper “IsCancel” makes reading and writing of the fields easier and user friendly.
Point to Remember
Although XAML compiler makes use of the .net property wrapper at compile time, at run time WPF calls the GetValue/SetValue methods directly. So to maintain the parity between the compile time and runtime operation, it is important that the property wrapper implementation does not include anything accept the GetValue/SetValue call.
Another important point is “IsCancelProperty” is static field and not the instance field, hence the dependency property implementation saves the per instance memory compared to typical .net property e.g. if button has got say 100 .net properties than each instance of button will result in creation of 100 fields for property information. This results in use of extensive memory as the no. of objects increases. But with dependency property it is not the case.
Motivation :
Now what is the motivation behind putting up this complex property mechanism in place> Following are the reasons :
1. Change Notifications
2. Property Value Inheritance
3. Support for Multiple providers
Change Notification
Whenever the value of the dependency property changes, WPF can automatically trigger number of actions depending upon the property’s metadata. One of the most important feature enabled by this built in change notification is property triggers, which enables to perform custom action when property value changes without writing any procedural code.
Property Value Inheritance
Property value inheritance means allowing the properties of the parents to flow down to the children in a tree e.g. if FontSize(which is dependency property) value is set on to the window class, the same FontSize value will also be applied to all the children of the Window for which the FontSize value is not explicitly set. If for particular children, FontSize is set explicitly the parent settings will not be applied.
Point to Remember
Not all dependency properties participate in Property Value Inheritance. Dependency properties can opt in to inheritance by passing the FrameworkPropertyMetadataOptions.Inherits to DependencyProperty.Register.
Support for Multiple providers
Multiple sources try to set the value of the dependency property however there is a defined mechanism based on which the final value is arrived at for dependency property. It is basically a five step process after going through which the value of the dependency property is finalized.
1. Determine the Base Value
Following eight providers can set the base value for property in chronological order :
- Local Value
- Style triggers
- Template Triggers
- Style setter
- Theme style triggers
- Theme style setters
- Property value inheritance
- Default Value
2. Evaluate
If the value from step 1 is expression, then WPF performs a special evaluation step to convert the expression into concrete result.
3. Apply Animation
If animations are running then they can alter/overwrite the value of the property derived from above two steps. Animation has higher precedence than the local value so animation can overwrite the local value.
4. Coerce
Property value derived from above step is passed to the CoerceValueCallback delegate, if registered with the property. This callback method provides the new value based on the custom logic set in callback. Property value derived from above step is an input to callback delegate.
5. Validate
Finally, coerced value is passed to ValidateValueCallback delegate, if registered with the property. This callback may have some validation checks. Callback returns true if value is valid and sets the property value. However, if Callback returns false, it raises in exception and entire process gets cancelled and value is not applied to property.
P.S. :-
The above explanation of the topic may be bit theoretical but in coming days I will try to come out with the detail explanation of each point with illustrations.
XAML Compilation
XAML compilation involves three things :
- Converting XAML file in special binary format (namely BAML)
- embedding the converted content as a binary resource in the assembly being built
- performing the plumbing work that connects XAML with procedural code
Point to ponder :-
Normally XAML file declartaion starts with x:Class but it can also do without it. When x:Class is not used it means it’s pure xaml file without any code behind file. It means features related to procedural code can not be used.
Recent Comments