WPF Binding: Waiting for ItemsSource - wpf

I have a problem with the following binding:
<telerik:RadComboBox ItemsSource="{Binding Source={StaticResource TemplateDataSource}, Path=Templates}"
SelectedValue="{Binding Template}"
SelectedValuePath="Id"
DisplayMemberPath="Title"
Margin="0">
</telerik:RadComboBox>
All my data is loaded async via WCF data services.
From time to time I get the following error (which I could trace back to the above binding)
Specified argument was out of the range of valid values.
Parameter name: index
Now I guess it has something to do with the entity providing the SelectedValue (Template) being loaded before the ItemsSource. Could this be? Is there a solution to this problem, like waiting for the ItemsSource to load?
Thanks for any help in advance!

Try to write Dummy converter on SelectedValue="{Binding Template}"
You can then debug this converter to find out real cause of error.

Related

How to bind to multiple sources without codebehind or using SelectedValue

While trying to convert usual wpf fields to the custom fields that the program I need to modify, I came across an issue of having 2 different data sources.
1) The data source that retrieves/inserts data to fill this combobox (DataSource)
2) The data source that takes care of other UI elements (DSP)
As when certain items are selected from the combobox, not only does it get stored with the other information in the form, but it may show/hide another UI element.
I am trying to convert:
<ComboBox Name="tempComboBox"
ItemsSource="{Binding Source={StaticResource DataSource}, Path=Value.Properties[temp].MetaData.Lookups}"
DisplayMemberPath="Description"
SelectedValuePath="Value"
SelectedValue="{Binding Source={StaticResource DSP}, Path=Value, ValidatesOnDataErrors=True}"
Style="{StaticResource tempComboStyle}"/>
Into something like this:
<ctrls:Fields Name="tempComboBox"
FieldName="temp"
DataContext="{Binding Source={StaticResource DataSource}, Path=Value, ValidatesOnDataErrors=True}"
Style="{StaticResource tempComboStyle}"/>
However, this WILL NOT work as it only stores the data, but does not hide/show elements when the specific item is selected.
I have tried multi binding, which does not work. Surrounding the combobox tags with the ctrls:Fields tag, again doesn't work. And combining the DataContext property with both SelectedValue and ItemSource, none of which work.
I do not have any way of getting to the code behind of this form either, it must be strictly done through XAML.
Thank you for any help!

DataGridColumnHeader of a DataGrid defined in a DataTemplate for a ViewModel

I have successfully used ProxyElement to pass Data Context of my Data Grid to DataGridColumnHeaders. However, I am trying out something new and I just can't figure out what I am doing wrong over here.
Here is what I am trying to do: I am creating a UserControl and associating it to my ViewModel in my Resources file (see Resources.xaml code snippet below).
Resources.xaml:
<ResourceDictionary
xmlns:myVm="clr-namespace:..."
xmlns:myUserControl="clr-namespace:...">
<DataTemplate DataType={x:Type myVm:DummyModel}">
<myUserControl:DummyUserControl />
</DataTemplate>
</ResourceDictionary>
Now in my UserControl, I have a DataGrid with a DataGridComboBoxColumn. I am trying to access my data context to set its item source and in the past I was able to do it using proxy element. This time however I am not able to do so. (See DummyUserControl.xaml code snippet below)
DummyUserControl.xaml:
<UserControl x:Class="Client.MyControl.DummyUserControl"
...>
<UserControl.Resources>
<FrameworkElement x:Key="ProxyElement" x:Name="ProxyElement"
DataContext="{Binding}" />
</UserControl.Resources>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Products}">
<DataGridComboBoxColumn
Header="Company"
ItemsSource="{Binding Path=DataContext.ProductCompanies,
Source={StaticResource ProxyElement}}"
DisplayMemberPath="Name" SelectedValuePath="Id"
SelectedValueBinding="{Binding CompanyId}" />
</DataGrid>
</UserControl>
When I do this, my binding fails with the following message:
System.Windows.Data Error: 3 : Cannot find element that provides DataContext.
BindingExpression:(no path); DataItem=null; target element is 'FrameworkElement'
(Name='ProxyElement'); target property is 'DataContext' (type 'Object')
I have no idea what to do here. I remember reading that the datacontext for a datatemplate is automatically set, so I have no idea why the data context is null in this case. To prove it is null, I also tried setting the binding in the code-behind file and added a breakpoint to check its value (which was null).
Can anyone suggest what to do here?
Edit 1
I have also tried the following approaches:
Remove ProxyElement altogether and see if it can detect DataContext. To no surprise, this failed.
Tried binding to the templated parent. Fail.
Tried binding to the UserControl itself. Fail.
I also tried referencing the data context of the parent item where this view model is going to be displayed, which is in a TabItem of a TabControl.
All of the alternate bindings gave me same error as the error above.
Here is a (working but not preferred) solution to this problem. You will realize why it is not preferred by the end of it.
The key to this problem is understanding what and how data context of a data template works. Whenever you define a Data Template for a View Model, the data context for the view that follows, whether it is a user control or just xaml itself, is the View Model! This shouldn't be a surprise to anyone.
But this will surprise people: if you specify a User Control, the Data Context of the User Control is not set during construction of the User Control! In other words, in the constructor of User Control, Data Context is going to be null. Furthermore, any XAML code that relies on the Data Context at construction time, which in this case was my FrameworkElement resource called ProxyElement got its DataContext set to null because it gets constructed at construction time of the User Control!
So when does the DataContext get set? Simply after the User Control is created. In pseudo code, this following describes the logic behind drawing a ViewModel:
Draw ViewModel x;
DataTemplate in ResourceDictionary says ViewModel x can be drawn using UserControl abc
Let's create a new instance of UserControl abc
Let's now assign the DataContext of abc to the ViewModel itself.
Let's return the newly created instance of UserControl abc
So what do we do to solve the problem in this question?
UserControl.xaml:
<UserControl ...
DataContextChanged="DaCoHasChanged">
<UserControl.Resources>
<FrameworkElement x:Key="ProxyElement" /> <!--Remove DataContext="{Binding}"-->
</UserControl.Resources>
<DataGrid ...>
<DataGridComboBoxColumn
ItemsSource="{Binding Path=DataContext.ProductCompanies,
Source={StaticSource ProxyElement}}"
... />
</DataGrid>
</UserControl>
UserControl.xaml.cs:
private void DaCoHasChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var proxyElement = Resources["ProxyElement"] as FrameworkElement;
proxyElement.DataContext = e.NewValue; // instead of e.NewValue, you could
// also say this.DataContext
}
I am trying to figure out a way of getting rid of the code in the code-behind file. But till then, if someone else hits this problem, then they might be able to get inspired from this solution.
Credit to the concept behind this solution goes to: How to set the DataContext for a View created in DataTemplate from ViewModel
Try this
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Products}">
<DataGridTemplateColumn Header="Company">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding Path="{Binding DataContext.ProductCompanies,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="Name" SelectedValuePath="Id"
SelectedValueBinding="{Binding CompanyId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Now as I got your problem I think the problem is in DataGridComboBoxColumn I dont know why it not Binding using RelativeResource . Try it with DataGridTemplateColumn and you would not require any ProxyElement I hope this will help.

