Добрый день,
У меня есть очень распространенная проблема. У меня есть пользовательский элемент управления, который имеет модель представления в качестве контекста данных. Элементы в этом пользовательском элементе управления затем используют эту ViewModel для привязки и т. Д.
The ViewModel
public class TicketDetailsViewModel : ViewModelBase
{
public DelegateCommand<object> HideSelectedText { get; private set; }
private Ticket _ticket;
public Ticket Ticket
{
get { return _ticket; }
set
{
_ticket = value;
this.RaisePropertyChanged(p => p.Ticket);
}
}
}
Моя ViewModel содержит один объект Ticket. К этому объекту заявки прикреплена коллекция комментариев, которые передаются в пользовательский элемент управления Ticket Display с использованием ItemsControl
<ItemsControl ItemsSource="{Binding Path=Ticket.Comments}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border CornerRadius="15" Background="{Binding Path=CommentType, ConverterParameter=CommentType, Converter={StaticResource ResourceKey=commentColorConverter}}" Padding="10" Margin="40,10,40,0">
<TextBox x:Name="tbComment" Text="{Binding CommentText}" IsReadOnly="True">
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Spam" Command="{Binding Path=DataContext.HideSelectedText,RelativeSource={RelativeSource Mode=FindAncestor, AncestorLevel=1, AncestorType={x:Type UserControl} }}">
</MenuItem>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Вы заметите, что к каждому TextBox, отображаемому этим ItemsControl, прикреплено ContextMenu. То, что я пытаюсь сделать, это связать команду этого ContextMenuItem с DelegateCommand в моей ViewModel. Конечно, просто используя;
<MenuItem Header="Spam" Command="{Binding HideSelectedText}">
Мы не получаем ничего полезного, так как «Binding» в этом контексте равен Ticket.Comment и, следовательно, не имеет представления о том, что на самом деле представляет собой HideSelectedText.
Похоже, много вопросов, похожих на этот, и все ответы, похоже, отклоняются от решения RelativeSource. Как вы можете видеть в моем исходном коде XAML, я попробовал это, а также многие другие его версии (с набором AncestorLevel и без него, с AncestorType = {x: Type ItemsControl}, AncestorType = {x: Type Window}, AncestorType = {x: Type DataTemplate} и т. Д.) И ALL выдают ошибку вывода, аналогичную;
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.UserControl', AncestorLevel='1''. BindingExpression:Path=DataContext.HideSelectedText; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')
или
System.Windows.Data Error: 40 : BindingExpression path error: 'HideSelectedText' property not found on 'object' ''TicketComment' (HashCode=49290260)'. BindingExpression:Path=DataContext.HideSelectedText; DataItem='ContextMenu' (Name=''); target element is 'MenuItem' (Name=''); target property is 'Command' (type 'ICommand')
Так почему же это решение работает для стольких людей, и все же для меня нет никакой разницы, чем просто набирать {Binding HideSelectedText}
?