WPF Binding To Child Control - wpf

I've got a TabControl which contains a nested ListView. The ListView is bound to the selected item in the parent TabControl. This works great in that switching tab displays the child elements in the ListView. What I can't figure out, is how to bind to the ListView's SelectedItem from outside of the Menu UserControl.
i.e.
<TabControl x:Name="Parent">
<TabControl.ContentTemplate>
<DataTemplate>
<ListView x:Name="Child"
ItemsSource="{Binding Path=SelectedItem.Tabs, ElementName=Parent}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<ItemsControl ItemsSource="{Binding Path=SelectedItem.Controls, ElementName=Child}">
<ItemsControl.ItemTemplate>
<DataTemplate>
... controls go here ...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I'm using M-V-VM so don't want to do my binding in code ideally - I'm sure it's possible, just can't figure it out :)

In general, if you need a property on a higher level you could move the property to the ViewModel that is bound to the higher level.
So, if I understand correctly, I would move the property of the ViewModel that is bound to the SelectedItem to the VM of the TabControl.
Does this make sense?

Related

WPF MVVM Light dynamic views and datagrids

Okay I have a mildly complex piece of functionality here. I'd like to know A) If I am doing it properly. If not, what should I change? 2) If it is proper, what is the best solution to my problem?
I have a main window with a ListView of items. If I click one of these, the right hand Grid Column in this window should populate with a DataGrid with information on the item selected. If I click another item in the ListView, it should change to another DataGrid.
I have seen some ContentPresenter examples but I cannot get this to work, so I stripped it out and will show you the code I have so far. Right now, I only have one item setup, so I will stick with this Driver example.
DriverGrid.xaml
<UserControl DataContext="{Binding AdminDriver, Source={StaticResource Locator}}">
<Grid>
<DataGrid>
//stuff here for datagrid
</DataGrid>
<Button Content="Edit" Command="{Binding ShowEditWindow}" />
<Button Content="Add" Command="{Binding ShowAddWindow}"/>
</Grid>
</UserControl>
AdminDriver.cs (VM)
//Contains variables, and is the datacontext for the above usercontrol
AdminMain.xaml (view for all admin stuff)
//Contains a bunch of junk for the min admin screen which has the listview with the options in it. If you require this piece of code, I can trim it down but I don't se currently see it's relevance. The DataGrid belongs in this window, I'm assuming in a Content Presenter. Here is the ListView that is in column 1 of 2.
<ListView ItemsSource="{Binding AdminMenu}"
Name="AdminFields"
SelectionMode="Single">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand CommandParameter="{Binding SelectedItem, ElementName=AdminFields}" Command="{Binding registerSelected}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemTemplate>
<ItemContainerTemplate>
<TextBlock Text="{Binding FieldName}"/>
</ItemContainerTemplate>
</ListView.ItemTemplate>
</ListView>
I would take the binding of the DataContext out of the UserControl. This will allow you to use it in other spots if you ever find the need. Instead, just bind the DataContext where you are using it.
<view:YourUserControl DataContext="{Binding AdminDriver}" />
If you are looking to present different UserControls based upon which item is selected in the ListView, then you'll use a ContentPresenter. All the items in your ItemsSource will have the same base class or implement the same interface so that you can put them in the same ObservableCollection. I'll assume AdminDriver would be of that type/interface as well then.
You would set up some DataTemplates at the top of the Window that map the possible real types of the objects in your ItemsSource (AdminMenu) to the UserControl that would represent them.
<Window.Resource>
<DataTemplate DataType="{x:Type model:TypeA}">
<view:UserControlA />
</DataTemplate>
<DataTemplate DataType="{x:Type model:TypeB}">
<view:UserControlB />
</DataTemplate>
//rinse and repeat
</Window.Resource>
Then you'll add a ContentPresenter to the Grid and bind it's DataContext to the AdminDriver property. The UserControl matching the actual type of the selected item as mapped in your DataTemplates will appear.
<ContentPresenter Content="{Binding AdminDriver}" />

