{Binding DataContext.foo} vs {Binding foo} Difference - wpf

I thought {Binding DataContext.foo} and {Binding foo} were identical until I came across an issue binding a selection changed event from a ComboBox to a command in my ViewModel.
I was doing it like so...
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding DataContext.TestCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Page}}}" />
</i:EventTrigger>
Using DataContext.TestCommand works while just specifying TestCommand appears to fail. I've never encountered a difference between the two can anyone explain it?

They're binding to two subtly different things:
"Binding DataContext.TestCommand" is binding to the TestCommand property of the Datacontext (presumably the context defines that property) of your Page.
"Binding TestCommand" is binding to the TestCommand property of the Page itself, which in this case probably doesn't exist, which is why it doesn't work.
There's a neat program called WPF Snoop that you can use to inspect the bindings whilst things are running (often helps me make sense of things when I'm, stuck).

Almost each element in visual tree (View) is linked to the data layer (ViewModel) per DataContext property. Of course the data layer tree is much more simpler because most controls just inherit from their parent.
By default a Binding is looking for the Path in data layer. But if you specify a RelativeSource (like RelativeSource.Self or with AncestorType) or an ElementName the Binding switches to visual layer and searches in controls for the bound property. With DataContext you can go back to data layer.

Related

WPF: why my ComboBox Selected Value Command return wrong value [duplicate]

I'm using MVVM and custom ICommand objects are provided by ViewModel layer. One ViewModel object at the same time can be attached via DataContext property to many View objects (windows, pages, etc). In ICommand.CanExecute() I want to check absence of validation errors for some controls in View (which attached to ViewModel props, significant for a particular VM command). One ViewModel can provide many commands, each of them has own set of controls for errors validation verification. So, pseudo-XAML is:
<Button.CommandParameter>
<x:Array Type="sys_win:DependencyObject">
<sys_win:DependencyObject>
<reference_to_textbox_or_other_control/>
</sys_win:DependencyObject>
<sys_win:DependencyObject>
<reference_to_textbox_or_other_control/>
</sys_win:DependencyObject>
</x:Array>
</Button.CommandParameter>
The second problem is that the particular command may be invoked by control, which itself is the part of the DataTemplate for collection item (in my case - part of ListBoxItem data template). My templated listbox item has two text boxes (binded to two props of corresponding ViewModel) and button, which invoke the ViewModel command. So, in command CanExecute() I need to check for validation errors for some window controls & two text boxes, which belongs to this listitem, not other items. The code below works fine if I want to pass ListBoxItem.IsSelected property as CommandParameter:
<Button DataContext="{Binding}"
Command="{Binding Path=SwitchCommand}"
CommandParameter="{Binding Path=IsSelected, RelativeSource={
RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}}}"/>
But how can I pass whole (DependencyObject)ListBoxItem as the CommandParameter? And how this ListBoxItem, passed via {Binding RelativeSource} can be mixed with other current window controls in the first code example?
I'm very sorry, but how can I add the references to controls in xaml?
<Button.CommandParameter>
<x:Array Type="sys_win:DependencyObject">
<sys_win:DependencyObject>
<reference_to_textbox_or_other_control/>
</sys_win:DependencyObject>
<sys_win:DependencyObject>
<reference_to_textbox_or_other_control/>
</sys_win:DependencyObject>
</x:Array>
</Button.CommandParameter>
Just use a binding with no Path :
<Button DataContext="{Binding}"
Command="{Binding Path=SwitchCommand}"
CommandParameter="{Binding RelativeSource=
{RelativeSource
Mode=FindAncestor,
AncestorType={x:Type ListBoxItem}}}"/>
I'm not sure if I'm reading your example correctly, but it seems to violate a bit of the MVVM principle. (My apologies if I read it incorrectly).
The idea behind MVVM is to decouple the viewmodel from any dependency on a XAML / View entity. You're breaking that by having the CommandParameter dependent on the usercontrol. What I would do is create state properties in the ViewModel and bind the usercontrol validations to those states, then in CanExecute you can test the values of those properties rather than trying to bind to a usercontrol.

