WPF Caliburn.Micro ItemsControl ContextMenu don't find method - c#

I'am really having some problems with the ContextMenu from Caliburn.Micro. No matter what I do, I get the error "Cant' find the method ...".
I've tried this solutions, and that one too, but I can't get this to work.
What I'am doing wrong? Actually, there's a way to debug the view and find out in which Context the control is searching for the respective ViewModel?
And another thing... this View is inside a DataTemplate from another view, does that change anything? All the others bindings are working from the correct ViewModel...
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
Grid.Row="1" Grid.Column="0"
Padding="10,5,15,5"
MaxHeight="390" x:Name="xImages">
<ItemsControl
ItemsSource="{Binding Path=Document.Images}"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Height="110">
<Border Margin="5" BorderBrush="Gainsboro" BorderThickness="1">
<Image Source="{Binding Path=PathThumb}" Width="70" Height="100"> <!-- Tag="{Binding DataContext, ElementName=xImagens}" -->
<Image.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=xImagens}"> <!--PlacementTarget.Tag, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"-->
<MenuItem Header="Ampliar"
cal:Message.Attach="[Event Click] = [Action ExpandImage($datacontext)]"></MenuItem>
<MenuItem Header="Excluir"
cal:Message.Attach="[Event Click] = [Action DeleteImage($datacontext)]"></MenuItem>
</ContextMenu>
</Image.ContextMenu>
</Image>
</Border>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>

cal:Action.TargetWithoutContext="{Binding Source={x:Reference xImagens} , Path=DataContext}">
Because ContextMenu is not part of the VisualTree , you can't bind to elements in the visual tree
of it's TargetPlacement. ( Though in XAML it seems like it is part of it ).
You have two choices:
{Binding Path=PlacementTarget.DataContext}
Or:
{Binding Source={x:Reference xImagens}, Path=DataContext}

give the x:Name="xImages" to the ItemsControl and then do the binding with ElementName to the ContextMenu using the Action.TargetWithoutContext, you had it right but the ScrollViewer isn't what has the Datacontext to the List of data, the ItemControl does since it has the ItemSource.
Was there a reason for naming the ScrollViewer?
<ItemsControl x:Name="xImages">
<ContextMenu Action.TargetWithoutContext="{Binding Path=DataContext, ElementName=xImages}">
<!-- Shortened -->
</ContextMenu>
</ItemsControl>

Related

WPF bind to property of the ItemsPanel of an ItemsControl

I've written a code example below:
<StackPanel>
<TextBlock>Appointments today</TextBlock>
<ItemsControl ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:CalendarMonthDayEventsItemsPanel OutsideViewportCount="..." />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border>
<TextBlock Text="{Binding Title}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ......}" /> <!-- Should show number of items in ItemsControl that are outside view, using CalendarMonthDayEventsItemsPanel.OutsideViewportCount -->
<TextBlock>more items</TextBlock>
</StackPanel>
</StackPanel>
I Created a custom Panel, the CalendarMonthDayEventsItemsPanel, and I use that panel as the itemspanel of the ItemsControl. In the panel's layout code, I determine how many items (panel childs) are outside the bounds of the panel. The property OutsideViewportCount contains the number of items that are outside of the visible bounds of the CalendarMonthDayEventsItemsPanel.
Now I want to show the value of OutsideViewportCount in a TextBlock that's below the ItemsControl.
This means I have to create some kind of binding, but everything I tried doesn't work.
Does someone have a solution or a better approach to achieve the same result?
Maybe you can make use of Tag property of ItemsPanel to relay the value of ItemsPanel as a workaround.
<ItemsControl x:Name="A"
ItemsSource="{Binding Appointments}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:CalendarMonthDayEventsItemsPanel OutsideViewportCount="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=Tag, Mode=OneWayToSource}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
...
</ItemsControl>
<StackPanel Orientation="Horizontal">
<TextBlock>+</TextBlock>
<TextBlock Text="{Binding ElementName=A, Path=Tag, Mode=OneWay}"/>
<TextBlock>more items</TextBlock>
</StackPanel>

Getting ContextMenu target from Item in ItemsControl

