Binding nested control using MVVM pattern - silverlight

I have a problem with binding nested control with my MVVM pattern. This is my XAML code:
<ItemsControl Grid.Column="1" ItemsSource="{Binding NotificationContacts}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<toolkit:Expander>
<toolkit:Expander.Header>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding ContactName}" Grid.Column="0" VerticalAlignment="Center"></TextBlock>
<Image Source="Images/answer_ok.png" Grid.Column="1" Margin="15,0,15,0" Width="27" Height="27"></Image>
</Grid>
</toolkit:Expander.Header>
<toolkit:Expander.Content>
<ListBox Margin="30,10,0,10" ItemsSource="{Binding NotificationContacts.Messages">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MessageName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</toolkit:Expander.Content>
</toolkit:Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The problem is, that the listbox control located in ExpanderControl Data Template is not being data bound.
Listbox control is populated by EntityCollection named 'Messages' which is contained in parent object 'NotificationContacts' that ItemsControl is databound with...
Does anyone know how to resolve this issue ?
Thanks in advance !!!

Did you try this:
<ItemsControl Grid.Column="1" ItemsSource="{Binding NotificationContacts}">
......
<ListBox Margin="30,10,0,10" ItemsSource="{Binding Messages}">
.....
<TextBlock Text="{Binding MessageName}"></TextBlock>
If I remember it right, when you are "inside" ItemContol, binding context is set to NotificationContacts. So use just "{Binding Messages}" could be fine.
And by the way, you are missing curly bracket on the line:
<ListBox Margin="30,10,0,10" ItemsSource="{Binding NotificationContacts.Messages">

Call ItemsControl f.i. "ic" and use next binding in ListBox
<ItemsControl x:Name="ic" Grid.Column="1" ItemsSource="{Binding NotificationContacts}">
...
<ListBox Margin="30,10,0,10" ItemsSource="{Binding ElementName=ic, Path=DataContext.Messages}">

Related

Items Control Binding not displaying anything?

For some reason, my XAML is not displaying anything for my Items Control. I am using a List of Students as my ItemsSource and referencing the properties of that List to create a custom control.
This is my XAML:
<ItemsControl ItemsSource="{Binding Class.Students}" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="500"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding FavoriteSubject, UpdateSourceTrigger=PropertyChanged}" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Right now, the drop-down is just empty. The bindings are correct and if I pull them outside the ItemsControl, they display fine. Is there something specific about ItemsControls that I am missing?

WPF - Use DataType from parent DataTemplate inside ContentControl

So I'm defining a DataTemplate in the UserControl.Resources like so:
<DataTemplate x:Key="Impact">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="Impact:" />
<ComboBox Grid.Column="1"
ItemsSource="{Binding Impacts}">
</ComboBox>
</Grid>
</DataTemplate>
I then have an ItemsControl define like so in the visual tree:
<ItemsControl ItemsSource="{Binding Path=ViewModelsList}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type ui:FirstViewModel}">
<ContentControl ContentTemplate="{StaticResource Impact}"></ContentControl>
</DataTemplate>
<DataTemplate DataType="{x:Type ui:SecondViewModel}">
<ContentControl ContentTemplate="{StaticResource Impact}"></ContentControl>
...
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
Is there a way to relate that {Binding Impacts} in the resources to the respective ViewModel type defined in DataTemplate's DataType?
Maybe there is a way to pass the DataType to the ContentControl?
Add this to your ContentControls:
Content="{Binding}"

silverlight combobox template binding

I am trying to bind a combobox from a static resource(added on code behind) and add an image beside each item. The best solution I have so far is the following:
<ComboBox x:Name="cmbGroup"
Width="150" Height="32" ItemsSource="{StaticResource Groups}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Source="Question.jpg" Height="30" MouseEnter="Image_MouseEnter" ></Image>
<ComboBoxItem Content="{Binding Source={StaticResource Groups}}" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This is not working, although I can see the image on each item, but instead a text, I got a "Systems.Collection.GenericList". Any ideas how to solve this? Thanks
When you have a control using Binding inside your datatemplate, it is bound to each item in the ItemsSource collection. Also, if you want to display just the string you can use the TextBlock control instead of ComboboxItem. So, if your code looks like:
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Source="Question.jpg" Height="30" MouseEnter="Image_MouseEnter" ></Image>
<TextBlock Text="{Binding}" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I think you will achieve the effect you are looking for.
Hope this helps.
I guess your "Groups" is a a List?
So you configure your template to display an image, and your object Groups by default.
Thus it displays your groups object: ie the toString() of your Groups, which for a List is "Systems.Collection.GenericList".
My guess is that you bind the bad thing? You want to bind an item of your list, which should have a more suitable toString() version.
Let's say you have some Users item in your Groups List. Thus you binding should look like this:
<ComboBox x:Name="cmbGroup"
Width="150" Height="32" ItemsSource="{StaticResource Groups}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Source="Question.jpg" Height="30" MouseEnter="Image_MouseEnter" ></Image>
<ComboBoxItem Content="{Binding Source={StaticResource Users}}" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Hope it helps

How to get selected item value?

