Микро-сообщение WPF Caliburn. Не всплывает через HierarchicalDataTemplate - PullRequest
2 голосов
/ 11 марта 2019

Я пытаюсь подключить кнопку удаления в TreeView, чтобы она вызывала метод Remove в его непосредственной родительской модели просмотра.

enter image description here

Я получаю это исключение: System.Exception: 'No target found for method Remove.' при нажатии кнопки Удалить.

Если я переместу метод Remove с B_ViewModel на SomeViewModel, он будет вызван, но я бы предпочел не реализовывать его таким образом.

Как я могу сказать Message.Attach всплывать к его непосредственному родителю?

Вот SomeView.xaml:

<TreeView ItemsSource="{Binding As}">
<TreeView.Resources>
    <HierarchicalDataTemplate DataType="{x:Type vm:A_ViewModel}"
                                ItemsSource="{Binding Bs}">
        <TextBlock Text="{Binding AName}"  />
    </HierarchicalDataTemplate>
    <HierarchicalDataTemplate DataType="{x:Type vm:B_ViewModel}"
                                ItemsSource="{Binding Cs}">
        <TextBlock Text="{Binding BName}"  />
    </HierarchicalDataTemplate>
    <DataTemplate DataType="{x:Type vm:C_ViewModel}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding CName}"  />
            <Button Margin="2" 
                        cal:Message.Attach="Remove($dataContext)" 
                    Content="Delete"/>
        </StackPanel>
    </DataTemplate>
</TreeView.Resources>
<TreeView.ItemContainerStyle>
    <Style TargetType="TreeViewItem">
        <Setter Property="IsExpanded" Value="True" />
    </Style>
</TreeView.ItemContainerStyle>

Вот мои модели:

public class SomeViewModel: Screen
{
    public BindableCollection<A_ViewModel> As { get; private set; } 
        = new BindableCollection<A_ViewModel>();
    public SomeViewModel()
    {
        var a = new A_ViewModel() { AName = "A1" };
        var b = new B_ViewModel() { BName = "B1" };
        b.Cs.Add(new C_ViewModel() { CName = "C1" });
        b.Cs.Add(new C_ViewModel() { CName = "C2" });
        a.Bs.Add(b);
        this.As.Add(a);
    }
}
public class A_ViewModel: PropertyChangedBase
{
    public BindableCollection<B_ViewModel> Bs { get; private set; } 
        = new BindableCollection<B_ViewModel>();
    public A_ViewModel()
    {
    }
    private string _aName;

    public string AName
    {
        get { return _aName; }
        set { Set(ref _aName, value); }
    }
}
public class B_ViewModel : PropertyChangedBase
{
    public BindableCollection<C_ViewModel> Cs { get; private set; } 
        = new BindableCollection<C_ViewModel>();
    private string _bName;
    public string BName
    {
        get { return _bName; }
        set { Set(ref _bName, value); }
    }
    public void Remove(C_ViewModel c)
    {
        if (this.Cs.Contains(c))
            this.Cs.Remove(c);
        else
            Debug.Print(c.CName + " not found");
    }
}
public class C_ViewModel : PropertyChangedBase
{
    private string _cName;
    public string CName
    {
        get { return _cName; }
        set { Set(ref _cName, value); }
    }
}

1 Ответ

1 голос
/ 11 марта 2019

Вы можете использовать cal:Action.TargetWithoutContext присоединенное свойство, чтобы установить DataContext для Button на родительский B_ViewModel:

<DataTemplate DataType="{x:Type vm:C_ViewModel}">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding CName}"  />
        <Button Margin="2"
                cal:Action.TargetWithoutContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=TreeViewItem, AncestorLevel=2}}"
                cal:Message.Attach="Remove($dataContext)" 
                Content="Delete"/>
    </StackPanel>
</DataTemplate>
...