WPF : Binding Order - wpf

I have a usercontrol (ItemsView) that I use in one of my other view. Since I need to access its ViewModel, the ItemsViewViewModel is contained by the ViewModel of the view that contained the control. I use this control at many times and I find it useful to bind a collection on the ItemsSource of my ItemsView control (differently, depending on the view that used it). It works, but not all the time.
Here some code :
<local:ItemsView DataContext="{Binding Path=ItemsViewModel}" ItemsSource="{Binding Path=DataContext.CurrentItem.Children, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" />
The problem is that the DataContext of the ItemsView is sometimes set before the ItemsSource, and sometimes after. This is problematic because the ItemsSource is a dependency property linked to the ItemsViewViewModel.
Is there a way to have the DataContext set before the ItemsSource everytime?

After InitializeComponent, set SelectedIndex to -1 - this worked for me.

Related

trying to bind datagrid item source to a property in another class

I have a WPF app with a MainWindow. The MainWindow consists of several CLR properties of type ObservableCollection. The MainWindow has a datagrid, whose ItemsSource property is bound to one of the observable collections (works fine). Next, I have a dialog. Its purpose is to display one of the observable collections from the main window in a datagrid. The dialog gets instantiated in the MainWindow. Initially I was passing the ObservableCollection to the dialog's constructor, and copying it into the dialog's CLR property. Then I would set the DataContext of the dialog to itself, and bind the ItemsSource property in the datagrid to the name of the CLR property. This worked fine.
Is there a better way to do this instead of passing the observable collection through the constructor? I tried setting the ItemsSource property of the Datagrid in the dialog to the observable collection in the MainWindow by using the GUI editor, which generated a binding using RelativeAncestor, but the data did not show. The problem is I have a bunch of dialogs that are meant to display data from the MainWindow, and I feel like there should be a simpler solution rather than passing everything to dialog's constructor. Also, would the dialogs be considered SubViews? The main window is a view.
Let's say your Dialog control is named DialogControl and has a DependencyProperty named Items defined in its code behind. In the XAML, I would bind this property to the DataGrid like this:
<DataGrid ItemsSource="{Binding Items, RelativeSource={RelativeSource Mode=
FindAncestor, AncestorType={x:Type DialogControl}}" />
This RelativeSource binding will go off and search through the properties of your DialogControl class and find the Items property. Note: Do NOT set the DataContext of the UserControl to itself.
Now in your MainWindow.xaml.cs file where you instantiate your DialogControl, you can set the Items property:
DialogControl dialogControl = new DialogControl();
dialogControl.Items = someCollection;
dialogControl.Show();
UPDATE >>>
Oh I see what you're after now... you want to bind from your UserControl to the actual collection in the MainWindow.xaml.cs file. You can still follow my advice, but instead of having the DependencyProperty in your DialogControl, you need to have it in your MainWindow.xaml.cs file. In that case, your binding in the UserControl would be:
<DataGrid ItemsSource="{Binding Items, RelativeSource={RelativeSource Mode=
FindAncestor, AncestorType={x:Type MainWindow}}" />
For this to work, the Items property must be a DependencyProperty.

Binding with parent DataContext

I'm trying to bind combobox editor in a PropertyGrid to a list.
<dxprg:PropertyGridControl SelectedObject="{Binding SelectedEmployee}">
<dxprg:PropertyDefinition Path="EmployeeCountryID">
<dxprg:PropertyDefinition.EditSettings>
<dxe:ComboBoxEditSettings
ItemsSource="{Binding Path=DataContext.Countries, ElementName=rootWindow}"
ValueMember="CountryId" DisplayMember="CountryName" />
</dxprg:PropertyDefinition.EditSettings>
</dxprg:PropertyDefinition>
</dxprg:PropertyGridControl>
This example is from a third-party control but the problem may be just general.
The "rootWindow" DataContext has been set to a ViewModel which holds a property List(of Country) that I want have as ItemsSource in a Combobox.
I was trying to access that list by setting the Combobox ItemsSource to the rootWindow.DataContext.Countries property but I don't get any data.
Tried also all those RelativeSource FindAncestor bindings but no data appeared either.
Why can't I bind through a DataContext of a given element like this?
This became solved. The problem was not with the binding at all but realated to how I defined the third-party control: Instead of EditSettings I should have defined CellTemplate -> DataTemplate.

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 to bind to a property of the ViewModel from within a GridView

I'm using the MVVM design pattern, and the DataContext of my View is set to a ViewModel.
In my View, I have a ListView/GridView with ItemsSource bound to a DataTable. One of the GridViewColumns has a CellTemplate that presents a Button. I want the IsEnabled property of the button to be bound to the SelectButtonsEnabled property of my ViewModel.
Using IsEnabled="{Binding Path=SelectButtonsEnabled}" doesn't work because my DataTable doesn't have a column named "SelectButtonsEnabled". The property I'm trying to bind to is global for the whole ViewModel, not specific to a row of the DataTable.
I think I need some kind of RelativeSource tag, but all my attempts thus far have failed.
Thanks.
Well, I don't know if this is the most succinct way to do it, but this works:
IsEnabled="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}, Path=DataContext.SelectButtonsEnabled}"

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

Resources