Silverlight: Alternative to using a DataContextProxy? - silverlight

We have been using the DataContextProxy concept based on (or exactly) as described in Dan Wahlin's Blog. Functionally This has worked fine for our purposes. However, after doing extensive memory profiling, and after discovering similar reports online (link below), it seems that this approach leaks memory as a result of a problem/bug with UserControl.Resources.
Has anyone found a decent alternative to the DataContextProxy approach?
Connect Report, which says the problem has been fixed in SL 5. I am going to try to post a repro solution for SL4.

I've come up with something very close to the DataContextProxy but instead of the binding being created in the Loaded event of the class, the declaration in the XAML binds back to the class. Seems to work exactly the same except it doesn't leak.
Would love someone else to verify this.
<UserControl.Resources>
<local:DataContextProxy x:Key="DataContextProxy" ViewModel="{Binding Path=DataContext, ElementName=LayoutRoot, Mode=TwoWay}" />
</UserControl.Resources>
The class
namespace Silverlight.Infrastructure
{
/// <summary>
/// Refactored to not leak. Set binding on ViewModel propery to DataContext of page, in Resources of page
/// Binding in XAML on declaration of DataContextProxy
/// Usage: <shared:DataContextProxy x:Key="DataContextProxy" ViewModel="{Binding Path=DataContext, RelativeSource={RelativeSource Self}, Mode=TwoWay}" />
/// </summary>
/// <remarks></remarks>
public class DataContextProxy : DependencyObject
{
public static DependencyProperty ViewModelProperty = DependencyProperty.Register("ViewModel", typeof (object), typeof (DataContextProxy), new PropertyMetadata(default(object)));
public object ViewModel
{
get { return (object)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
}
}
usage:
DataToBindTo="{Binding ViewModel.DataToBindTo, Source={StaticResource DataContextProxy}}"
Changed the binding to ElementName as it seemed to work better on child views that didn't get a viewmodel until after the binding had been initially resolved.

You can look at this SL implementation of a relative source binding. Caliburn Micro also has a way to solve this problem by Action bubbling.

I'm not aware of memory leaks problems, but as Silverlight 4 introduced ElementName in bindings, it mostly eliminates the need for a DataContextProxy:
<ListBox ItemsSource="{Binding DataContext.Languages, ElementName=LayoutRoot}">
More explanations here.

Related

Changing WPF Decorator Child Base on a Property Value

I have a WPF control whose content completely depends on a property of its data context. For the sake of this, let's just say the control's DataContext is of type Product, which has a Status property of InStock, OutOfStock, or Discontinued.
I have individual user controls for each of those status types. I could, and have, created some kind of panel that binds the visiblity of each to Product.Status. But that created problems, since some of the user controls ended up with funky stuff because some depend on various properties being set. And in my actual application, there are many statuses, so the visualtree gets too big for my taste.
I solved the problem by creating and in my code, I check for a status change on the DataContext and set the appropriate child in a big switch statement. I would like to do this in XAML if possible. I want the child to be set on demand, so I assume I'll need to use templates. Something like this:
SwitchControl would derive from Decorator or Border, whatever.
<SwitchControl Property="Status">
<SwitchControl.Possibilities>
<Possibility Value="Discontinued">
<Possibility.Template>
<DiscontinuedView />
</Possibility.Template>
</Possibility>
<Possibility Value="InStock">
<Possibility.Template>
<InStockView />
</Possibility.Template>
</Possibility>
<SwitchControl.Possibilities />
</SwitchControl>
It would be even better if I could shorten the whole thing to:
<SwitchControl>
<Possibility Value="Discontinued">
<DiscontinuedView />
</Possibility>
<Possibility Value="InStock">
<InStockView />
</Possibility>
</SwitchControl>
Point being, only one child would exist at any given time. Anyone know of a way to get this done? I looked around in MVVM frameworks and couldn't find anything. Otherwise I'll experiment with creating a custom control myself.
You might want to take a look at the DataTemplateSelector class. This allows you to define templates based on different criteria, e.g. the type of the current DataContext. An example could look somewhat like the following:
public class MyDataTemplateSelector : DataTemplateSelector
{
public DataTemplate DiscontinuedDataTemplate { get; set; }
public DataTemplate InStockDataTemplate { get; set; }
public DataTemplate OutOfStockDataTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var product = item as Product;
switch (product.Status)
{
case Status.InStock:
return InStockDataTemplate;
case Status.Discontinued:
return DiscontinuedDataTemplate;
case Status.OutOfStock:
return OutOfStockDataTemplate;
}
// Fallback
return DiscontinuedDataTemplate;
}
}
...and use it in the following way:
<Window.Resources>
<DataTemplate x:Key="DiscontinuedDataTemplate">
<DiscontinuedView />
</DataTemplate>
<DataTemplate x:Key="InStockDataTemplate">
<InStockView />
</DataTemplate>
<DataTemplate x:Key="OutOfStockDataTemplate">
<OutOfStockView />
</DataTemplate>
<!-- DataTemplate Selector -->
<local:MyDataTemplateSelector x:Key="MyTemplateSelector"
DiscontinuedDataTemplate="{StaticResource DiscontinuedDataTemplate}"
InStockDataTemplate="{StaticResource InStockDataTemplate}"
OutOfStockDataTemplate="{StaticResource OutOfStockDataTemplate}"/>
</Window.Resources>
<ContentControl ContentTemplateSelector="{StaticResource MyTemplateSelector}" Content="{Binding Product}"/>
Thanks for the suggestion andreask. I ended up creating a control that I think solves the problem more directly. I've been working on a WPF helper library that I'll post to nuget in the future, but if you want to use it now, it's at:
https://gist.github.com/StevePotter/b17f8d4b2657a2d2610390a11fb57e03
Example XAML is included. I hope this is useful for someone!

WPF MVVM Implementation

I have just started using WPF with MVVM pattern. I had gone through some material related to MVVM.
However, the project I have to work on has an implementation of MVVM that seems very different than what I have read (maybe incorrect as well, not sure).
The implementation has all the Views (controls or windows) implemented as ResourceDictionary where all the controls, in the view are in the "Style" element.
The code behind for such ResourceDictionary have all the DependencyProperty and the Commands (there is no other class for ViewModel). Also, the classes (code behind) some how inherit from the Windows.Controls.Control class.
Is this the correct implementation ? If not what are the reasons that you see that prove this as a wrong implementation.
I may be wrong but the reasons I see are the following:
Implementing views as ResourceDictionary is not correct and Resources are not for creating custom views.
Having minimal code in the code behind is one of the important aspects of MVVM, that allows for loosely coupled architecture.
Since all views inherit from Windows.Controls.Control, writing unit test cases for the views would be difficult.
Am I correct or there are some other reasons that this implementation is incorrect (or am I wrong and this can be a way to implement MVVM in WPF).
Your views are highly appreciated.
Below is a sample code: (XAML)
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Presentation"
>
<Style TargetType="{x:Type local:FirstControl}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:FirstControl}">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Height="490" DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneTime}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="TEST TEXT" FontWeight="DemiBold"/>
<Button Command="{Binding Path=CloseCommand, Mode=OneTime}"
Width="48" Height="30"/>
</StackPanel>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code Behind:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
namespace Presentation
{
/// <summary>
/// View-model
/// </summary>
public class FirstControl : Control
{
static FirstControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(FirstControl), new FrameworkPropertyMetadata(typeof(FirstControl)));
}
public FirstControl()
{
CloseCommand = new DelegateCommand(OnCloseCommand);
}
private void OnCloseCommand()
{
// Write code to close application.
}
public static readonly DependencyProperty CloseCommandProperty = DependencyProperty.Register("CloseCommand", typeof(ICommand), typeof(FirstControl));
public ICommand CloseCommand
{
get { return (ICommand)GetValue(CloseCommandProperty); }
set { SetValue(CloseCommandProperty, value); }
}
}
}
Hope this helps.
The DelegateCommand is a class to allow delegating command logic to methods passed as parameters.
The main point of MVVM is to allow each layer to be fully tested without the need of "higher" layers.
You should be able to test the Model, and in that test you should be able to successfully complete all the tasks required to send and retrieve data from your data store. Your model testing should not require any view or view-model to complete.
You should be able to test your View Model without the need for any UI code or other View level code. Your View Model should be able to logically do everything your application needs to do without any user interraction or UI code. Ideally, you should be able to test your ViewModel using mocked Model classes that provide predictable responses.

