Setting ListView ItemSource binding in code - wpf

I have a working ListView like this
<ListView Name="passageListView" ItemsSource="{Binding Path=Passages, NotifyOnTargetUpdated=True}" TargetUpdated="PassageListViewTargetUpdated">
where Passages is an ObservableCollection<>.
Now, how I do the same binding in code? (note that NotifyOnTargetUpdated=True has to be set)
I have tried to assign a Binding to passageListView.ItemsSource but this is not allowed and I can't use SetBinding() since passageListView.ItemsSourceis not a DependencyProperty?
Any ideas?

try this in the constructor of the control where the ListView is:
passageListView.SetBinding(ListView.ItemsSourceProperty,
new Binding
{
Path = new PropertyPath("Passages"),
NotifyOnTargetUpdated = true
});
If the DataContext is set properly, this should work.
The DependencyProperty could also be ItemsControl.ItemsSourceProperty, because that is the base class.

Related

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.

Binding inside ContentControl not working

I'm building a graphical designer, based upon an article by Sukram in CodeProject. I'm now trying to extend it so that each item on the canvas binds to a different ViewModel object - i.e. I'm setting the DataContext for each item.
Every item on the designer is actually a ContentControl, into which is placed a different template (based upon which toolbox item was dragged onto the canvas). So I have a template containing a TextBox, and I have a ViewModel object containing a Name property, and I bind the Text property of the TextBox to the Name property of the ViewModel, and ... nothing. I've checked the visual tree with Snoop, and it confirms that the DataContext of the TextBox is the ViewModel object. Yet the TextBox remains empty. And if I modify the (empty) Text in the TextBox, the Name property in the ViewModel does not change. So it looks like the binding is not being applied (or has been removed somehow).
I've found a few posts which talk about the ContentControl messing around with the DataContext and Content properties, but I'm not sure how applicable they all are. The code sets the ContentControl.Content as follows:
newItem = new ContentControl();
ControlTemplate template = toolbox.GetTemplate();
UIElement element = template.LoadContent() as UIElement;
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
newItem.Content = element;
newItem.DataContext = viewModel;
and the XAML for the template is:
<ControlTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="100">
<TextBox Text={Binding Name}/>
</Border>
</ControlTemplate>
Snoop shows that the TextBox has a DataContext, and if I Delve that DataContext I can see that it has a Name property whose value is "Bob". So why does the TextBox remain empty? Snoop allows me to change that Name property, but the TextBox remains empty.
What am I doing wrong?
A few more details. I've set the VS2010 Debug DataBinding option for the OutputWindow to Verbose, which seems to show that the binding is all being attempted before I set the DataContext. Is it possible that the change to the DataContext is not being recognised?
I've just found this post DataTemplate.LoadContent does not preserve bindings - apparently DataTemplate.LoadContent does not preserve bindings. So it looks like I have to write my own version of LoadContent().
I've realised that the template has come through a XamlWriter, which apparently strips all bindings. This wouldn't be helping.
I've not been able to fix the DataTemplate.LoadContent(), but I realised that I didn't actually need a DataTemplate, since the XamlWriter / XamlReader was already instantiating the UI element that I was after. I found a fix to make the XamlWriter write all the bindings here, and after that it all works.
Thanks for your help.
Maybe you need to tell the binding in the ControlTemplate to look at the TemplatedParent, as is mentioned in this thread?
<TextBox Text="{Binding Path=Name, RelativeSource={RelativeSource TemplatedParent}}"/>
Either that, or try to use a DataTemplate instead.
I can't test this at the moment, so I might just be guessing here.
I would use a DataTemplate, as bde suggests.
You are trying to put some UI on your own data (ViewModel), and this is what Data-Templates are meant for (ControlTemplate is usually what you use if you want to change how e.g. a Button looks).
Change your code to use ContentControl.ContentTemplate with a DataTemplate:
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Width="100">
<TextBox Text={Binding Name}/>
</Border>
</DataTemplate>
Code-behind:
newItem = new ContentControl();
//NOTE: .GetTemplate() needs to return a DataTemplate, and not a ControlTemplate:
newItem.ContentTemplate = toolbox.GetTemplate();
ViewModelItem viewModel = new ViewModelItem() { Name = "Bob" };
newItem.Content = viewModel;
newItem.DataContext = viewModel;

Binding ItemsSource dependency property in custom control

