Set DataTemplate control property binding to the item from an ItemsSource collection? - wpf

I have an ItemsCountrol with its ItemsSource property bound to an ObservableCollection. I have a usercontrol (TeamUserControl) that displays this type. I created a datatemplate that loads this usercontrol for each customtype item in the itemssource collection. At this point any Binding statements I make inside TeamUserControl can reference Team properties directly by path {Binding Path=TeamOwner} and work. Is there a way to bind a reference to the ItemsSource item the usercontrol is representing? For example, in the TeamUserControl creating a dependancy property of type Team and have it bound to the instance of the item from the ItemsSource.
<ItemsControl Name="ItemCtrl" Grid.Row="0" ItemsSource="{Binding Path=League.Teams}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<mycontrols:TeamUserControl AttachedTeam="{Binding ???}" TeamOwnerName="{Binding Path=TeamOwner}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In this example the window is representing a class "League" which has the property:
ObservableCollection Teams. And there is a class "Team" which has the property:TeamOwner. The TeamUserControl has two dependancy properties: AttachedTeam of type Team, and TeamOwnerName of type string.
I included the team-owner property reference to show that there is an instance of Team for each of these usercontrols. I am just not sure how to reference it.

As I understand you, you should to write
<mycontrols:TeamUserControl AttachedTeam="{Binding}" TeamOwnerName="{Binding Path=TeamOwner}"/>
{Binding} statement will bind to current item in ItemsSource, where type T is type which your ObservableCollection<T> League.Teams uses.
I also recommend you to read MSDN article about ItemsControl, and look around Binding to make it clear for yourself, what you can bind to.

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.

Identifing context of clicked item from ItemsControl in code

I have some collection bound to ItemsControl. DataTemplate was customized to represent its elements. Now I have to perform some operation on data (one Cell from collection) corresponding to rendered DataTemplate in result of clicking it.
Window's DataContext is set to ViewModel containing my collection.
<DataTemplate x:Key="template"
DataType="logic:Cell">
<Ellipse .../>
</DataTemplate>
...
<ItemsControl ItemTemplate="{DynamicResource template}"
ItemsSource="{Binding collection}">
...
</ItemsControl>
I have just started with MVVM pattern for WPF. I'm looking for good pattern to deal with such issue (in MVVM style).
In your ViewModel, you can use the following snippet...
var v = CollectionViewSource.GetDefaultView(MyCollection);
var ci = v.CurrentItem;
int p = v.CurrentPosition;
where 'MyCollection' is the list you have bound to your ItemsControl. The variable 'ci' will contain an object which can be downcast to the item you need. The variable 'p' tells the index of where 'ci' is in your collection.
If 'MyCollection' inherits from IList, there are additional goodies you can access as well.
Adding: check for nulls before referencing

Custom control's content can't bind to parent of the control

I have following XAML (simplified, no ending tags):
<Window Name="myWindow" DataContext="{Binding ElementName=myWindow}" >
<DockPanel>
<tb:ToolBar Name="toolbar" DockPanel.Dock="Top">
<tb:ToolBar.Items>
<tb:ToolBarControl Priority="-3">
<tb:ToolBarControl.Content>
<StackPanel Orientation="Horizontal">
<TextBlock>Maps:</TextBlock>
<ComboBox ItemsSource="{Binding Generator.Maps, ElementName=myWindow}">
But the ComboBox's binding will fail with
Cannot find source for binding with
reference 'ElementName=myWindow'
Some facts about the custom controls:
tb:ToolBar is UserControl which contains actual ToolBar with ItemsSource bound to the Items property of the tb:ToolBar (of type inheriting IList).
The ToolBar's ToolBarItem DataTemplate is chosen from several DataTemplates (according to the type of the item).
The DataTemplate belonging to the tb:ToolBarControl is very simple - it just contains ContentPresenter bound to property Content of the tb:ToolBarControl.
tb:ToolBarControl is not for technical reasons UserControl, it is just DependencyObject with property Content of type object.
Why can't the ComboBox reference the Window?
Thanks for any help!
I had a similar problem here:
Bindings on child dependency object of usercontrol not working
DependencyObject doesn't have a DataContext and I think that's why the binding doesn't work. Instead of inheriting from 'DependencyObject' try inheriting from FrameworkElement.

Where is the datacontext for the CustomerViewModel in the official MSDN MVVM article?