I have an ItemsControl bound to a collection on my ViewModel. This ItemsControl presents several "Messages". I need a ContextMenu that, when clicked, provides an option to Copy that particular message to the clipboard.
The Command should activate on the ViewModel and the CommandParameter I want to pass is the Message itself.
The problem I'm having is getting the actual message that the ContextMenu has been opened OVER.
I've tried mutliple different approaches, but I cannot seem to figure out a way to pass the message as the Command's parameter.
Should I look for a different approach to accomplish this? Is the issue using an ItemsControl with an ItemsPresenter?
<ScrollViewer CanContentScroll="False"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
Grid.RowSpan="1">
<ItemsControl ItemsSource="{Binding MyActiveConversation.OrderedMessages, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding MyActiveConversation.IsOptOut, Converter={StaticResource BoolToEnabledInverter}}"
ItemTemplateSelector="{StaticResource tSelector}"
VirtualizingPanel.IsVirtualizing="False"
SourceUpdated="SourceUpdatedHandler" MinWidth="450">
<ItemsControl.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy" Template="{DynamicResource MenuItemControlTemplate}"
CommandParameter="{Binding}" Command="{Binding Path=Data.CopyTextMessageCommand, Source={StaticResource ContextProxy}}">
</MenuItem>
</ContextMenu>
</ItemsControl.ContextMenu>
<ItemsControl.Template>
<ControlTemplate>
<Grid>
<ItemsPresenter VirtualizingPanel.IsVirtualizing="False"/>
</Grid>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
CommandParameter="{Binding}" works good for me, same for CommandParameter="{Binding .}"

Can a DataTemplate be placed inside another DataTemplate of different Template Structure?

I want a DataTemplate for ListBox having the ItemsSource as Collection of Borders. Inside each Border i want to display another ListBox containg set of some items having its own ItemsSource.
But, when i try to acheive this structure i am not able to populate any data.
My XAML code -
<Grid x:Name="RightPanel" Grid.Column="2" Background="Beige">
<Border BorderBrush="Black" Margin="4" BorderThickness="1.5">
<ScrollViewer Margin="2" Focusable="False">
<ListBox x:Name="MainRightListBox" ItemsSource="{Binding ListBoxCollection,Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBox x:Name="ChildListBox" ItemsSource="{Binding CurrentPage.ClonedVectorImages,Mode=TwoWay}" SelectedItem="{Binding ImageVectorSelected}" BorderBrush="Transparent" Background="Transparent">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="canvas" Background="Transparent" Orientation="Horizontal" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}, Mode=FindAncestor}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Delete" CommandParameter="{Binding}"
Command="{Binding PlacementTarget.Tag.DataContext.DeleteCloneCommand, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}, Mode=FindAncestor}}"/>
</ContextMenu>
</StackPanel.ContextMenu>
<Viewbox Width="35" Height="35" >
<Canvas Width="35" Height="35">
<Canvas>
<Path Fill="#ffda2526" Data="F1 M 0.000,112.500 C 0.000,50.369 50.368,0.000 112.500,0.000 C 174.632,0.000 225.000,50.369 225.000,112.500 C 225.000,174.633 174.632,225.000 112.500,225.000 C 50.368,225.000 0.000,174.633 0.000,112.500 Z" Height="30.667" Stretch="Fill" Width="31"/>
<TextBlock x:Name="tb1" Text="{Binding CountId}" Foreground="WhiteSmoke" FontSize="20" FontFamily="Arial Bold" Height="20" RenderTransformOrigin="1.588,1.224" Canvas.Left="9.322" Canvas.Top="3.335"></TextBlock>
</Canvas>
</Canvas>
</Viewbox>
<TextBox Text="Enter Text Here" Height="20" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Border>
</Grid>
"Can a DataTemplate be placed inside another DataTemplate of different Template Structure?"
The answer is yes, it can. Your XAML structure is fine.
But what possibly wrong is binding path/expression used. You need to be aware that DataContext of the inner ListBox (the one inside DataTemplate) is corresponding item in ListBoxCollection. So if that item mentioned before has property CurrentPage.ClonedVectorImages, this way of binding should work fine to populate the inner ListBox :
<ListBox x:Name="ChildListBox"
ItemsSource="{Binding CurrentPage.ClonedVectorImages,Mode=TwoWay}"
........>
You need to put DataTemplates in resources with the corresponding keys, because otherwise an exception may occur:
Markup.IStyle.Connector.Connect error
This is bug of studio, which is described as follows link:
A good way to look at this problem “Templating is like parentheses, quoting parentheses” the Template XAML is not created but saved and run later. The bug is therefore: We have a problem with nested parentheses.
In any case as I think, should be avoided nesting templates and use him via resources, it will be easier and clearer.