MVVM Light WPF binding, lifecycle problems?

I am fleshing out a Window view for a LOB app. An early version with few XAML elements, but binding the title bar close button to a VM command using EventToCommand on the Closing event works fine. A later version with a few dozen elements, none yet data-bound, fails to bind that button:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=CloseCommand; DataItem=null; target element is 'EventToCommand' (HashCode=42527634); target property is 'Command' (type 'ICommand')
There are about a dozen other binding errors, referring to Border or Button element properties such as OpacityMask, HeadersVisibility, and the like - again no data binding has been set up yet. In my experience that is not unusual and not a problem?
If I comment out the new XAML elements, the close button binds and executes my CloseCommand.
I'm an MVVM Light 'journeyman', a few successful apps behind me, I think I do everything as Laurent suggests in his training and documentation.
Suggestions?
UPDATE:
The only bindings so far, both on the Window element:
DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<command:EventToCommand Command="{Binding CloseCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
All the other elements are garden variety LOB layout and widgets with no binding expressions yet.

How do you set a CommandBinding on a TreeViewItem in a DataBound TreeView?

To simplify the issue I'm having, consider this hypothetical scenario.
In the XAML for my control, I have defined a TreeView and two fixed root TreeViewItem nodes, 'AItemsNode' and 'BItemsNode'. In its ViewModel, I expose two child collections: AItems and BItems. I then bind each root node's ItemsSource property to the respective collection on the ViewModel. This works great and displays exactly what I want.
Now what I'd like to do is add a CommandBinding for ApplicationCommands.Open to the child TreeViewItem nodes of the two root nodes. Specifically I want the children under the root 'AItemsNode' to have their 'Open' CommandBinding point to 'OpenAItem_Executed' and children of the second root node to point theirs at 'OpenBItem_Executed'.
The issue I'm having is I don't know how to set the CommandBindings on the TreeViewItem objects themselves. I can't figure this out at all via XAML, and if I were to do it in the code-behind, I'd have to integrate with the ItemContainerGenerator, inspect what's being generated and add the bindings, essentially writing so much code I may as well add the 'Open' CommandBinding to the TreeView itself and inspect the SelectedObject and go from there. Not optimal as I now have a single Open_Executed handler that delegates all over the place based on data type, but it does work!
Still, I'm hoping someone can show me how to add a CommandBinding directly to a generated TreeViewItem to avoid that and segregate out the code much more cleanly.
So... how can one apply specific CommandBindings via a style (or any other way in XAML) for a TreeViewItem?
Implemented mvvm, I would suggest using interaction triggers.
Hope this helps you in the right direction.
Xaml:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<TreeView >
<TreeView.Resources>
<DataTemplate x:Key="ItemATemplate">
<TextBlock Text="{Binding MyNodeTitle}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding AChildCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
<DataTemplate x:Key="ItemBTemplate">
<TextBlock Text="{Binding MyNodeTitle}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseDown">
<i:InvokeCommandAction Command="{Binding BChildCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</DataTemplate>
</TreeView.Resources>
<TreeView.Items>
<TreeViewItem Header="AItemRootNode" ItemsSource="{Binding SomeAStuff}" ItemTemplate="{StaticResource ItemATemplate}"/>
<TreeViewItem Header="BItemRootNode" ItemsSource="{Binding SomeBStuff}" ItemTemplate="{StaticResource ItemBTemplate}"/>
</TreeView.Items>
</TreeView>
ViewModel:
private ICommand _aChildCommand;
public ICommand AChildCommand
{
get
{
if (_aChildCommand == null)
_aChildCommand = new DelegateCommand(OnAChild);
return _aChildCommand;
}
}
private void OnAChild(object obj)
{
}
I take that you havent implemented MVVM (which would have intuitively solved this issue for you by making use of RelayCommands / DelegateCommands instead of RoutedCommands)
However in your case, you need to handle the Initialized event of TreeViewItem via Style targetted to TreeViewItem. Use EventSetter in the Style. And put your code that adds the CommandBinding to the e.OriginalSource value (which is the TreeViewItem itself that is getting initialized) incoming to the TreeViewItem.Initialized event handler.
Let me know if this makses sense.
EDIT
I understand that your have x number keyborad shortcuts for x number of distinct TreeViewItems. If so x number of styles make sense to me.
But if you want to do this cluttered in a single handler at the tree view level, then may be you would have to handle an attached event at that level ... I dont think Initialised / Loaded events bubble from indv treeviewitem all the way to the parent tree view, but it would be interesting to check that and I would be happy to have proved wrong!
Plus this would potentially not work for collapsed tree view items.
So suppose you define "Ctrl + o" shortcut for a specific tree view item which is within a collapsed tree branch or is it in the opened branch however it is outside the scroll view, the routed event based mechanisms (and thus command bindings) woudnt work because they need the item to be devirtualised (in UI memory) for routing to work ...
So my solution (as I understand now) becomes a little impractical in that case.
Solution
What is visible all the time?
TreeView!
So use that to your advantage. Add all command bindings (and shortcuts) to the TreeView itself!
And within the handler (which could be common across all command bindings) devise a mechanism to identify the individual item using a ItemsSource of TreeViewItemViewModels by searching within them and then inside the relevant TreeViewItemViewModel have mechanism to Open the branch hierarchy by Binding IsOpen property (INotifyable) to the IsExpanded property of the TreeViewItem via a generic style.