I speak about josh smith article.
can anyone show me please how the CustomerView.xaml specifically this:j
<TextBox
x:Name="firstNameTxt"
Grid.Row="2" Grid.Column="2"
Text="{Binding Path=FirstName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{x:Null}"
/>
Why is there a Binding to FirstName which is public property in the CustomerViewModel.
There is a datacontext set for the MainViewModel, but not for the CustomerViewModel, so why does the binding work ???
Check out the ResourceDictionary in MainWindowResources.xaml. Josh uses the following code to describe what View should be used if an instance of CustomerViewModel is shown in the main window:
<DataTemplate DataType="{x:Type vm:CustomerViewModel}">
<vw:CustomerView />
</DataTemplate>
We've described that when our DataType is of Type CustomerViewModel, we'll create a new instance of the CustomerView. WPF takes care of the DataContext and creation when it sees the CustomerViewModel type.
From the rest of the article:
Applying a View to a ViewModel
MainWindowViewModel indirectly adds
and removes Workspace ViewModel
objects to and from the main window's
Tab Control. By relying on data
binding, the Content property of a
TabItem receives a
ViewModelBase-derived object to
display. ViewModelBase is not a UI
element, so it has no inherent support
for rendering itself. By default, in
WPF a non-visual object is rendered by
displaying the results of a call to
its ToString method in a TextBlock.
That clearly is not what you need,
unless your users have a burning
desire to see the type name of our
ViewModel classes! You can easily tell
WPF how to render a ViewModel object
by using typed DataTemplates. A typed
DataTemplate does not have an x:Key
value assigned to it, but it does have
its DataType property set to an
instance of the Type class. If WPF
tries to render one of your ViewModel
objects, it will check to see if the
resource system has a typed
DataTemplate in scope whose DataType
is the same as (or a base class of)
the type of your ViewModel object. If
it finds one, it uses that template to
render the ViewModel object referenced
by the tab item's Content property.
The MainWindowResources.xaml file has
a Resource Dictionary. That dictionary
is added to the main window's resource
hierarchy, which means that the
resources it contains are in the
window's resource scope. When a tab
item's content is set to a ViewModel
object, a typed DataTemplate from this
dictionary supplies a view (that is, a
user control) to render it, as shown
in Figure 10.
The DataContext for the MainViewModel in App.xaml.cs serves as a starting point for our application.

WPF UserControl in DataTemplate within ItemsControl - how to bind to parent of ItemsSource

The subject line says it all really! I have a user control which can be bound successfully to, say, a Fullname object - i.e. it works ok.
I now need to show a list of these and, again, this works ok when the control is in a DataTemplate within ItemsControl.Template.
But, the control has a property (InEditMode) that is not a property of the Fullname object but of the object that has the FullnameList property to which the ItemsControl is bound, via ItemsSource. This InEditMode property works fine when the control is not in a list and is bound to parent sibling properties named, say, ParentInEditMode and ParentFullname.
The question is - what style of binding expression is required to 'get at' the edit mode property of the parent object when the control is an ItemsControl?
Or, should I re-design the Fullname object to contain an EditMode property?
Many thanks in advance!
Update:
The item (i.e. that which is in collection bound to the ItemsControl) does NOT have such a property. Code is very simple:
<ItemsControl ItemsSource="{Binding Path=FullnameList}">
...then...
<ItemsControl.ItemTemplate>
<DataTemplate>
<jasControls:NameView
NameValue="{Binding Path=.}"
InEditMode= ??????? />
The overall parent (the viewmodel for the window) has properties:
FullnameList
ParentInEditMode
Fullname (single item for testing NameView which works perfectly with this xaml outside of any list control using:
<jasControls:NameView NameValue="{Binding Path=Fullname}" InEditMode="{Binding Path=ParentInEditMode}"/>
I would like to apply the edit mode to the entire collection - making that flag part of Fullname does not seem right!?
I have found an answer to my own question, which I hope will help others.
The working syntax I have is this:
<StackPanel>
<ItemsControl ItemsSource="{Binding Path=FullnameList}">
...then...
<ItemsControl.ItemTemplate>
<DataTemplate>
<jasControls:NameView
NameValue="{Binding Path=.}"
InEditMode= "{Binding DataContext.ParentInEditMode,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StackPanel}}}" />
This correctly picks up the property that is a sibling of FullnameList and passes it to the data template item. More by luck than judgement, but I hope this is a valid way to do this!
For each Item in ItemsSource, ItemsControl creates the specified DataTemplate and to its DataContext it assigns the respective Item. Now every DataTemplate can bind to its item in its data context.
So I suppose your item does have a property "ParentInEditMode"; there should be no issue with binding to that property.
If it doesn't work, please update your question with some code.

Resources