How can i bind a button in listviewitem to a Command in ViewModel in Winrt

I have a NavigateToAccountsCommand RelayCommand property in the ViewModel. When I bind the same to a button on the page anywhere outside the ListView the command binding is working. However as soon as I move this to a ListView's DataTemplate its not working.
I have tried changing the binding from NavigateToAccountsCommand to DataContext.NavigateToAccountsCommand still not working.
Appreciate your help...
<Page
x:Class="FinancePRO.App.Views.AccountsView"
DataContext="{Binding AccountsViewModel, Source={StaticResource MainViewModelLocator}}"
mc:Ignorable="d">
<Grid>
<!--**This one is working**-->
<Button Command="{Binding NavigateToAccountsCommand}" >
<!--**This one is not working**-->
<ListView ItemsSource="{Binding AllAccounts}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding AccountName}"/>
<Button Command="{Binding NavigateToAccountsCommand}">
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
When you are inside the DataTemplate of the ListView, your data context is the current item of the ListView's ItemsSource. As there is nothing called "NavigateToAccountsCommand" property within your AllAcounts' each individual element, binding isn't working.
To fix that, you will need to reference something from the outside of DataTemplate; following should work. It changes the binding to reference the root Grid's DataContext which should have the property NavigateToAccountsCommand accessible. To reference the grid, you have to add Name attribute, and then use ElementName binding.
<Grid Name="Root">
<!--**This one is working**-->
<Button Command="{Binding NavigateToAccountsCommand}" >
<!--**This one is not working**-->
<ListView ItemsSource="{Binding AllAccounts}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel HorizontalAlignment="Stretch">
<TextBlock Text="{Binding AccountName}"/>
<Button Command"{Binding ElementName=Root, Path=DataContext.NavigateToAccountsCommand}">
</Button>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
You can use
<Button x:Name="cmdTabItemCloseButton"
Style="{StaticResource TabItemCloseButtonStyle}"
Grid.Column="1" Margin="15,0,0,0"
Command="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ListView}},
Path=DataContext.NavigateToAccountsCommand}"
CommandParameter="{Binding}"/>
I had a similar problem (Win RT) which I solved by just using:
<GridView
x:Name="itemGridView"
ItemClick="ItemView_ItemClick"
IsItemClickEnabled="True"/>
and then in the Page class:
private void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
//e is the object being clicked
}

how to bind a command from DataContext of Page to a list item

I have a Page and a viewmodel is set as its datacontext. in that page I have a list. which is populating through a property in the viewmodel. List has a user control. and that user control has a button. I want that button to be bind with a command that is in viewmodel. Is there anyway to do that?
<Page DataContext=PageViewModel>
...
<ScrollViewer Grid.Row="3" Margin="20,0" Visibility="{Binding ByVenueSelected, Converter={StaticResource BooleanToVisibilityConverter}}">
<StackPanel>
<ItemsControl ItemsSource="{Binding EventsListByVenue}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<myControls:EventDetails /> <!--in this control i want to bind a command available in PageViewModel-->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
...
</Page>
with help of #FunksMaName, I solved this. I am sure there are more elegant and better approach, but yet this is a quick & easy solution for me:
<Button Style="{StaticResource NoHighlightButtonStyle}" Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}" Visibility="{Binding link,Converter={StaticResource DataAvailabilityToVisibilityConverter}}" Command="{Binding Path=Event.LinkCommand,Source={StaticResource Locator}}" >
<TextBlock Margin="0,5" Foreground="SkyBlue" Text="{Binding link}" TextWrapping="Wrap" FontSize="16"/>
</Button>
things to note:
i think xaml searched the command parameter in context of command only, so it was giving me null parameter, while the same binding was working fine for textblock inside Button. So i tricked it to store the value in tag, and used it from there.
Tag="{Binding link}" CommandParameter="{Binding Path=Tag,RelativeSource={RelativeSource Mode=Self}}"

Categories