【问题标题】:In WPF, how to display AdornerLayer on top of DataGrid在 WPF 中,如何在 DataGrid 之上显示 AdornerLayer
【发布时间】:2011-08-01 12:02:27
【问题描述】:

我正在使用来自 codeplex 的 WPF 数据网格。我正在使用 DatagridTemplateColumn,并且我已经编写了数据模板来显示每列中的内容。

现在我必须在数据网格中的任何控件被聚焦时向用户显示一些帮助消息。 为此,我想到了使用装饰层。我使用了 ComboBox 加载事件并访问了它的 adrorner 层。然后我添加了我自己的装饰层,其中显示了一些类似于工具提示的东西。下面是代码。

        TextBox txtBox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
        if (txtBox == null)
            return;

        txtBox.ToolTip = comboBox.ToolTip;
        AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(txtBox);
        Binding bind = new Binding("IsKeyboardFocused");
        bind.Converter = new KeyToVisibilityConverter();
        bind.Source = txtBox;
        bind.Mode = BindingMode.OneWay;
        PEAdornerControl adorner = new PEAdornerControl(txtBox);
        adorner.SetBinding(PEAdornerControl.VisibilityProperty, bind);

PEAdorner 层是这个 ::

  public class PEAdornerControl : Adorner
  {
    Rect rect;

    // base class constructor.
    public PEAdornerControl(UIElement adornedElement)
        : base(adornedElement)
    { }

    protected override void OnRender(DrawingContext drawingContext)
    {
          .....
    }
  }

现在问题如下。我附上了它在数据网格中的外观的屏幕截图。如果数据网格有超过 4 行,一切都很好。下面是截图

如果数据网格的行数较少,则此装饰器进入数据网格内部并且对用户不可见。截图如下

如何在 DataGrid 上方获得这个装饰层?请帮帮我!!!

【问题讨论】:

  • 如果我没记错的话,并不是装饰器进入数据网格内部,而是数据网格的大小不够大,无法正确显示装饰器。这是由于父级的 OnMesaure 方法没有考虑到 adnorner 层。您可能需要考虑创建自己的父容器来考虑这一点,或者(更有可能)将装饰器附加到包含父装饰器层。
  • @JMcCarty -- 我明白了。但我很抱歉地说我无法理解你在最后两行中想说什么。您能否发布一些示例代码或者可能是一个链接以帮助我理解?

标签: wpf datagrid z-order adornerlayer


【解决方案1】:

我再次查看了您的问题,我认为这就是您所需要的。

    TextBox txtBox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
    if (txtBox == null)
        return;

    txtBox.ToolTip = comboBox.ToolTip;

    //this is locating the DataGrid that contains the textbox
    DataGrid parent = FindParent<DataGrid>(this);

    //Get the adorner for the parent
    AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(parent);
    Binding bind = new Binding("IsKeyboardFocused");
    bind.Converter = new KeyToVisibilityConverter();
    bind.Source = txtBox;
    bind.Mode = BindingMode.OneWay;
    PEAdornerControl adorner = new PEAdornerControl(txtBox);
    adorner.SetBinding(PEAdornerControl.VisibilityProperty, bind);

find父方法是这样的:

public T FindParent<T>(DependencyObject obj) where T : DepedencyObject
{
  if (obj == null)
     return null;
  DependencyOBject parent = VisualTreeHelper.GetParent(obj);

  if (parent is T)
      return parent as T;
  else
      return FindParent<T>(parent);
 }

您可能需要在 OnRender 方法中设置装饰器的位置,但这应该可以。不过要考虑的一件事是,如果您的 DataGrid 位于另一个容器中(例如面板、网格等),那么您可能仍会遇到裁剪问题。

裁剪问题是由于容器检查其子级的布局时通常不会考虑其装饰器。为了解决这个问题,您可能需要创建自己的控件并覆盖 MeasuerOverride(Size constraint) 方法。

例子:

public class MyPanel : Panel
{
   protected override Size MeasureOverride(Size constraint)
   {
     Size toReturn = new Size();
     foreach (UIElement child in this.InternalChildren)
     {
       //Do normal Measuring of children

       foreach( UIElement achild in AdornerLayer.GetAdorners(child))
       //Measure child adorners and add to return size as needed
     }

     return toReturn;
   }
 }

该代码确实很难衡量,但应该为您指明正确的方向。查看文档页面http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.measureoverride.aspx,了解有关在面板中测量子元素的信息。

【讨论】:

    【解决方案2】:

    只需获取最上面的AdornerLayer,而不是

        static AdornerLayer GetAdornerLayer(FrameworkElement adornedElement)
        {
            var w = Window.GetWindow(adornedElement);
            var vis = w.Content as Visual;
    
            return AdornerLayer.GetAdornerLayer(vis);
        }
    

    另外,如果你有 DataGrid 的名字,你可以得到它上面最近的层:

    AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(myDataGrid);
    

    【讨论】:

      猜你喜欢
      • 2018-10-16
      • 2011-10-22
      • 2017-05-30
      • 1970-01-01
      • 2020-05-23
      • 1970-01-01
      • 2017-06-28
      • 2021-10-24
      • 2013-02-10
      相关资源
      最近更新 更多