How do I bind a "list" of strings to a ComboBox in WPF?

I basically want to take a bunch of names in a collection and bind them to a combobox. For example:
Bill
Jack
Bob
Kevin
and have those items in a collection and have it bound to the ComboBox. I'm not sure if the list will be updated dynamically or not, but I prefer to plan for it to be. Any help would be appreciated. I've been trying for a few hours now and can't figure it out. I want to do it in XAML and not the code-behind. In the code-behind,
MyComboBox.ItemsSource = MyObservableCollection;
works fine. I don't know how to do that in XAML though with the collection declared in the code-behind.
Thanks in advance (again), community.
*EDIT:
This is how I have the collection declared and accessible.
public ObservableCollection<string> propertynames
{
get {return _propertynames;}
}
private ObservableCollection<string> _propertynames;
The last thing I tried was this:
<Window.Resources>
<CollectionViewSource Source="{Binding propertynames}" x:Key="srcSort"/>
</Window.Resources>
....
<ComboBox x:Name="cboSort" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="256" Background="WhiteSmoke" Margin="12,50,0,0" FontSize="12pt"
Height="27.28"
SelectedIndex="0"
SelectionChanged="cboWorkCenters_SelectionChanged"
ItemsSource="{Binding Path = {StaticResource srcSort}}">
</ComboBox>
....
I'm a total n00b to this stuff. Been in it about a week now, so I may have done something really obvious to a seasoned user.
*EDIT #2
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:WpfApplication1"
Title="Window1" Height="226" Width="242"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<ComboBox Margin="43,71,40,77"
Name="comboBox1"
ItemsSource="{Binding ob}" />
</Grid>
</Window>
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public ObservableCollection<string> ob
{
get
{
return _ob;
}
}
private ObservableCollection<string> _ob = new ObservableCollection<string>();
public Window1()
{
InitializeComponent();
FillObj();
//comboBox1.ItemsSource = ob;
}
private void FillObj()
{
for (int i = 1; i < 6; i++)
{
_ob.Add(i.ToString());
}
}
}
}
Made above real simple project just to see if I was doing it all wrong. This worked fine so something else must be causing it to fail.
*EDIT #3
*PROBLEM FIXED
For God's sake, I figured it out. I've been on this for HOURS and it's just silly what's caused it to fail.
The solution is this: I wasn't instantiating _propertynames when I declared it. I was querying the class properties with Linq to get the list of properties and then created _propertynames by passing ...GetProperties.ToList<...>() to the constructor. Apparently, you have to instantiate the variable so it hits during InitializeComponent. Unreal.
Once I did that and then added the items to it after the fact, it worked fine.
I wish WPF had a face so I could punch it. I know it's my ignorance of how it works, but I really could have used some kind of message.
Thanks guys for the help. Both of your suggestions were useful once I took care of the root issue.
private ObservableCollection<string> _propertynames
needs to be
private ObservableCollection<string> _propertynames = new ObservableCollection<string>()
There are countless ways of doing this. Once you've created the collection in code-behind, you can:
Call Resources.Add to add it to the window's resource dictionary, and then bind to the resource, e.g. ItemsSource="{Binding {DynamicResource MyList}}".
Give the ComboBox a name (using the x:Name attribute) and set its ItemsSource explicitly in code, e.g. MyComboBox.ItemsSource = myCollection;.
Create a class, make the collection a property of the class, and set the window's DataContext to an instance of that class and bind to it directly, e.g. ItemsSource = "{Binding MyCollectionProperty}".
Make the collection a property of the window, set the window's DataContext to this, and bind to the property (this is essentially the same technique as #3, only you're not creating a new class).
Without setting the window's DataContext, you can still reference a property on it using binding as long as you've given it a name, e.g. {Binding ElementName=MyWindow, Path=MyCollection}. (This is the same as Ross's suggestion.)
Or, without giving the window a name, you can use RelativeSource binding to find the ancestor Window and bind to a property on it. I don't have any confidence in my ability to write a working binding expression that uses RelativeSource off the top of my head, so I'll leave that as an exercise for the reader.
You can set the DataContext of the ComboBox to the instance of your collection, and then set itsItemsSource to {Binding}. You probably wouldn't do this in practice; I mention it just because it seems to be a common mistake for people to set the DataContext of a control without also setting a binding, and then wonder why content from the bound object isn't showing up.
(While I've said "window" in the above, everything I've said is also true for user controls.)
I'm sure there are at least five other ways to do this that I'm not thinking of. Binding is really, really flexible.
What have you tried so far?
I would approach it as follows, assuming the combo box is within a UserControl with a code-behind class containing the public property MyObservableCollection:
<UserControl x:Name="MyCollectionOwnerControl">
<ComboBox ItemsSource="{Binding ElementName=MyCollectionOwnerControl, Path=MyObservableCollection, Mode=OneWay}" />
</UserControl>

Can a XAML object be a source for one binding as well as a target for another binding?

Is it possible to have a TextBlock as a target and a source?
Basically I have a bunch of entities which have simple relationships to other entities (like Entity1 Knows Entity3, Entity3 WorksAt Entity2 etc.)
I have a Link class that stores SourceEntity, Relationship and TargetEntity details.
What I want to be able to do is to select an entity then display the relationships related to that entity, with the target entities of each relationship listed underneath the relationship names.
When an entity is selected, an ObservableCollection is populated with the Links for that particular entity (SelectedEntityLinks<Link>).
Because each entity could have the same relationship to more than one target entity (Entity1 could know both Entity3 and Entity4 for eg.), I've created a method GetThisRelationshipEntities() that takes a relationship name as a parameter, looks through SelectedEntityLinks for relationship names that match the parameter, and returns an ObservableCollection with the target entities of that relationship.
In my xaml I have a WrapPanel to display each relationship name in a TextBlock:
<TextBlock x:Name="relationship" Text="{Binding Path=Relationship.Name}" />
Then underneath that another Textblock which should display the results of GetThisRelationshipEntities(String relationshipName).
So I want the "relationship" TextBlock to both get its Text from the binding I've shown above, but also to provide its Text as a parameter to the GetThisRelationshipEntities() method which I've added to <UserControl.Resources> as an ObjectDataProvider.
Sorry if this is a bit wordy but I hope it's clear. Any pointers/advice would be great.
To me it sounds like you should create a value converter class using IValueConverter and a property which is you relations table.
When doing
<TextBlock x:Name="relationship" Text="{Binding Path=Relationship.Name}" />
you would add
<TextBlock x:Name="relationship" Text="{Binding Path=Relationship.Name, Converter={StaticResource myRelationConverter}}" />
in the Convert() method you can do any crazy thing you want to.
I'm not entirely sure i got what you're trying to do, but i suggest trying to set the binding mode to TwoWay.
<TextBlock x:Name="relationship" Text="{Binding Path=Relationship.Name}"
Mode=TwoWay />
although now that i think about it, it might be the default option, so you can also try to call the GetThisRelationshipEntities() function on the TextBlock, every time it's source is updated:
private void relationship_SourceUpdated(object sender, DataTransferEventArgs e)
{
//To DO: whatever update you wanna make
}
Your wording is a litte inaccurate: it is not the DependencyObjects that are the source or target of a binding, but the properties of the DependencyObjects. A plain property can only be the source in a binding, but a DependencyProperty can act both as a source and as a target. For example in
<TextBox Text="{Binding Path=Name}" Name="txtName" />
<Label Content="{Binding ElementName=txtName, Path=Text}" />
the Text property of the TextBox is the target of the binding to some Name property in the DataContext, and at the same time it is the source of the binding to the Content property of the Label. The parameter of a method call is not a property, therefore it cannot be source or target in a binding. In your case the simplest solution is probably to handle the TextBlock.TextChanged event and to call your method from there. Using a ValueConverter as suggested by Martin is also an option.
Edit: Here is a working example that demonstrates the approach using the TextChanged event. It writes the contents of the TextBox to the Console everytime you change something. To bind to the result of your method you could just let the event handler write its result to a property and then bind to that property.
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Orientation="Vertical">
<TextBox Name="textBox1" TextChanged="textBox1_TextChanged" />
</StackPanel>
</Window>
MainWindow.xaml.cs:
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
Console.WriteLine(this.textBox1.Text);
}
}
}

