When to use FindAncestor? - c#

In the image below, why is FindAncestor needed and why is AncestorType not UserControl?
If the UserControl was inside a StackPanel, would AncestorType be StackPanel?
In other words, what does the parent control have to do with binding to the viewmodel.Message? Why is all the other xaml needed in the Binding?

It wouldn't need to specify AncestorType=UserControl, since that's the default context. If you omit the "RelativeSource" parameter, it will bind to the local DataContext.
In this case, the UserControl and the Window it is contained in must have different DataContexts. Since a UserControl generally doesn't know the name of its parent at design time, you can at the least usually assume it's only going to be in a single Window and create a binding to the Window's DataContext using RelativeSource as shown.
This can be common because in an application, the Window might have a DataContext for information about the application as a whole, but the current UserControl might be focused on a particular piece of data (such as an Employee). In this case all the default bindings point to the Employee, but the UserControl might want to bind to something in the parent DataContext too.

Why is FindAncestor needed?
Here FindAncestor is used to access to the Window object to get an access to the DataContext of Window object.
Why is AncestorType not UserControl?
Because the DataContext of the UserControl object may be not the same as the DataContext of Window object.
Normally it's the same but you can redefine it.
If the UserControl was inside a StackPanel, would AncestorType be StackPanel?
No if the StackPanel is itself in your Window.
Don't forget that you target the Type of the graphical object that contain the DataContext you want.

In this case, the developer just knew that the object that had the datacontext they were looking for was a Window. If, for example, a data context was set on a stackpanel and you wanted something from that datacontext, then you would use the AncestorType = Window. Since there are two datacontexts, and the user wanted to bind something to the outside one, FindAncestor was used.

Related

What is different between {binding} and inherit in wpf datacontext?

