Sybren Sybren - 1 month ago 43
C# Question

Caliburn Micro TabItem click event no target found for method

I'm using Caliburn Micro to call a method in my ViewModel from a MenuItem in my View. But every time when I click the MenuItem I get the exception: no target found for method SuggestPresent. I tried different ways of calling my ViewModel method but nothing worked so far. How can I make it work?

MainView.xaml

<Controls:MetroWindow x:Class="Expreriment.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="clr-namespace:Expreriment.ViewModels"
xmlns:vc="clr-namespace:Expreriment.Converters"
xmlns:local="clr-namespace:Expreriment"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:cal="http://www.caliburnproject.org"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DataContext="{x:Type model:MainViewModel}"
Title="{Binding WindowTitle}"
x:Name="Window"
Height="500" Width="800">

<Controls:MetroWindow.Resources>
<vc:FindResourceFromString x:Key="FindResourceFromStringConverter" />
</Controls:MetroWindow.Resources>

<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<Controls:Flyout Header="Menu" Position="Left" Width="175" IsOpen="True" Name="menuFlyout" Grid.Column="0">
<Menu ItemsSource="{Binding enumData}" DisplayMemberPath="Enum">
<Menu.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</Menu.ItemsPanel>
<MenuItem Header="Category" ItemsSource="{Binding EnumData}" DisplayMemberPath="Enum">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable" Value="True"/>
<Setter Property="IsChecked" Value="{Binding IsChecked, Mode=TwoWay}"/>
<Setter Property="StaysOpenOnClick" Value="True"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
<MenuItem cal:Action.TargetWithoutContext="{Binding ElementName=Window, Path=Datacontext}" cal:Message.Attach="SuggestPresent" Header="Suggest present">
<MenuItem.Icon>
<Image Height="25" Width="25" Source="/Resources/Images/Plus.png"/>
</MenuItem.Icon>
</MenuItem>
</Menu>
</Controls:Flyout>

<Controls:FlipView Grid.Column="1" ItemsSource="{Binding Gifts}" SelectedItem="{Binding Path=SelectedGift, Mode=TwoWay}" BannerText="{Binding SelectedGift.Name}">
<Controls:FlipView.ItemTemplate>
<DataTemplate>
<Grid Background="#2E8DEF">
<Rectangle Margin="0, 0, 10, 0" Width="100" Height="100">
<Rectangle.Fill>
<VisualBrush Visual="{Binding Icon, Converter={StaticResource FindResourceFromStringConverter}}" />
</Rectangle.Fill>
</Rectangle>
</Grid>
</DataTemplate>
</Controls:FlipView.ItemTemplate>
</Controls:FlipView>
</Grid>




MainViewModel.cs

using Caliburn.Micro;
using Expreriment.Model;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel.Composition;
using System.Linq;

namespace Expreriment.ViewModels
{
[Export(typeof(MainViewModel))]
public class MainViewModel : PropertyChangedBase
{
//added
private readonly IWindowManager _windowManager;

[ImportingConstructor]
public MainViewModel(IWindowManager windowManager)
{
_windowManager = windowManager;
}

private void SuggestPresent()
{
_windowManager.ShowWindow(new SuggestPresentViewModel(_windowManager));
}
//end

private const string WindowTitleDefault = "Present Presenter";

private string _windowTitle = WindowTitleDefault;

public string WindowTitle
{
get { return _windowTitle; }
set
{
_windowTitle = value;
NotifyOfPropertyChange(() => WindowTitle);
}
}

public ObservableCollection<EnumData> _enumData = new ObservableCollection<EnumData>(Enum.GetNames(typeof(CategoryType)).Select(s => new EnumData { Enum = s, IsChecked = false }));
public ObservableCollection<EnumData> EnumData
{
get { return _enumData; }
set
{
_enumData = value;
NotifyOfPropertyChange(() => EnumData);
}
}

public ObservableCollection<Gift> _gifts = new ObservableCollection<Gift>(GiftAction.GetGifts());

public ObservableCollection<Gift> Gifts
{
get { return _gifts; }
set
{
_gifts = value;
NotifyOfPropertyChange(() => Gifts);
}
}

public Gift _selectedGift = new Gift();
public Gift SelectedGift
{
get { return _selectedGift; }
set
{
_selectedGift = value;
NotifyOfPropertyChange(() => SelectedGift);
}
}
}
}


I tried the following lines without success:

"SuggestPresent($orignalsourcecontext)"

cal:Message.Attach="SuggestPresent()" cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"

cal:Action.TargetWithoutContext="{Binding ElementName=Window, Path=Datacontext}" cal:Message.Attach="SuggestPresent"

Answer

The method SuggestPresent needs to be public. It is currently private based on the example provided. The framework searches for public methods and properties when binding to the view model.

public void SuggestPresent()
{
    _windowManager.ShowWindow(new SuggestPresentViewModel(_windowManager));
}