WPF: What distinguishes a Dependency Property from a regular CLR Property?

In WPF, what, really, does it mean to be a "dependency property"?
I read Microsoft's Dependency Properties Overview, but it's not really sinking in for me. In part that article says:
Styles and templates are two of the chief motivating scenarios for using dependency properties. Styles are particularly useful for setting properties that define application user interface (UI). Styles are typically defined as resources in XAML. Styles interact with the property system because they typically contain "setters" for particular properties, as well as "triggers" that change a property value based on the real-time value for another property.
And then the example code is this:
<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>
....
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>
But I'm not getting what is special about this. Does it just imply, that when I set Style on the button to the given style, that I am actually setting Background implicitly? Is that the crux of it?
Here's the explanation for how dependency properties work that I always wished someone had written for me. It's incomplete and quite possibly wrong, but it will help you develop enough of an understanding of them that you can will be able to grasp the documentation that you read.
Dependency properties are property-like values that are get and set via methods of the DependencyObject class. They can (and generally do) look very much like CLR properties, but they're not. And this gets to the first confusing thing about them. A dependency property is really made up of a couple of components.
Here's an example:
Document is a property of the RichTextBox object. It's a real CLR property. That is to say, it's got a name, a type, a getter, and a setter, just like any other CLR property. But unlike "normal" properties, the RichTextBox property doesn't merely get and set a private value inside the instance. Internally, it's implemented like this:
public FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
When you set Document, the value you passed in gets passed to SetValue, along with DocumentProperty. And what is that? And how does GetValue get its value? And ...why?
First the what. There's a static property defined on the RichTextBox named DocumentProperty. When this property is declared, it's done like this:
public static DependencyProperty DocumentProperty = DependencyProperty.Register(
"Document",
typeof(FlowDocument),
typeof(RichTextBox));
The Register method, in this case, tells the dependency property system that RichTextBox - the type, not the instance - now has a dependency property named Document of type FlowDocument. This method stores this information...somewhere. Where, exactly, is an implementation detail that's hidden from us.
When the setter for the Document property calls SetValue, the SetValue method looks at the DocumentProperty argument, verifies that it's really a property that belongs to RichTextBox and that value is the right type, and then stores its new value...somewhere. The documentation for DependencyObject is coy on this implementation detail, because you don't really need to know it. In my mental model of how this stuff works, I assume there's a property of type Dictionary<DependencyProperty, object> that's private to the DependencyObject, so derived classes (like RichTextBox) can't see it but GetValue and SetValue can update it. But who knows, maybe it's written on parchment by monks.
At any rate, this value is now what's called a "local value," which is to say it's a value that's local to this specific RichTextBox, just like an ordinary property.
The point of all this is:
CLR code doesn't need to know that a property is a dependency property. It looks exactly like any other property. You can call GetValue and SetValue to get and set it, but unless you're doing something with the dependency property system, you probably don't need to.
Unlike a normal property, something other than the object that it belongs to can be involved in getting and setting it. (You could do this with reflection, conceivably, but reflection is slow. Looking things up in dictionaries is fast.)
This something - which is the dependency property system - essentially sits between an object and its dependency properties. And it can do all kinds of things.
What kinds of things? Well, let's look at some use cases.
Binding. When you bind to a property, it has to be a dependency property. This is because the Binding object doesn't actually set properties on the target, it calls SetValue on the target object.
Styles. When you set an object's dependency property to a new value, SetValue tells the style system that you've done so. That's how triggers work: they don't find out that a property's value has changed through magic, the dependency property system tells them.
Dynamic resources. If you write XAML like Background={DynamicResource MyBackground}, you can change the value of the MyBackground resource, and the background of the object referencing it gets updated. This isn't magic either; the dynamic resource calls SetValue.
Animations. Animations work by manipulating property values. Those have to be dependency properties, because the animation is calling SetValue to get at them.
Change notification. When you register a dependency property, you can also specify a function that SetValue will call when it sets the property's value.
Value inheritance. When you register a dependency property, you can specify that it participate in property value inheritance. When you call GetValue to get the value of an object's dependency property, GetValue looks to see if there's a local value. If there's not, it traverses up the chain of parent objects looking at their local values for that property.
This is how it is that you can set the FontFamily on a Window and magically (I'm using that word a lot) every control in the window uses the new font. Also, it's how it is that you can have hundreds of controls in a window without each of them having a FontFamily member variable to track their font (since they don't have local values) but you can still set the FontFamily on any one control (because of the seekrit hidden dictionary of values that every DependencyObject has).
In WPF, what, really, does it mean to be a "dependency property"?
In order to be a dependency property, the property must actually be defined as a DependencyProperty, statically, on the class. The dependency property system is very different than a standard CLR property.
Dependency properties are handled very differently, though. A type defines a dependency property statically, and provides a default value. The runtime actually doesn't generate a value for an instance until it's needed. This provides one benefit - the property doesn't exist until requested for a type, so you can have a large number of properties without overhead.
This is what makes the styling work property, but is also important to allow attached properties, property "inheritance" through the visual tree, and many other things WPF relies on.
For example, take the DataContext dependency property. Typically, you set the DataContext dependency property for a Window or a UserControl. All of the controls within that Window, by default, "inherit" their parent's DataContext proeprty automatically, which allows you to specify data bindings for controls. With a standard CLR property, you'd need to define that DataContext for every control in the window, just to get binding to work properly.
It may be helpful to understand what problem the dependency property is trying to solve.
If we put the Binding, Animation and the Change Event model to one side as they've been discussed in other answers, the benefit is memory usage and thus scalability to host many thousand WPF objects in a window.
If a window contains 1000 Label objects with each Label object having the usual Foreground, Background, FontFamily, FontSize, FontWeight, etc., then traditionally this would consume memory because each property would have a private backing field to store the value.
Most applications will change only a few properties, the majority of which will be left at their default values. Basically very wasteful and redundant information (each object just holding the same default values in memory)
This is where dependency properties are different.
// Lets register the Dependency Property with a default value of 20.5
public static readonly DependencyProperty ColumnWidthProperty =
DependencyProperty.Register("ColumnWidth", typeof(double), typeof(MyWPFControl), new UIPropertyMetadata(20.5, ColWitdhPropChanged));
public double ColumnWidth
{
get { return (double)GetValue(ColumnWidthProperty); }
set { SetValue(ColumnWidthProperty, value); }
}
There is no private backing field. When the dependency property is registered a default value can be specified. So in most cases the returned value from GetValue is the default value that has only been stored the once to cover all instances of the Label object across all windows of your application.
When a dependency property is set using the SetValue it stores the non-default value in a collection identified by the object instance, to be returned in all subsequent GetValue calls.
This storage method will therefore only consume memory for the properties of the WPF objects that have changed from the default value. i.e. only the differences from the default value.
A simple/fundamental difference - Change Notification: Changes to Dependency Properties are reflected/refreshed in UI on changes whereas CLR properties don't.
<Window x:Class="SampleWPF.MainWindow"
x:Name="MainForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SampleWPF"
Title="About WPF Unleashed" SizeToContent="WidthAndHeight"
Background="OrangeRed"
>
<StackPanel DataContext="{Binding ElementName=MainForm}">
<!-- Bind to Dependency Property -->
<Label Name="txtCount1" FontWeight="Bold" FontSize="20" Content="{Binding ElementName=MainForm, Path=Count1, Mode=OneWay}" />
<!-- Bind to CLR Property -->
<Label Name="txtCount2" Content="{Binding ElementName=MainForm, Path=Count2, Mode=OneWay}"></Label>
<!-- Bind to Dependency Property (Using DataContext declared in StackPanel) -->
<Label Name="txtCount3" FontWeight="Bold" FontSize="20" Content="{Binding Count1}" />
<!-- Child Control binding to Dependency Property (Which propagates down element tree) -->
<local:UserControl1 />
<!-- Child Control binding to CLR Property (Won't work as CLR properties don't propagate down element tree) -->
<local:UserControl2 />
<TextBox Text="{Binding ElementName=txtCount1, Path=Content}" ></TextBox>
<TextBox Text="{Binding ElementName=txtCount2, Path=Content}" ></TextBox>
<Button Name="btnButton1" Click="btnButton1_Click_1">Increment1</Button>
<Button Name="btnButton2" Click="btnButton1_Click_2">Increment2</Button>
</StackPanel>
</Window>
<UserControl x:Class="SampleWPF.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label Content="{Binding Count1}" ></Label>
<!--
<Label Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Count1}"></Label>
-->
</StackPanel>
</UserControl>
<UserControl x:Class="SampleWPF.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel>
<Label Content="{Binding Count2}" ></Label>
<!--
<Label Content="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=Count2}"></Label>
-->
</StackPanel>
</UserControl>
And the code behind here (To declare the CLR and Dependency property):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SampleWPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static readonly DependencyProperty Count1Property;
private int _Count2 = 2;
public int Count2
{
get { return _Count2; }
set { _Count2 = value; }
}
public MainWindow()
{
return;
}
static MainWindow()
{
// Register the property
MainWindow.Count1Property =
DependencyProperty.Register("Count1",
typeof(int), typeof(MainWindow),
new FrameworkPropertyMetadata(1,
new PropertyChangedCallback(OnCount1Changed)));
}
// A .NET property wrapper (optional)
public int Count1
{
get { return (int)GetValue(MainWindow.Count1Property); }
set { SetValue(MainWindow.Count1Property, value); }
}
// A property changed callback (optional)
private static void OnCount1Changed(
DependencyObject o, DependencyPropertyChangedEventArgs e) {
}
private void btnButton1_Click_1(object sender, RoutedEventArgs e)
{
Count1++;
}
private void btnButton1_Click_2(object sender, RoutedEventArgs e)
{
Count2++;
}
}
}
Another feature provided by Dependency Properties is value inheritance - value set in top level elements propagates down the element tree - In following example taken from http://en.csharp-online.net, FontSize and FontStyle declared on "Window" tag is applied to all child elements underneath:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
Title="About WPF Unleashed" SizeToContent="WidthAndHeight"
FontSize="30" FontStyle="Italic"
Background="OrangeRed">
<StackPanel>
<Label FontWeight="Bold" FontSize="20" Foreground="White">
WPF Unleashed (Version 3.0)
</Label>
<Label>© 2006 SAMS Publishing</Label>
<Label>Installed Chapters:</Label>
<ListBox>
<ListBoxItem>Chapter 1</ListBoxItem>
<ListBoxItem>Chapter 2</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button MinWidth="75" Margin="10">Help</Button>
<Button MinWidth="75" Margin="10">OK</Button>
</StackPanel>
<StatusBar>You have successfully registered this product.</StatusBar>
</StackPanel>
</Window>
References:
http://www.codeproject.com/Articles/29054/WPF-Data-Binding-Part-1
http://en.csharp-online.net/WPF_Concepts%E2%80%94Property_Value_Inheritance

Resources