I am using an Xceed DataGridControl hosted inside an Infragistics container control SplitPane/ContentPane.
If I instantiate a UserControl containing the DataGridControl within a floating SplitPane/ContentPane and immediately invoke a function on it (using the dispatcher), the DataGridControl.ItemsSource property is null. Even if invoke another dispatcher call before checking, it is null.
However, if I make the SplitPane/ContentPane not floating, it is not null and I am able to use it as I require.
It appears to be a rendering issue perhaps, but using the dispatcher is not helping in this case.
As this error has been very difficult to reproduce in a barebones example project written from scratch, I have spent some time stripping down my commercial application to the skeleton code causing the issues. This is attached. The Xceed DataGrid for WPF control suite will have to be installed from here (site registration may be required).
In the attached example project, after loading, if the user selects 'Call & Alert Manager' from the OutlookBar on the left, an assert error message box pops up denoting the occurrence of the issue in CallAndAlertManager.UpdateAutoFilterValues() function. However, if the spCallMonitor SplitPane has its XamDockManager.InitialLocation set to DockedLeft, the problem is resolved. But I need this to work for the floating case.
Any assistance in resolving this would be greatly appreciated.
Brilliant! That resolved it. A simple and elegant solution.
Thanks,
Jason
FindAncestor bindings only look in the immediate visual tree so they will not work for floating windows. You can however rely on the floating windows getting the DataContext of the associated xamDockManager. You can also rely on using ElementName binding but in your case the usercontrol's name will be provided by the object that creates an instance of the usercontrol so I wouldn't rely on that in this case since you're trying to get to the usercontrol. For your situation, it seems that the best option is to simply set the DataContext of the UserControl to itself and then just bind to the property on that. e.g.
<local:ScreenControl x:Class="BarclaysCapital.CR.PDC.Margin.CallAndAlertManager" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:igDock="http://infragistics.com/DockManager" xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid" xmlns:local="clr-namespace:BarclaysCapital.CR.PDC.Margin" DataContext="{Binding RelativeSource={RelativeSource Self}}" >
And then bind to:
<xcdg:DataGridCollectionViewSource x:Key="callList" Source="{Binding Path=CallList}">
OK, I've adjusted the project to bind to ContentPane.Tag instead from my nested element. However, this seems incredibly against OO as I now have to programmatically set ContentPane.Tag each time the object reference changes.
Technically, I had to do this before, but this was using INotifyPropertyChanged so that all subscribers (binders) to the property would update themselves (by invoking OnPropertyChanged) rather than having to explicitly update each binder to the property as I have to do with this solution.
The only way around this I found is to set the Binding of ContentPane.Tag to my property programmatically during the UserControl.Initialized event and notify this property binding/subscription of any change to the property via INotifyPropertyChanged.OnPropertyChanged. I have attached the updated project.
This seems incredibly convoluted vs. my solution of using a wider scope container's Resources to put my binding element, but I would welcome your thoughts on this from a design point-of-view.
I suppose you can use the DataContext/Tag property of the ContentPane itself.
This should be working either when the content pane is docked or floating:
<igDock:ContentPane Header="Pane 2" Tag="This is the tag of the ContentPane" >
<TextBlock Text="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type igDock:ContentPane}}}"/>
</igDock:ContentPane>
OK, I've tried this, and this works as long as the pane is assumed to always initially be floating, so that, by the time DataContext is read, it has already been set in the ToolWindowLoaded event handler.
However, my situation uses the XamDockManager SaveLayout and LoadLayout functions which sets whether the ContentPane is floating or not before the binding takes place. So, at the point of binding, DataContext will not be set if the ContentPane is not floating as per LoadLayout, in which case I would need to use the UserControl up the visual tree as per my original implementation. I have attached another example project demonstrating this.
Is there any way of setting a binding that will cater for a ContentPane that could be either floating or not floating upon initialisation short of putting the binding element in a wider scope container Resources?