SelectedItem of ListBox with DataTemplate

I have a Listbox with DataTemplate. The DataTemplate contains UserControl element. If I clicked on the UserControl element the Item, which contains this UserControl does not become the SelectedItem of the ListBox. If I clicked anywhere in the area of item except it's UserControl, it is selected.
How can I select the item of ListBoxby clicking on the area belongs item's UserControl?
<ListBox ItemsSource="{Binding ListOfQuestion, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
HorizontalContentAlignment="Stretch"
x:Name="ListOfQuestion"
SelectedItem="{Binding SelectedQuestion, Mode=TwoWay}">
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<local:usc_QuestionEdit x:Name="QuestionList"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Sounds like the user control is catching the mouse click and not the listbox. That is why it doesn't get selected. If you are using code-behind, you can use the events with the Preview prefix to catch the click higher in the control hierarchy.
To learn more about this events read about Routed Events on MSDN
Update: This post seems to have the answer you are looking for.
Hope this helps

DataGrid binding in DataTemplate

I'm currently trying to do some binding inside of a datagrid but I'm having problems getting up to the level of DataContext of the view.
Here is the code:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Operators}"
ItemsSource="{Binding DataContext.OperatorList,ElementName=FilterGrid}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
Any ideas on whats wrong? The View's Viewmodel is connected in the code behind.
EDIT: The Binding that is not working is the ItemsSource binding shown above
When you use the DataTemplate of the DataGrid, you cannot use ElementName bindings as it won't resolve properly due to limitations in the resolution capabilities of FindControl within the DataGrid control hierarchy. You need to use a RelativeSource binding that travels up the control tree looking for a specific control type (which you need to determine - from your element name I assumed it was a DataGrid ancestor type).
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
SelectedItem="{Binding Operators}"
ItemsSource="{Binding DataContext.OperatorList,
RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
See this SO post that shares some potentially related sample code using MVVM to access the DataContext of the UserControl host to populate a ComboBox ItemsSource.

WPF ListBox ItemsSource with DataTemplate

I have a ListBox with an ItemsSource pointing to a static variable, and a DataTemplate for the ListBox's ItemTemplate that should be displaying the Description property of the variable the ItemsSource points to
<ListBox x:Name="classificationTypeListBox"
ItemsSource="{x:Static h:AmbientHighlightingStyleRegistry.Instance}"
SelectedIndex="0" Foreground="Black">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=(Description)}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I can put a break point on my application and view the ListBox. The ItemsSource does point to the variable I want and it looks like the ListBox is trying to display all the values because I can click and scroll down the it. However, no text is getting displayed so you can't actually tell what you're clicking. Also, while the break point is on, it says that the list box contains 0 items, maybe it should because I'm binding it, not sure. Any suggestions?
<TextBlock Text="{Binding Path=(Description)}" />
Why do you have parens in there? This syntax causes WPF to try to bind to an attached property, which is not what you want to do.

How to bind items of a TabControl to an observable collection in wpf?

What is the simplest example of binding the items of a TabControl to an ObservableCollection?
Each tab's content will have unique data, and indeed this data will have observableCollections of its own bound to the items components.
Currently I have a user control, which I would like to set as the content of each tab as soon as it is created. I also need to dynamically set the datacontext of this new user control when the tab is created. So, essentially, I would like the tabcontrol's observablecollection contain modelviews that map to the data in each tab.
On top of that, I need to do all this without violating MVVM in WPF! Any help?
Much appreciated!
Basic example :
<Window.Resources>
<DataTemplate x:Key="templateForTheContent" DataType="{x:Type vm:TheViewModelType}">
<v:YourUserControl/>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" DataType="{x:Type vm:TheViewModelType}">
<TextBlock Text="{Binding ThePropertyToDisplayInTheHeader}"/>
</DataTemplate>
</Window.Resources>
...
<TabControl ItemsSource="{Binding YourCollection}"
ContentTemplate="{StaticResource templateForTheContent}"
ItemTemplate="{StaticResource templateForTheHeader}">
</TabControl>

Resources