How to get ItemsControl display items selected Item textbox text value using MVVM pattern?
<ListBox Margin="0,25,0,0" Grid.Row="3" ItemsSource="{Binding Path=ViewModelSearchResults}" SelectedItem="{Binding Path=SelectedCategoryViewModel, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0" Grid.Column="0" Text="{Binding Path=CategoryName}" FontSize="14" FontWeight="Normal" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=CategoryID}" FontSize="14" FontWeight="Normal" Visibility="Hidden" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
Like getting anything else from Views: bind it! Yes, ItemsControl has SelectedItem but ItemsControl itself doesn't have selection behavior. You should use something like ListBox instead.
You can bind SelectedItem to a property and access the required values through that property.

MVVM Binding in Silverlight3 ItemsControl to get the parent controls DataContext

I have the following ItemsControl in Silverlight 3.
<ItemsControl ItemsSource="{Binding ValueCollectionList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="MyBtn" Height="40" Content="{Binding Name}"
Tag="{Binding Value}"
cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot, Path=ButtonCommand}"
cmd:ButtonBaseExtensions.CommandParameter="{Binding ElementName=MyBtn, Path=Tag}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The Problem is that I have the ItemsControl bound to the Collection in my ViewModel, but I need the button to trigger a command on the ViewModel which is of course not Available in the DataContext of the button since it only contains the collection.
I can make the command fire by setting my ViewModel as a Resource and then binding to it as a StaticResource, but I want to know why the element to element binding won't work in this scenario. I would prefer not to use the StaticResource binding because that requires the default constructor on the ViewModel and so I can't inject my data easily.
UPDATE
I'm working through this slowly... Looking at the suggestions from Peter I realized that I may have more serious binding issues because of my page setup. I have two possible road blocks, but first things first.
My Items control above is wrapped in another items control that is bound to an observable collection. I moved my items control so that its a direct child of the root items control. It was wrapped in another control that I'll get to. So I tried the element binding to the items control ControlItemList, but its a collection so it can't find my ButtonCommand method in that Collection. What I need to do is bind to an item within that collection. How do I bind to a single item within the collection?
<Grid x:Name="LayoutRoot" Background="White"><!-- DataContext="{Binding Path=., Source={StaticResource lvvm}}">-->
<StackPanel Orientation="Vertical">
<ItemsControl x:Name="ControlItemList" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="ControlName" Grid.Column="0" Text="{Binding Name}" VerticalAlignment="Center" />
<ItemsControl ItemsSource="{Binding ValueCollectionList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
So, Assuming I can get the above to work the other road block is that my items control is wrapped in another usercontrol that I'm using to get DataTemplateSelector type functionality. I think this control may be blocking me from getting to the parent DataContext. Is there a limit as to how far up the tree you can go?
<common:DeviceControlTemplateSelector Grid.Column="1" FieldType="{Binding ValueType}" Margin="0,2,0,2">
<common:DeviceControlTemplateSelector.StringTemplate>
<DataTemplate>
<TextBox Text="{Binding Value, Mode=TwoWay}" Width="100"/>
</DataTemplate>
</common:DeviceControlTemplateSelector.StringTemplate>
<common:DeviceControlTemplateSelector.DateTimeTemplate>
<DataTemplate>
<TextBox Text="this is date time binding" Width="100"/>
</DataTemplate>
</common:DeviceControlTemplateSelector.DateTimeTemplate>
<common:DeviceControlTemplateSelector.BooleanTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Value, Mode=TwoWay}" />
</DataTemplate>
</common:DeviceControlTemplateSelector.BooleanTemplate>
<common:DeviceControlTemplateSelector.IntegerTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding ValueCollection}" DisplayMemberPath="Value" SelectedIndex="{Binding Value, Mode=TwoWay}" >
</ComboBox>
</DataTemplate>
</common:DeviceControlTemplateSelector.IntegerTemplate>
<common:DeviceControlTemplateSelector.MultiButtonTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding ValueCollectionList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button x:Name="MyBtn"
Height="40" Content="{Binding Name}"
Tag="{Binding Value}"
cmd:ButtonBaseExtensions.Command="{Binding ElementName=ControlItemList, Path=DataContext.ButtonCommand}"
cmd:ButtonBaseExtensions.CommandParameter="{Binding Value}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</common:DeviceControlTemplateSelector.MultiButtonTemplate>
<Button x:Name="MyBtn"
Height="40" Content="{Binding Name}"
Tag="{Binding Value}"
cmd:ButtonBaseExtensions.Command="{Binding ElementName=ControlItemList, Path=ButtonCommand}"
cmd:ButtonBaseExtensions.CommandParameter="{Binding Value}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Thanks again everyone for your help!
the best solution i have found so far to deal with this situation is by Dan Wahl where he uses a DataContextProxy.
http://weblogs.asp.net/dwahlin/archive/2009/08/20/creating-a-silverlight-datacontext-proxy-to-simplify-data-binding-in-nested-controls.aspx
Try to change
from
cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot, Path=ButtonCommand}"
to
cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot, Path=DataContext.ButtonCommand}"
OR
cmd:ButtonBaseExtensions.Command="{Binding ElementName=LayoutRoot.DataContext, Path=ButtonCommand}"
In MVVM messaging is a strong concept for cummunication between ViewModels. You could use PRISM Eventaggregator or the Messenger class of MVVM Light Toolkit. On the button command you can publish a message and subscribe to it in the viewmodel.

Resources