【问题标题】:Outside Property inside a DataTemplate WPFDataTemplate WPF 中的外部属性
【发布时间】:2010-10-16 17:20:42
【问题描述】:

场景:我有一个 ListBox,而 ListBoxItems 有一个 DataTemplate。我想要做的是在 DataTemplate 中放置一个 ContextMenu。问题是我希望这个 ContextMenu ItemsSource 根据窗口中的某些属性而有所不同。我最初的想法是我可以将 ItemsSource 绑定到窗口中的一个属性,然后返回一个 ItemsSource;但是,我似乎无法正确绑定到此属性。我相信这是因为我在 DataTemplate 中,因此 DataContext(我相信这是正确的词)属于那个 ListBoxItem 而不是窗口。 如何让 DataTemplate 中的 ContextMenu 绑定到 DataTemplate 之外的属性。

【问题讨论】:

    标签: wpf .net-3.5 properties datatemplate


    【解决方案1】:

    您可以使用 RelativeSource FindAncestor 语法从窗口中获取 DataContext

    <DataTemplate>
      <TextBlock Text="{Binding MyInfo}">
        <TextBlock.ContextMenu>
          <Menu ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.MyContextMenuItems}"/>
        </TextBlock.ContextMenu>
      </TextBlock>
    </DataTemplate>
    

    不完全确定,但绑定是正确的... 如果您的 DataContext 是另一个对象类型,您只需更改 AncestorType(例如通过 UserControl)。

    【讨论】:

      【解决方案2】:

      这可能是AttachedProperty 的良好候选者。基本上,您要做的是将 ContextMenu 包装在 UserControl 中,然后将 Dependency Property 添加到 UserControl。例如:

      MyContextMenu.xaml

      <UserControl x:Class="MyContextMenu" ...>
        <UserControl.Template>
          <ContextMenu ItemSource="{Binding}" />
        </UserControl.Template>
      </UserControl>
      

      MyContextMenu.xaml.cs

      public static readonly DependencyProperty MenuItemsSourceProperty = DependencyProperty.RegisterAttached(
        "MenuItemsSource",
        typeof(Object),
        typeof(MyContextMenu),
        new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)
      );
      public static void SetMenuItemsSource(UIElement element, Boolean value)
      {
        element.SetValue(MenuItemsSourceProperty, value);
        // assuming you want to change the context menu when the mouse is over an element.
        // use can use other events.  ie right mouse button down if its a right click menu.
        // you may see a perf hit as your changing the datacontext on every mousenter.
        element.MouseEnter += (s, e) => {
          // find your ContextMenu and set the DataContext to value
          var window = element.GetRoot();
          var menu = window.GetVisuals().OfType<MyContextMenu>().FirstOrDefault();
          if (menu != null)
            menu.DataContext = value;
        }
      }
      public static Object GetMenuItemsSource(UIElement element)
      {
        return element.GetValue(MenuItemsSourceProperty);
      }
      

      Window1.xaml

      <Window ...>
        <Window.Resources>
          <DataTemplate TargetType="ListViewItem">
            <Border MyContextMenu.MenuItemsSource="{Binding Orders}">
              <!-- Others -->
            <Border>
          </DataTemplate>
        </Window.Resources>
        <local:MyContextMenu />
        <Button MyContextMenu.MenuItemsSource="{StaticResource buttonItems}" />
        <ListView ... />
      </Window>
      

      VisualTreeHelpers

      public static IEnumerable<DependencyObject> GetVisuals(this DependencyObject root)
      {
          int count = VisualTreeHelper.GetChildrenCount(root);
          for (int i = 0; i < count; i++)
          {
              var child = VisualTreeHelper.GetChild(root, i);
              yield return child;
              foreach (var descendants in child.GetVisuals())
              {
                  yield return descendants;
              }
          }
      }
      
      public static DependencyObject GetRoot(this DependencyObject child)
      {
          var parent = VisualTreeHelper.GetParent(child)
          if (parent == null)
            return child;
          return parent.GetRoot();
      }
      

      这个例子未经测试,今晚稍后我会看看并确保它准确。

      【讨论】:

        猜你喜欢
        • 2015-09-09
        • 2012-04-11
        • 1970-01-01
        • 1970-01-01
        • 2011-03-08
        • 1970-01-01
        • 2010-11-25
        • 2018-04-26
        • 2019-03-02
        相关资源
        最近更新 更多