I have some problems about datacontext binding.
My app has virtualization listbox.
Sometimes Button is not fired dataContextChanged.
So I found this.
<Grid DataContext={Binding ~~>
<Button DataContext={Binding}/>
</Grid>
<Grid DataContext={Binding ~~>
<Button/>
</Grid>
My Code is first one. but It's not fired DataContextChanged sometimes, So I changed code to second one.
snoop said first one is from inherit, and second one is from parentTemplate.
What is different first one and second one?
TL;DR:
SomeProperty={Binding} will bind the SomeProperty to the ENTIRE DataContext object from the parent. SomeProperty does not have to be the DataContext from the child. In this special case I don't think there is any difference, since the DataContext is inherited anyways. You are simply explicitly stating, what is already the default. Discussed here
More Info:
Here is an explanation from the official documentation for
<Button DataContext={Binding}/>
As long as the binding already has a data context (for example, the
inherited data context coming from a parent element), and whatever
item or collection being returned by that context is appropriate for
binding without requiring further path modification, a binding
declaration can have no clauses at all: {Binding}. This is often the
way a binding is specified for data styling, where the binding acts
upon a collection. For more information, see Using Entire Objects as a Binding Source.
and from here
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="true"/>
The above example uses the empty binding syntax: {Binding}. In this
case, the ListBox inherits the DataContext from a parent DockPanel
element (not shown in this example). When the path is not specified,
the default is to bind to the entire object. In other words, in this
example, the path has been left out because we are binding the
ItemsSource property to the entire object. (See the Binding to
collections section for an in-depth discussion.)
In general, the DataContext is inherited from parent elements. So in your 2nd example the button gets the DataContext from the Grid. Example
"ItemsControl" are special: Example
I don't know what ~~ is, is this meant to be a placeholder?
Some more information on Bindings and Markup Extensions:
Link1
Link2
Link3

Databinding a TabItem to a parent Window

I'm trying to clean up the way I use DataContexts with my UserControls, and currently am running into a problem where I need to databind a UserControl inside of a TabItem to the parent Window's DataContext.
Here is a sketch of what my Window looks like:
As you can see, this Window owns a TabControl that contains TabItems that are dynamically added via the "Tabs" ItemSource. Databinding at this point is working because "Tabs" gets populated with Tab 1.
Tab 1 contains a UserControl that needs access to multiple string properties in the DiagnosticsViewModel, but when I run my application, the Output window indicates that all bindings have failed. For example:
System.Windows.Data Error: 4 : Cannot find source for binding with
reference 'RelativeSource FindAncestor,
AncestorType='System.Windows.Window', AncestorLevel='1''.
BindingExpression:Path=Property1; DataItem=null; target element is
'Tab1UserControl' (Name=''); target property is 'UCName' (type
'String')
The XAML for the UserControl in Tab 1 looks something like this:
<Grid>
<uc:Tab1UserControl UCName="{Binding Property1, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Grid>
where UCName is a String DependencyProperty.
If I am telling WPF that I want to look up the tree and bind to the DataContext for the nearest Window, and my Window's DataContext is set to DiagnosticsViewModel, why isn't it using it for my UserControl's DataContext? I have not set DataContext = this in my UserControl, as I have done improperly many times in the past, with the expectation that my UserControl will be able to inherit the DataContext from its parent.
I would like to see if Snoop can shed light on my problem, but this GUI is being displayed from a MFC application, and Snoop doesn't seem to be able to attach to my WPF dialog.
If you change the source of a binding using RelativeSource, ElementName or the like, the binding will be directly to the element you specify - not its data context. Which means that in your code the user control will try to bind to a property called Property1 on the Diagnostics class itself.
Try using
<Grid>
<uc:Tab1UserControl UCName="{Binding Path=DataContext.Property1, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Grid>
in the code for your user control and see if that fixes the problem.
(As an aside, the idea of the user control itself knowing that the window it belongs to will have a datacontext with a given property seems like a code smell to me, especially since the point of user controls is that they're reusable - it'd feel better to have a dependency property on the user control and then bind that to the appropriate property when you use it. This may just be due to me lacking context, though.)

Binding doesn't work on DependencyObject created in XAML

I'm trying to pass multiple CommandParameters in XAML with the use of a custom class.
I have created a class called ValueCommandArgs that inherits from DependencyObject and has two DepencyProperties (lets call them Value1 and Value2 for this example).
The button which is supposed to call a command and pass this object looks like this:
<Button Command="{Binding ChangeValueCommand}" Content="Execute Command">
<Button.CommandParameter>
<args:ValueCommandArgs Value1="{Binding TestValue1}" Value2="{Binding TestValue2}" />
</Button.CommandParameter>
</Button>
I do get an ValueCommandArgs-Object in my command as paramter, however the properties Value1 and Value2 are always null/empty.
I know this can be solved with a MultiBinding and Converter, but I think the way I'm trying it would be a cleaner approach.
Why doesn't this work?
A Binding needs a source object to be able to provide a value. When the Binding source is not specified (with Source or ElementName etc.) eg: Value1="{Binding TestValue1}" the DataContext of the element is used.
The args:ValueCommandArgs object does not inherit the DataContext from the Button element because property value inheritance is particularly about how property values can inherit from one element to another on the basis of the parent-child relationships within a tree of elements.
The button object does not include the value of the CommandParameter property in its logical nor the visual tree.
In many cases the need for such a CommandParameter with multiple bound values can be avoided by binding the values directly to the ViewModel.
When it can't be avoided you can use a different type of binding markup extension like: https://github.com/JohanLarsson/Gu.Reactive#ninjabinding that will use the root FrameworkElement as the source of the binding.
Another approach would be a binding proxy technique shown in this blog post: How to bind to data when the DataContext is not inherited

DataContext changes before I can pass parameters

I have a control with a dependency property which I want to pass which is a property in a class, and I also want to use an ObservableCollection which part of that class as the datacontext for that control.
<mycontrols:News
feedStatus="{Binding newsData.newsStore.feedStatus}"
DataContext="{Binding newsData.newsStore.news}"
/>
The problem here is that the DataContext is used when it evaluates {Binding newsData.newsStore.feedStatus} how can I get it to pass feedStatus first and then set the DataContext.
I would use just the single datacontext if silverlight had the ability to back track up the datacontexts parent, but I don't think this is the case.
Could I set datacontext as a nested parameter?
Set the DataContext to DataContext="{Binding newsData.newsStore} and then bind the feedStatus and news properties inside your UserControl.
Alternatively use multiple dependency properties, instead of the DataContext.
Also, please use .NET naming conventions (PascalCase!). Java style casing makes my eyes cringe.

Multiple DataContext in a View vs MVVM? Is that right?

I have the following problem: I'm building a chat WPF application on which I want the user to be connected with different accounts to GTalk. I've made a ViewModel that permits handling the communication but I don't know which is the best way to handle DataContext. I think that I need different DataContexts for every connection instance but I don't know if this is the right way and don't know how to define multiple DataContexts in a View.
A DataContext provides the default binding source for an element in the view. It is inherited from parent to child within the visual tree. You can change the DataContext for any element by binding it to some property of its parent DataContext. This is a common way of creating 'islands' that bind to a child view model.
For example, if you have a User view model that has an Address Property, you can render this in an AddressUserControl as follows:
<StackPanel>
... elements bound to properties of User ...
<AddressUserControl DataContext="{Binding Address}"/>
</StackPanel>
If you have a variable number of accounts, you can use the ItemsControl.
The rough idea behind this: You can bind the ItemsControl to a list of "Sub-ViewModels" in your main ViewModel and define a DataTemplate (= a View) for each of them. The DataContext of each DataTemplate is automatically assigned to a corresponding item in your ViewModel's list.

Categories