Styles and DataTemplates: FindAncestor-like search including Self - wpf

I have a style containing binds expression of the form
{Binding Path, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyType}}}
However, sometimes the DataContext in which this style operates is actually of type MyType. In this case, FindAncestor doesn't do what I want: it starts its search from the parent.
Is there any {Binding ...} incantation that checks the type of the current datacontext before continuing up the element hierarchy? I have other solutions specific to my project, but FindAncestor is so close...

RelativeSource bindings do not look for DataContexts, they search the visual tree for UI elements. The AncestorType should be a control.
To perform a RelativeSource binding on the same control you can use RelativeSource Self

Related

Bind the current instance of a control to an attached property

I'm looking to see if you can bind the current instance of a usercontrol or window to an attached property defined in its xaml, eg:
<Window MyAttachedProp.Value="{Binding Self}"/>
You want the MyAttachedProp.Value to have the Window object reference?
You can use any of these methods:
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}
give your Window an x:Name="XXXXX"...and then use {Binding ElementName=XXXXX} to find it.
{Binding RelativeSource={RelativeSource Self}}
{Binding RelativeSource={x:Static RelativeSource.Self}}
With example 4, it avoids the creation of a new RelativeSource object (with the Mode set to Self)...instead it points to the Static one already created in the RelativeSource class....(this is a VERY minor and premature optimization).
Most people use example 3 as it's less to type and clearer to read.
http://www.c-sharpcorner.com/uploadfile/yougerthen/relativesources-in-wpf/
{Binding RelativeSource={RelativeSource Self}}

Setting RelativeSource correctly

I have a combo box on a xaml form (MainWindow).
I set the Items source to an ObservableCollection in the code behind. To populate the Combo box I used Relative Source (it sits inside an ItemsControl), which worked great (without it, if did not populate):
ItemsSource="{Binding SelectableItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
I have now factored out the ObservableCollection into a seperate View Model Class, named 'MainWindowViewModel', the combo box does not populate.
I have set the DataContext of the MainWindow to my ViewModel and have checked that it populates other controls as expected, which it does.
How should I construct the RelativeSource so the combo box populates?
Thanks
Joe
I needed to add the Path at the end, thus:
ItemsSource="{Binding SelectableItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.SelectableItems}"
You do not want to use a RelativeSource any longer. If you don't specify a RelativeSource (or Source, or ElementName), then the binding will resolve against the current DataContext. Since the DataContext is inherited, your ItemsControl obtains its DataContext from the parent Window. Thus, this binding will resolve against your view model.
ItemsSource="{Binding SelectableItems}"

WPF binding Ancestor

I have problems with bindings. I want to use a UserControl (Intellibox from codeplex) but I only get error messages in the output window.
Basically I have
window grid ... stuff ... usercontrol (self written) ... stuff ... usercontrol (IntelliBox)
In the Output window I get following stuff:
System.Windows.Data Error: 4 : Cannot find source for binding with reference
'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl',
AncestorLevel='1''. BindingExpression:Path=ShowResults; DataItem=null;
target element is 'Popup' (Name='IntelliboxPopup1');
target property is 'IsOpen' (type 'Boolean')
The binding in the IntelliBox control is defined as follows:
{Binding Path=ShowResults, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}}}
I guess there is a problem, cause the nesting withing usercontrols - how to I get this error fixed?
Thanks!
I have two questions. First, is this a Binding that you wrote for your use, or is it something that came out-of-the-box inside the UserControl you're using? Second, are you trying to Bind to the Intellibox, or to your "self written" UserControl?
Assuming it's a Binding you wrote for your use (I don't have knowledge of Intellibox so I wouldn't know where to start for fixing it), there are a couple of solutions you might try.
First, when binding to an ancestor, try using the exact ancestor type. For instance, if you're binding to the Intellibox, use AncestorType={x:Type Intellibox}. Otherwise use AncestorType={x:Type <YourType>}. Your Binding will be less ambiguous this way.
Second, and perhaps the best answer in this case, is to bind to the control you want by name by setting x:Name="BindSource (or whatever)" on the target and using the Binding syntax:
{Binding Path=ShowResults,
ElementName=BindSource}
--
HTH,
Dusty

WPF won't let me put a binding on the path of a binding -- is there another way?

I have a DataTemplate that I'm using as the CellTemplate for a GridViewColumn.
I want to write something like this for the DataTemplate:
<DataTemplate
x:Key="_myTemplate">
<TextBlock
Text="{Binding Path={Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumn}}, Path=Header}}" />
</DataTemplate>
My GridView is bound to a DataTable, and I want to bind to the column of the DataTable whose name is equal to the Header of the GridViewColumn the DataTemplate is attached to. [I hope that made sense!]
Unfortunately, this doesn't work. I get a XamlParseException: "A 'Binding' cannot be set on the 'Path' property of type 'Binding'. A 'Binding' can only be set on a DependencyProperty of a DependenceyObject."
How can I set this up?
Edit (elevating comment by DanM to the question)
I basically need a DataTemplate whose binding is determined by the DataContext and which column the DataTemplate is attached to. Is there an alternative?
You cannot assign a Binding to just any property. The property must either of the type Binding or be implemented as a Dependency Property on the object.
The Path property of the Binding class is of type PropertyPath and Binding does not implement the Path property as a dependency property. Hence you cannot dynamically bind the Path in the way you are attempting to.
Edit
You basically want to embed metadata in your bound data which drives the configuration of the DataTemplate. This can't be done in XAML alone. You would need at least some support from code.
It would seem to me that the best approach would be to use a ViewModel. That makes the binding in the XAML straight-forward and pushes this "what to bind with what" decision down into the code of the ViewModel.
Don't you just want this?
{Binding Path=Header, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumn}}}

How can I access the root DataContext in a DataTemplate in WPF?

I have a grid of items which is populated using databinding.
In the grid I have a DataTemplate for certain cells. I need to access the DataContext of the root element (the one which is hosting the grid) so that I can access additional bindings to support my datatemplate.
So you have:
Window
Window.DataContext = TheDataSourceWithItemsAndSupports
DataGrid.ItemsSource = {Binding Items}
DataTemplate
ListBox.ItemsSource = {Binding Supports}
I want the {Binding Supports} on TheDataSourceWithItemsAndSupports, but I don't see how to do that. I tried specifying {Binding} but that always returns null. I also tried using RelativeSource FindAncestor, but that yields null too.
Any clues?
Maybe try
Window Name="TheWindow"
...
ListBox.ItemsSource = {Binding DataContext.Supports, ElementName=TheWindow}
Another little trick to bind to your root context
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}, AncestorLevel=1}, Path=DataContext.Supports}"/>
My solution was to expose whole DataContext class by implementing This field
get
{
return this;
}
and then binding to it.
It should work the way you describe. Only thing I see your DataTemplate is not ItemTemplate. You should also look at the output window to see where bindings fail.

Resources