Caliburn.Micro message bubbling skipping a control - wpf

I've got a hierarchical collection and I lazy load the lowest level because of it's size.
The action I'm trying to activate is on the CollectionHolderManager but it seems that the bubbling skips that visual layer for some reason.
<ItemsControl DataContext="{Binding Path=CollectionHolderManager}"
ItemsSource="{Binding Path=CollectionTopLevel}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<telerik:RadToolBar cal:Bind.Model="{Binding}">
<TextBlock x:Name="Name" />
<ItemsControl ItemsSource="{Binding Path=CollectionMiddleLevel}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<telerik:RadDropDownButton cal:Bind.Model="{Binding}"
Content="{Binding Path=Name}"
cal:Message.Attach="[Event DropDownOpened] = [Action GetLowestLevel($dataContext)]">
<telerik:RadDropDownButton.DropDownContent>
<telerik:RadListBox SelectionMode="Multiple"
ItemsSource="{Binding Path=CollectionLowestLevel}">
<telerik:RadListBox.ItemTemplate>
<DataTemplate>
<!-- some template -->
</DataTemplate>
</telerik:RadListBox.ItemTemplate>
</telerik:RadListBox>
</telerik:RadDropDownButton.DropDownContent>
</telerik:RadDropDownButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</telerik:RadToolBar>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
So if I have the action on the TopLevelCollection it get's called.
If I have it on the ViewModel that owns CollectionHolderManager it get's called, but not when it's on the CollectionHodlerManager itself. Why is it skipping over that?

Such a simple thing I can't believe I missed it.
<ItemsControl cal:Bind.Model="{Binding Path=CollectionHolderManager}"
ItemsSource="{Binding Path=CollectionTopLevel}">
Bind.Model instead of DataContext.

Related

WPF/XAML Intuitive UserControl

what steps must be done to make a user control, to work in such order:
<local:MyUserControl ItemsSource="{Binding Items}">
<local:MyUserControl.Items>
<local:MyUserControl.Item Name="{Binding Name}"/>
</local:MyUserControl.Items>
</local:MyUserControl>
I know that for ItemsSource I need to create DependencyProperty, but what for the part which is inside MyUserControl.
Example:
Look below is an example how I used to do it.
This is called MyUserControl
<UserControl>
<Grid>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}" Margin="3,3,3,3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
MainPage:
<local:MyUserControl />
As you can see in this scenario, MyUserControl is not universal, it can be used properly ONLY if I have ItemsSource called Items, and inside of it there is a property called Name.
My Intention is to create flexible MyUserControl.
Thanks in advance.

Listboxes hierarchy

I have 3 embedded listboxes for entities: group, item, subitem.
<ListBox Name="GroupItemsListBox"
ItemSource="{Binding EntityGroups"}>
<ListBox.ItemTemplate>
<DataTemplate>
<ItemsControl Name="ItemsListBox"
ItemSource="{Binding Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl Name="SubItemsListBox"
ItemSource="{Binding SubItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name} />
</DataTemplate>
</ItemsControl.ItemTemplate>
</DataTemplate>
</ItemsControl.ItemTemplate />
</ItemsControl>
</DataTemplate>
<ListBox.ItemTemplate>
</ListBox>
Also there is a case when last listbox is empty.
I want to handle SelectedItem from the lowest existing ItemControl. So i will be able to manage when the most specific object is selected.
For example when i click on ItemGroup[1].Items[0].SubItem[2] i want to get this element, but not ItemGroup[1] or ItemGroup[1].Items[0].
How can i achieve it?
Use the LongListSelector instead. This supports grouping in a much nicer way.

Bind DataTemplate after Task is finished

I'm looking for a way to bind a datatemplate which is in a resource file that my MainWindow accesses, but only after a Task that is running in the viewmodel has completed.
The idea was to load a lot of data while the view displays with a little progress area... when the progress is done... then the data should be binded... is the dependency property that allows for this?
<DataTemplate x:Key="TabsTemplate">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<UserControls:TabButton Command="{Binding Path=Tab}" Content="{Binding Path=DisplayName}" Template="{Utilities:BindableResource {Binding Path=TemplateResource}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
Figured it out...
Tabs.GetBindingExpression(ContentControl.ContentProperty).UpdateTarget();
Works perfect after the progress is completed.

XAML ~ Need help with the Binding syntax for collection of objects

I am trying to bind a List of objects to an ItemsControl. The object has only two properties: Movie (a string) and Actors (an array of string). I can get the binding to work fine for the Movie. But I can't figure out the binding for the Actors array.
<ItemsControl x:Name="MovieList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Width="100">
<Border Margin="2">
<TextBlock Text="{Binding Movie, Mode=OneWay}" />
</Border>
<ListBox ItemsSource="{Binding Actors, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controlsToolkit:WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Any suggestions?
<ListBox ItemsSource="{Binding Actors, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
this is wrong...you have to tell it what you want to bind to in the actors collection.
{Binding Path=ActorName} for example...since you only have it one way you could use displaymemberpath instead and just go: DisplayMemberPath="ActorName"

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