XAML Binding to parent of data object

I have a grid column defined. The parent grid gets its items from an ObservableCollection of type ItemClass. ItemClass has two properties: String Foo, and bool IsEditAllowed.
This column is bound to property Foo. There's a control template for editing the cell. I'd like to bind the ItemClass.IsEditAllowed property to the IsEnabled property of the TextBox in the template.
The question is how to bind it. Can this be done? The XAML below gets me "Cannot find source for binding with reference" in the debug trace.
The grid will let me bind the ItemClass itself to the field via some "custom" event thingy, and I can then bind to any of its properties. That's fine, but it seems kludgy. But if it's the only way, it's the only way.
<dxg:GridColumn
Header="Foo Column"
FieldName="Foo">
<dxg:GridColumn.EditTemplate>
<ControlTemplate>
<TextBox Text="{Binding Value, Mode=TwoWay}"
IsEnabled="{Binding Path=IsEditAllowed, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ItemClass}, AncestorLevel=1}}" />
</ControlTemplate>
</dxg:GridColumn.EditTemplate>
</dxg:GridColumn>
There are two potentially easier ways to set up this binding.
Name the grid. Then your binding could look something like this (assuming dxg:GridControl has a property named "Items" and that you have assigned an instance of your ItemClass to that property):
<TextBox IsEnabled="{Binding Path=Items.IsEditAllowed, ElementName=MyGridControl} />
Use relative binding, but look for the GridControl rather than something nominally internal to the way GridControl works (that is, GridControlContentPresenter). This gets you away from the implementation details of GridControl, which are perhaps more likely to change in ways that break your application than are properties on GridControl itself.
<TextBox IsEnabled="{Binding Path=Items.IsEditAllowed, RelativeSource={RelativeSource AncestorType={x:Type dxg:GridControl}}}" />
You may also want to read up on the Visual Tree and the Logical Tree in WPF/xaml. The "Ancestor" in relative bindings refers to ancestors in the visual tree, that is, things like parent containers, and not to super- or base classes (as you've discovered, I think).
Here's the answer[1]. FindAncestor finds ancestors in the runtime XAML tree, not in arbitrary C# objects. It cannot walk up to the ItemClass instance from the member we're bound to. But we do know that somebody above us in the XAML tree bound us to that member, and he was bound to the ItemClass instance itself. So whoever that is, we find him, and then we've got the ItemClass.
So let's add debug tracing to the binding, and we'll see what the XAML situation looks like at runtime. No doubt there are other and probably smarter ways to do that, but I happen to know this one without any research.
First add this to the namespaces at the top of the XAML file:
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
...and then to the binding itself, add this:
diag:PresentationTraceSources.TraceLevel=High
Like so:
<TextBox Text="{Binding Value, Mode=TwoWay}"
IsEnabled="{Binding Path=IsEditAllowed, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ItemClass}, AncestorLevel=1}, diag:PresentationTraceSources.TraceLevel=High}"
/>
At runtime, when the TextEdit's IsEnabled property tries to get a value from the binding, the binding walks up through the XAML tree looking for an ancestor of the specified type. It keeps looking until it finds one or runs out of tree, and if we put tracing on it, it traces the type of everything it finds the whole way up. We've told it to look for garbage that it'll never find, so it will give us a trace of the type of every ancestor back to the root of the tree, leaf first and root last. I get 75 lines of ancestors in this case.
I did that, and found a few likely candidates. I checked each one, and the winner turned out to be dgx:GridCellContentPresenter, which has a RowData property. RowData has a lot of properties, and RowData.Row is the row's instance of ItemClass. dxg:GridCellContentPresenter belongs to the DevExpress grid library we're using; in another vendor's grid class, there would presumably be some equivalent.
Here's the working binding:
<TextBox Text="{Binding Value, Mode=TwoWay}"
IsEnabled="{Binding Path=RowData.Row.IsEditAllowed, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type dxg:GridCellContentPresenter}, AncestorLevel=1}}"
/>
If DevExpress, the vendor, rewrites their GridControl class, we'll be in trouble. But that was true anyhow.
...
[1] Better answer, though it's too DevExpress specific to be of any real interest: The DataContext of the TextBox itself turns out to be dxg:EditGridCellData, which has a RowData property just like GridCellContentPresenter does. I can just use IsEnabled="{Binding Path=RowData.Row.IsEditAllowed}".
However, what I really wanted to do all along was not to present a grid full of stupid disabled textboxes, but rather to enable editing on certain rows in the grid. And the DevExpress grid lets you do that through the ShowingEditor event.
XAML:
<dxg:GridControl Name="grdItems">
<dxg:GridControl.View>
<dxg:TableView
NavigationStyle="Cell"
AllowEditing="True"
ShowingEditor="grdItems_TableView_ShowingEditor"
/>
</dxg:GridControl.View>
<!-- ... Much XAML ... -->
</dxg:GridControl Name="grdItems">
.cs:
private void grdItems_TableView_ShowingEditor(object sender, ShowingEditorEventArgs e)
{
e.Cancel = !(e.Row as ItemClass).IsEditAllowed;
}

Binding WPF ContextMenu MenuItem to UserControl Property vs ViewModel Property

I'm struggling to understand what is going on with the ContextMenu. I know it is rendered as a separate window, with a separate visual tree, so we can't use relative binding to bind a command exposed as a property of the user control. e.g. the following does not work:
<MenuItem Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=TestCommand}" Header="Test" />
But, if you set the data context of the user control to a view model that exposes a command as a property, the following will work:
<MenuItem Command="{Binding TestCommand}" Header="Test" />
What I don't understand is, how is the ContextMenu inheriting the value of the DataContext if it is not part of the visual tree. I would expect both of these examples to behave the same (i.e. both work or both fail).
The second binding works because of so called "inheritance context". You can read about it here: http://blogs.msdn.com/b/nickkramer/archive/2006/08/18/705116.aspx. Basically this is a kind of special case where some properties inherit data context of the owner object. Thus, for example, the inheritance context always works on properties of type Freezable (another interesting article about Freezables: http://drwpf.com/blog/category/freezables/).
Actually the article says that the inheritance context doesn't work on ContextMenu, but in version 4 they added it, so it actually works now as you've shown it in your example.

Resources