Bind the current instance of a control to an attached property - wpf

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}}

Related

Setting attached property value as target of binding

I have been searching for an answer to this question, but always find the reversed of what I am looking for.
like this Question: WPF Attached Property Data Binding with following answer:
IsChecked="{Binding Path=(local:Attached.Test), Mode=TwoWay, RelativeSource={RelativeSource Self}}"
But I would like to perform this kind of Binding in code-behind:
<Grid local:MyGridHelper.GridWidth = {Binding Elementname=XY, Path=ActualWidth} />
In code, setting a value for the attached Property is usually easy: MyGridHelper.SetGridWidth(mygrid, value). But how do I get a Binding into this instaed of just a value?

programmatic WPF binding fails

I have a UserControl with a grid in it and I am generating a column of rectangles in my code behind. The UserControl has some dependency properties that I need to bind the rectangles to. I originally did this in the XAML with the following markup:
<Rectangle Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=MeterBarColor}"
Grid.Row="0"
Margin="2,2,2,0" />
This binding worked, however I need to build the column of rectangles dynamically so I tried to create a binding in my code behind like this:
Dim oBinding As New Binding("{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=MeterBarColor}")
oRectangle.SetBinding(Rectangle.FillProperty, oBinding)
When I run the application I get errors for each binding attempt saying the property was not found.
Hopefully someone can help me resolve this,
Sid
The argument of the Binding constructor you use is a path, not a {Binding ...} expression. Thus, you need to call New Binding("MeterBarColor") and then set the RelativeSource property.
Or you could use the parameterless constructor and object initializers:
Dim oBinding As New Binding() {
.RelativeSource = New RelativeSource(RelativeSourceMode.FindAncestor,
GetType(UserControl), 1),
.Path = "MeterBarColor"
}
oRectangle.SetBinding(Rectangle.FillProperty, oBinding)

Styles and DataTemplates: FindAncestor-like search including Self

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

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}"

How do I databind to the control's property rather than the datacontext?

I have a sub control embedded inside my main control, it allows the user to edit an address. Because this is reused all over the place (sometimes in multiple places on one control) I bind it like so
<Controls:EditAddressUserControl DataContext="{Binding Path=HomeAddress}"/>
<Controls:EditAddressUserControl DataContext="{Binding Path=WorkAddress}"/>
But the EditAddressUserControl needs access to the main control's list of CountrySummary objects so it can choose which country the address belongs to.
I have added a Countries DependencyProperty to EditAddressUserControl and added
Countries="{Binding Countries}"
So far all is going well, the EditAddressUserControl.Countries property has the correct countries in it. However, how do I databind my Combobox.ItemsSource to that in XAML?
I still want everything on my EditAddressUserControl to bind to its DataContext, but the ComboBoxCountries.ItemsSource needs to bind to "this.Countries".
How do I do that?
I've tried this
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:EditAddressUserControl}}, Path=Countries}" />
I saw no binding errors in the output box, but I also saw no items in the combobox.
You can accomplish this by using a RelativeSource for the binding source, instead of the DataContext.
This would most likely look something like:
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Controls:EditAddressUserControl}}, Path=Countries}" />
The way to do it was to stop using DataContext completely. Instead I added a DependencyProperty to my control
public static DependencyProperty AddressProperty = DependencyProperty.Register("Address", typeof(EditPostalAddressDto), typeof(EditPostalAddressControl));
Then in the parent control instead of setting DataContext="..." I set Address="..." - The XAML for the control is then changed to include an ElementName on the binding
<UserControl ..... x:Name="MainControl">
<TextBox Text="{Binding ElementName=MainControl,Path=Address.Region}"/>
Now I can specifically bind to the Address property, but also bind to properties on the main data context.

Resources