bind data to combobox in datagrid in silverlight

how can i bind the data returning from WCF in combox in grid . the combobox is not in edit mode. I am able to display the static data but not the data returning from WCF.
u can use RelativeSource to search needed DataContext/ViewModel/Page/UserControl in the elements tree
example for the ViewModel where DataGrid itemssource defined near ComBoxCollectionSource:
<ComboBox ItemsSource={Binding RelativeSource={RelativeSource AncestorType=sdk:DataGrid}, Path=DataContext.ComboBoxColloctionSource} />
I'm assuming the static data is the stuff you enter into the Items property by hand. The syntax for a combobox is a bit different, but here it is:
<ComboBox ItemsSource="{Binding Path=<your collection>,Mode=OneTime}" SelectedValuePath="<id-field>" DisplayMemberPath="<display-field>" SelectedItem="{Binding Path=<your-property>,Mode=TwoWay}" />
The parameters ending in PATH above just have the names of the properties as a string.
EDIT: If you're using a dictionary, you would use:
<ComboBox ItemsSource="{Binding Path=<your dictionsry>,Mode=OneTime}" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedItem="{Binding Path=<your-int-property>,Mode=TwoWay}" />

Silverlight recursivly bind Treeview to XDocument

How can I recursivly bind a Treeview to an XDocument, mapping each XML Element to a Node in the Treeview?
The code below should work from my perspective (and also according to the very few posts I found regarding direct binding), however it does not:
<sdk:TreeView ItemsSource="{Binding Path=Elements}" DataContext="{Binding Path=Data}">
<sdk:TreeView.ItemTemplate>
<data:HierarchicalDataTemplate ItemsSource="{Binding Path=Elements}">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</data:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
</sdk:Treeview>
(Data is a Property of type XElement on the parents' DataContext)
Did I make a mistake somewhere or do I really need to implement an IValueConverter just to get at the child elements of an XElement?
The "Elements" member is not a Property, It's a Method call.
You cannot bind to method calls in Silverlight.
If you're really bent on getting this scenario to work you've got 2 options I can see:
1. Use an IValueConverter to extract the contents of the "Elements" method.
2. Wrap the XDocument in managed classes in a proper hierarchy.
Personally, While option #1 seems the fastest, I believe that in the long run it'll cost you more time to maintain and support then spending an additional 10 minutes building a proper domain model.
Sincerely,
-- Justin Angel

How to set TextSearch.Text for a combobox whose TextBlock uses converter?

In the below code, Combobox is wired to NameInfo object along with a converter.NameInfoConverter returns a format in which items in combobox are shown in a particular format (for eg: LastName, FirstName (Badge#) )
Now, when I set TextSearch.Text="{Binding NameInfo, Converter={StaticResource NameInfoConverter}, ConverterParameter=true}" on combobox; TextSearch doesn't work. When I set TextSearch.TextPath="Name", search itself works but doesnot get the correct format displayed in the selectionbox of combobox.
Any Ideas?
<StackPanel>
<ComboBox x:Name:"cmbName">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name,
Converter={StaticResource NameInfoConverter}, ConverterParameter=true}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
You've probably hit a limitation in the API. I suggest you take an alternative route and bind directly to a property that is correctly formatted for your textblock.
If this is a serious app, you may want to look into using the MVVM pattern and place your converted/formatted property in the viewmodel. Otherwise, just create a new property on your databound class called NameInfo or something and do the conversion from that.

Resources