The DataContext
property in WPF is extremely handy, because it is automatically inherited by all children of the element where you assign it; therefore you don’t need to set it again on each element you want to bind. However, in some cases theDataContext
is not accessible: it happens for elements that are not part of the visual or logical tree. It can be very difficult then to bind a property on those elements…
Let’s illustrate with a simple example: we want to display a list of products in aDataGrid
. In the grid, we want to be able to show or hide the Price column, based on the value of aShowPrice
property exposed by the ViewModel. The
obvious approach is to bind the Visibility
of the column to the
ShowPrice
property:
1
2
3
|
< DataGridTextColumn Header = "Price" Binding = "{Binding
Price}" IsReadOnly = "False"
Visibility="{Binding ShowPrice,
Converter={StaticResource visibilityConverter}}"/>
|
Unfortunately, changing the value of ShowPrice
has no effect, and the column is always visible… why? If we look at the Output window in Visual Studio, we notice the following line:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=ShowPrice; DataItem=null; target element is ‘DataGridTextColumn’ (HashCode=32685253); target property is ‘Visibility’
(type ‘Visibility’)
The message is rather cryptic, but the meaning is actually quite simple:
WPF doesn’t know which FrameworkElement
to use to get the DataContext
, because the column doesn’t belong to the visual or logical tree of theDataGrid
.
We can try to tweak the binding to get the desired result, for instance by setting the RelativeSource to theDataGrid
itself:
1
2
3
4
|
< DataGridTextColumn Header = "Price" Binding = "{Binding
Price}" IsReadOnly = "False"
Visibility="{Binding DataContext.ShowPrice,
Converter={StaticResource visibilityConverter},
RelativeSource={RelativeSource FindAncestor,
AncestorType = DataGrid }}"/>
|
Or we can add a CheckBox
bound to ShowPrice
, and try to bind the column visibility to theIsChecked
property by specifying the element name:
1
2
3
4
|
< DataGridTextColumn Header = "Price" Binding = "{Binding
Price}" IsReadOnly = "False"
Visibility="{Binding IsChecked,
Converter={StaticResource visibilityConverter},
ElementName = chkShowPrice }"/>
|
But none of these workarounds seems to work, we always get the same result…
At this point, it seems that the only viable approach would be to change the column visibility in code-behind, which we usually prefer to avoid when using the MVVM pattern… But I’m not going to give up so soon, at least not while there are other options
to consider
The solution to our problem is actually quite simple, and takes advantage of theFreezable
class. The primary purpose of this class is to define objects that have a modifiable and a read-only state, but the interesting feature in our case is that
Freezable
objects can inherit the
DataContext
even when they’re not in the visual or logical tree. I don’t know the exact mechanism that enables this behavior, but we’re going to take advantage of it to make our binding work…
The idea is to create a class (I called it BindingProxy
for reasons that should become obvious very soon) that inheritsFreezable
and declares a
Data
dependency property:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public
class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override
Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object
Data
{
get { return ( object )GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static
readonly DependencyProperty DataProperty =
DependencyProperty.Register( "Data" , typeof ( object ), typeof (BindingProxy), new
UIPropertyMetadata( null ));
}
|
We can then declare an instance of this class in the resources of the DataGrid
, and
bind the Data
property to the current
DataContext
:
1
2
3
|
< DataGrid.Resources >
< local:BindingProxy x:Key = "proxy" Data = "{Binding}" />
</ DataGrid.Resources >
|
The last step is to specify this BindingProxy
object (easily accessible withStaticResource
) as the
Source
for the binding:
1
2
3
4
|
< DataGridTextColumn Header = "Price" Binding = "{Binding
Price}" IsReadOnly = "False"
Visibility="{Binding Data.ShowPrice,
Converter={StaticResource visibilityConverter},
Source={StaticResource proxy}}"/>
|
Note that the binding path has been prefixed with “Data”, since the path is now relative to theBindingProxy
object.
The binding now works correctly, and the column is properly shown or hidden based on theShowPrice
property.
From: http://www.thomaslevesque.com/tag/datacontext/
分享到:
相关推荐
This is the final part of a three-part ...The purpose of this final article is to complete the introduction to LINQ to SQL by showing how to make your LINQ to SQL classes work with WPF data bindings.
* How to bind visual elements to data sources. * How to perform graphics transformations to produce eye–catching displays, and how to use animation to produce pages that are alive with action. * ...
Having helped alot of people on the MSDN Forum in the WPF section, I tend to see alot of people who fail to exploit the benefits of DataBinding in WPF, and not enough people are aware of the benefits ...
After giving you a firm foundation, it goes on to explore the more advance aspects of WPF and how they relate to the others elements of the .NET 4.0 platform and associated technologies such as ...
However, the knowledge of how to do this is missing from a large part of the development community―even amongst those who work with WPF and Silverlight on a daily basis. Too often there is a reliance...
By the end of the book, you should have a working knowledge of WPF and know how to architect a WPF application using the tools provided by Microsoft, such as SQL Server 2008 R2 Express Edition, the ...
a component to access the data, a component to include a logical function, a component to render the user interface, and so on. In this book, I will show you how to create and implement WPF, using ...
在窗口中实现绘图功能,并能够实现动态绘制,而且图表可交互
<br>This article is about how to create a peer-to-peer chat application using Windows Communication Foundation (WCF) and also how to make it look nice using Windows Presentation Foundation (WPF)....
If you want to learn how to build killer user interfaces for Windows and the web, then this book is for you. It arms you with the tools and code you'll need to effectively utilize the Windows ...
InteractiveDataDisplay x轴显示时间
Use the new model for using DataContext to validate a WPF window Employ the Telerik interface classes to load controls Understand object-oriented concepts such as inheritance and interfaces Secure an ...
I say Style, as it may not be 100% in line with what the Win8 Metro tile interface does, or how it functions, but to be honest, it fitted my needs well enough and I figured it may be OK for others....
The authors begin by explaining how to “think in WPF,” and then introduce powerful new techniques for everything from handling 3D layouts to creating game-like physics effects. Along the way, they ...
Learn how to use the MVVM software architectural pattern and see the benefits of using it with Windows Presentation Fountain (WPF) Learn which controls to use in particular situations and the various...
touch on a bit of everything WPF has to offer, so you know not only what’s provided by the platform, but also how to utilize it. Of course, because it’s a large platform, we won’t be able to cover ...
The CSWPFThreading sample project illustrates two WPF threading models. The first one divides a long-running ...* also want to keep the GUI responsive when doing expensive operations in * the UI thread.
闲暇时,写了个WpfDBOperateImage程序,此程序基于WPF 框架并通过创建LINQ to SQL 类进行上传、下载、删除图片,帮助初学者的你快速入门。
”, “How do I start using WPF?” and “What does WPF have to offer me?” are answered early in the first chapter, followed swiftly by a detailed look at the subsystems and graphical features offered ...