I have a RadGridView with a GridViewToggleRowDetailsColumn, which can expand a selected item and show more Details. I want to use CaliburnMicro to Display the DetailsView, so I add a property of the DetailsViewModel to my "MainViewModel" and add a ContentControl with a Binding to it.
<telerik:RadGridView ItemsSource="{Binding Products.View}"
SelectedItem="{Binding SelectedProduct}" ... >
<telerik:RadGridView.RowDetailsTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding ProductDetailsViewModel}" />
</DataTemplate>
</telerik:RadGridView.RowDetailsTemplate>
<telerik:RadGridView.Columns>
<telerik:GridViewToggleRowDetailsColumn />
...Columndefinitions...
<telerik:RadGridView.Columns>
</telerik:RadGridView>
The problem is, that the Details are not displayed. From here I read that the binding fails because of the ItemsSource. So i tried
<ContentControl cal:View.Model="{Binding ProductDetailsViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}}" />
but it still does not work.
If the ProductDetailsViewModel property is the defined in the same class as the Products property that the RadGridView is bound to, try this:
<ContentControl cal:View.Model="{Binding DataContext.ProductDetailsViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType=telerik:RadGridView}}" />
Related
I'm creating a custom control that has an ItemsSource and DisplayMemberPath properties, and in the ControlTemplate there's a ListBox control that's bound to this ItemsSourse, I want to use the property specified by DisplayMemberPath in this ListBox, unfortunately this doesn't work:
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisplayMemberPath}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT
As Mike Strobel suggested in the comment and as I read in some blog posts, I removed the ItemTemplate and provided only the DisplayMemberPath in the ListBox but this doesn't even bint to the list (there's no scroll bar):
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsSource}"
DisplayMemberPath="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisplayMemberPath}"/>
I even hard-coded the DisplayMemberPath value and still not working!, it's only working with List<string> not List<CustomClass>
Solution
Pardon, I missed changing the DP type from IEnumerable<string> to IEnumerable<object>
Thanks for the help!
Could it be that the TemplatedParent object isn't what you think it is? Have you tried traversing back by specified type?
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ItemsSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type **TYPE**}}, Path=DisplayMemberPath}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have a ContextMenu in a ResourceDictionary. The ContextMenu should hide or show depending on the value of a view-model property, but it does not work.
This is my XAML code (ControlBase derives from UserControl):
<control1:ControlBase>
<UserControl.Resources>
<ResourceDictionary>
<HierarchicalDataTemplate ItemsSource="{Binding InfraNetworkItems}">
<StackPanel>
<StackPanel.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}}">
<MenuItem Header="Delete"
Visibility="{Binding
DataContext.MyViewModel.DeleteEnabled,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=control1:ControlBase},
Converter={StaticResource
BooleanVisibilityConverter}}" />
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</HierarchicalDataTemplate>
</ResourceDictionary>
</UserControl.Resources>
</control1:ControlBase>
DeleteEnabled is a bool property on the view-model.
My previous attempts of solving the problem are based on this assumptions:
The ContextMenu is inside a HierarchicalDataTemplate which has the ItemsSource set. My property is not a member of this ItemSource, it belongs to the view-model. Therefore I've tried this line of code, but without any effect:
Visibility="{Binding DataContext.MyViewModel.DeleteEnabled,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=control1:ControlBase},
Converter={StaticResource BooleanVisibilityConverter}}"
But if I copy the DeleteEnabled property from the view-model to the ItemSource object, it works:
Visibility="{Binding DeleteEnabled, Converter={StaticResource BooleanVisibilityConverter}}"
what is the DataContext of your view? If it's an instance of MyViewModel you have to change the path of your Binding.
Please try this one:
<Visibility="{Binding DataContext.DeleteEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=control1:ControlBase}, Converter={StaticResource BooleanVisibilityConverter}}" />
With setting the path to DataContext you already have access to your viewmodel and of course to the DeleteEnabled-Property.
Hope this helps.
I have an itemscontrol that is bound to a collection of objects.
in the data template, i bind an action that is to be used by all of the controls created if their focus is lost.
In the control, there is a textbox so if there are 1 items in the item controls ItemSource, there will be 2 textboxes.
Now, if Textbox 1 has focus and I click somewhere besides Textbox 2, the action is executed once (because the focus was lost). But if I click in Textbox 2, the action is executed twice. Why?
<ItemsControl Grid.Row="1" Margin="0,5,0,5" ItemsSource="{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=Collection}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type ct:CollectionItem}">
<cc:TestControl
ValueChangedAction="{Binding
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Window}}, Path=ValueChangedAction}"
VerticalAlignment="Center" HorizontalAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is the Control.
<ewt:DecimalUpDown Tag="{Binding Uid}" Grid.Row="0" Grid.Column="3"
HorizontalAlignment="Stretch" TextAlignment="Left" Margin="10,5,10,5"
FormatString="C2" ShowButtonSpinner="False" VerticalAlignment="Center"
Value="{Binding Value}" LostFocus="DecimalUpDown_LostFocus" />
The bound action is executed in this event handler.
If your action is supposed to update the source of the binding (e.g. the Window, it looks like from your example), you might want to try adding OneWayToSource to your Binding so that binding only occurs one way—from the textbox to whatever it's bound to.
I have a problem with extended selection in ListBox. Let's say I have a ListBox with 10 items and I'm selecting first 5 of them using Shift button. The SelectionChanged event is fired with 5 items. After that I want to select 3 items from those 5, again with Shift button pressed, but SelectionChanged event is not fired. How can I react to the second selection of items, when I'm selecting 3 of those 5 previously selected ones?
can you show the xaml code as well I would like to see what your binding looks like
it should looks something like this.. but I can't be certain unless I see your code
In Command binding you have used binding which has relative source binding...
consider making these changes in binding
1) using list box as Ancestortype
2) While binding use Path=DataContext.SelectionChangedCommand otherwise it will take list box as datacontext.
<catel:EventToCommand Command="{Binding Path=DataContext.SelectionChangedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" DisableAssociatedObjectOnCannotExecute="False" PassEventArgsToCommand="True" />
here is an example of what the XAML would look like for ListBoxItem Template
<Grid>
<StackPanel Orientation="Horizontal">
<Label Width="180">Field1</Label>
<ListBox Height="200"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding List1, Mode=OneWay}"
Name="listBox1"
SelectionMode="Single"
Width="300">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="290">
<TextBlock Width="90" Text="{Binding}"></TextBlock>
<ComboBox Width="180" ItemsSource="{Binding DataContext.List2, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" DisplayMemberPath="Field1">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<catel:EventToCommand Command="{Binding Path=DataContext.SelectionChangedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" DisableAssociatedObjectOnCannotExecute="False" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
I've a ListView bound to an ObservableCollection<Foo>. On selecting a ListViewItem I display the details of the SelectedItem(Foo members) in a container. It works fine.
Now all I want is to display the details just next to the SelectedItem. ie, If I select the fourth ListViewItem then the Container's Top should be the same as the ListViewItem's Top. How would I sync their position provided it should create any problem even while scrolling the List.
P.S: Scrollbars are hidden
This question is not yet resolved. Can anybody help?
Original Answer
Does the detail need to be in a separate container? I may be misunderstanding your example, but I would have thought you could achieve what you wanted by adding the details section to the item template for your list items and then hiding/showing it based on the IsSelected flag:
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<ContentControl DockPanel.Dock="Right" Name="DetailsControl" Content="{Binding}" ContentTemplate="{StaticResource DetailsTemplate}" />
<TextBlock Text="{Binding}" />
</DockPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}" Value="False">
<Setter TargetName="DetailsControl" Property="Visibility" Value="Hidden" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Even if you aren't after exactly this behaviour, I imagine you could get close to what you want by replacing the ContentControl from the example with something else (e.g. a Popup)
Edit in response to comments
The example below will place a Popup to the right hand side of the ListView that is visible only for the selected item:
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<DockPanel>
<TextBlock Text="{Binding}" />
<Popup Placement="Right"
PlacementTarget="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}"
IsOpen="{Binding (ListViewItem.IsSelected), RelativeSource={RelativeSource FindAncestor, AncestorType=ListViewItem}}">
<Border Background="Black" Padding="3">
<TextBlock Text="{Binding}" />
</Border>
</Popup>
</DockPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This uses the Placement attribute to specify that the Popup should appear to the right of the target element, and binds the PlacementTarget property to the first ancestor of type ListViewItem (i.e. the parent container).
This causes an appearance like the example below: