Подтвердить что ты не робот

Связывание RelativeSource с помощью ToolTip или ContextMenu

Что я делаю неправильно здесь?

 <GridViewColumn>
    <GridViewColumn.CellTemplate>
       <DataTemplate>
          <Button>
            <Button.ToolTip>
              <TextBlock Text="{Binding Path=Title, RelativeSource={RelativeSource AncestorType=Window}}" />

Это просто упрощенный пример, который все равно не работает:) На самом деле мне нужно получить значение из другого свойства, которое находится в пределах окна DataContext.

Помогите мне.

4b9b3361

Ответ 1

Это сложно, потому что ToolTip не является частью VisualTree. Здесь вы видите классное решение для той же проблемы с ContextMenus. Точно так же вы можете обратиться за подсказкой.

UPDATE
К сожалению, ссылка ушла, и я больше не нашел ссылку. Насколько я помню, связанный блог показал, как привязываться к DataContext другого VisualTree, что часто необходимо при связывании с помощью ToolTip, ContextMenu или всплывающего окна.

Хороший способ сделать это - предоставить желаемый экземпляр (например, ViewModel) в свойстве Tag для PlacementTarget. В следующем примере это делается для доступа к Command-экземпляру ViewModel:

<Button Tag="{Binding DataContext,RelativeSource={RelativeSource Mode=Self}}">
  <Button.ContextMenu>
    <ContextMenu>
       <MenuItem Command="{Binding PlacementTarget.Tag.DesiredCommand,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ContextMenu}}" .../>
    <ContextMenu>
  </Button.ContextMenu>
</Button>

Я не тестировал его, и его долгое время я делал это в последний раз. Пожалуйста, сделайте комментарий, если он не работает для вас.

ОБНОВЛЕНИЕ 2

Поскольку исходная ссылка, о которой был написана этот ответ, исчезла, я нажал archive.org и нашел исходную запись в блоге. Вот оно, дословно из блога:

Так как ContextMenu в WPF не существует в визуальном дереве ваша страница/окно/контроль как таковой, привязка данных может быть немного сложной. Для этого я искал высоко и низко в Интернете, и общий ответ кажется "просто сделать это в коде позади". НЕПРАВИЛЬНО! я не пришел в прекрасный мир XAML, чтобы вернуться к делая вещи в коде позади.

Вот мой пример, который позволит вам привязать строку, которая существует как свойство вашего окна.

public partial class Window1 : Window
{
    public Window1()
    {
        MyString = "Here is my string";
    }

    public string MyString
    {
        get;
        set;

    }
}


<Button Content="Test Button" 
     Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
  <Button.ContextMenu>
    <ContextMenu DataContext="{Binding Path=PlacementTarget.Tag, 
          RelativeSource={RelativeSource Self}}" >
      <MenuItem Header="{Binding MyString}"/>
    </ContextMenu>
  </Button.ContextMenu>   
</Button>

Важной частью является тег на кнопке (хотя вы могли бы так же легко установить DataContext кнопки). В нем содержится ссылка на родительское окно. ContextMenu способен к доступу к этому через его свойство PlacementTarget. Затем вы можете передать этот контекст вниз через пункты меню.

Я признаю, что это не самое элегантное решение в мире. Тем не менее, это превосходит настройку в коде позади. Если у кого есть даже лучший способ сделать это Id люблю его слышать.

Ответ 2

Внизу:
PlacementTarget - это элемент управления, которым владеет ContextMenu (например: DataGrid). Не требуется свойство "tag".

IsEnabled привязывается к значению "myProperty" DataGrid.

Я тестировал это, и он работает. Имел аналогичную проблему со связыванием.

<ContextMenu
DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}"
IsEnabled="{Binding myProperty}"  
>

Ответ 3

Поскольку ContextMenu не находится в визуальном дереве, привязка не будет работать. простое решение использует прокси-шаблон, вы можете создать класс-оболочку, который наследует от DependencyObject и имеет DependencyProperty, который сохранит DataContext вашего Window, тогда вы можете иметь ресурс прокси-сервера в XAML и, наконец, привяжите команду MenuItem к вашей желаемой команде через прокси-объект.
Пример прокси:

Public class ProxyClass : DependencyObject
{
    Public object Data {get; set;}
   public static readonly DependencyProperty DataProperty = DependencyProperty.Register("DataProperty", typeof(object), typeof(ProxyClass), new FrameworkPropertyMetadata(null));

}

Как использовать в XAML:

<Window DataContext="{Binding MyViewModel}">
...
<Window.Resources>
    <ProxyClass Data={Binding} x:Key="BindingProxy"/>

</Window.Resources>
...  
<MenuItem Command="{Binding Source={StaticResource BindingProxy}, Path=Data.MyDesiredCommand"/>
...
</Window>

Что происходит?
Data свойство ProxyClass будет привязано к DataContext от Window, тогда у него есть все ваши comamnds и свойства вашего ViewModel внутри ресурса ProxyClass.
Другим преимуществом такого подхода является переносимость и повторное использование в нескольких представлениях и проектах.

Ответ 4

Я думаю, что это должно быть сделано следующим образом:

{Binding Path=Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"