I have a custom control that has a dependency property that should fill a datagrid's ItemsSource property in the control. For some reason the collection never gets filled and the ItemsSource always ends up empty.
Public Shared ReadOnly ItemsSourceProperty As DependencyProperty = DependencyProperty.Register("ItemsSource", GetType(ObservableObjectCollection), GetType(HomePageControl), New PropertyMetadata(New ObservableObjectCollection, New PropertyChangedCallback(AddressOf ItemsSourceCallback)))
Public Property ItemsSource As ObservableObjectCollection
Get
Return DirectCast(GetValue(HomePageControl.ItemsSourceProperty), ObservableObjectCollection)
End Get
Set(value As ObservableObjectCollection)
SetValue(HomePageControl.ItemsSourceProperty, value)
End Set
End Property
Xaml:
<Controls:HomePageControl x:Name="myControl"
Margin="0,25,0,0"
Grid.Row="1"
HeaderText="{Binding Source={StaticResource MainViewModel}, Path=CurrentUser, Mode=TwoWay, UpdateSourceTrigger=Default}"
HeaderCount="30"
HeaderLinkText="This is optional."
HeaderLinkURI="/Projects"
ItemsSource="{Binding Source={StaticResource MainViewModel}, Path=TaskList, Mode=TwoWay, UpdateSourceTrigger=Default}"
GridViewStyle="{StaticResource RadGridViewStyleNoFlag}"
/>
I have five other DPs that work just fine, 3 strings and one style (to set up the columns of the datagrid) and a URI. I can either set them directly, as in "This is optional", or by binding them like the HeaderText, but the ItemsSource property never seems to get bound... a gridview outside of the control that uses the same binding as used in the ItemsSource binding inside the control gets filled... so the binding does return a filled collection, but it is not making it to the datagrid inside the custom control.
If I change ObservableObjectCollection to the object type that I'm using in the collection that I bind, then it works fine. The reason I want to use ObservableObjectCollection is because I want to be able to bind any object to the datagrid, just like a datagrid can... it doesn't care what type you bind to it - how can I get my user control to not care?

Binding a combobox in XAML to a childwindow property

I want to display a child window that contains a combobox with several values coming from one of the child window's property:
public partial class MyChildWindow : ChildWindow
{
private ObservableCollection<MyClass> _collectionToBind = // initialize and add items to collection to make sure it s not empty...
public ObservableCollection<MyClass> CollectionToBind
{
get { return _collectionToBind; }
set { _collectionToBind = value; }
}
}
How do I bind in XAML my combobox to the ComboBoxContent collection (both are in the same class)? I've tried several things such as:
<ComboBox x:Name="linkCombo" ItemsSource="{Binding Path=CollectionToBind }" DisplayMemberPath="Description">
I've only been able to bind it in the code behind file and would like to learn the XAML way to do it.
Thank you!
In this case I would use ElementToElement binding like this:-
<ComboBox x:Name="linkCombo" ItemsSource="{Binding Path=Parent.CollectionToBind, ElementName=LayoutRoot }" DisplayMemberPath="Description">
You give the Content element of the ChildWindow the x:Name of LayoutRoot (in the standard template for child window this is done for you). Hence you can bind to this named element and navigate to the containing ChildWindow by using its Parent property.
Using DataContext = this is tempting and works in simple scenarios but things can get awkward in more complex requirements when the DataContext has already been taken in this way.
You need to set the DataContext of the ChildWindow to what contains the values you'd like to bind to. In this case where you're putting the values you want to bind to on the ChildWindow itself so just put a line in the constructor assigned the DataContext to itself.
DataContext = this;
You can also do this using a RelativeSource binding in the XAML, like this:
{Binding Path=CollectionToBind, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}
However, a better way to do this would be to put the CollectionToBind in a separate class and assign it to the Window DataContext. Now both the Window and the XAML Bindings can all refer to the same class as the DataContext and you can isolate more of your logic into this class rather than putting it in the Window implementation.

How can I access the root DataContext in a DataTemplate in WPF?

I have a grid of items which is populated using databinding.
In the grid I have a DataTemplate for certain cells. I need to access the DataContext of the root element (the one which is hosting the grid) so that I can access additional bindings to support my datatemplate.
So you have:
Window
Window.DataContext = TheDataSourceWithItemsAndSupports
DataGrid.ItemsSource = {Binding Items}
DataTemplate
ListBox.ItemsSource = {Binding Supports}
I want the {Binding Supports} on TheDataSourceWithItemsAndSupports, but I don't see how to do that. I tried specifying {Binding} but that always returns null. I also tried using RelativeSource FindAncestor, but that yields null too.
Any clues?
Maybe try
Window Name="TheWindow"
...
ListBox.ItemsSource = {Binding DataContext.Supports, ElementName=TheWindow}
Another little trick to bind to your root context
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}, AncestorLevel=1}, Path=DataContext.Supports}"/>
My solution was to expose whole DataContext class by implementing This field
get
{
return this;
}
and then binding to it.
It should work the way you describe. Only thing I see your DataTemplate is not ItemTemplate. You should also look at the output window to see where bindings fail.

Resources