如何在没有ControlTemplate的情况下创建WPF自定义控件?

时间:2014-12-11 06:24:09

标签: wpf custom-controls

我需要编写一个WPF自定义控件,它由4个其他FrameworkElement派生的自定义类组成。通常我会使用Grid来安排它们,但Grid有一些布局问题,我必须编写自己继承自Panel的类。当然,我的自定义控件可以从Panel继承,但是会暴露子和其他面板功能,它不应该。

我需要一个自定义控件,它只显示我添加的一些属性和典型的FrameworkElement属性。我正在考虑我的自定义控件继承自Control。但我不想使用ControlTemplates。我想创建Panel并从代码后面添加FrameworkElements。怎么办呢?

让我总结一下问题: 1)控制是从中派生出来的最佳类吗?

2)如何在不使用ControlTemplate的情况下将FrameworkElements添加到Control派生类?

2 个答案:

答案 0 :(得分:1)

  1. 是。控制是最好的等级。

  2. 您需要覆盖方法GetVisualChild()和属性VisualChildrenCount。我在考虑你想要4个自定义框架元素作为你的孩子,并在构造函数中初始化该集合。然后代码如下,

    private List<UIElement> visualChildren;
    
    protected override int VisualChildrenCount
    {
        get
        {
            return this.visualChildren.Count;
        }
    }
    
    protected override Visual GetVisualChild(int index)
    {
        return this.visualChildren[index];
    }
    
  3. 您还可以覆盖MeasureOverride和ArrangeOverride方法,为子项分配大小并分别安排子项。

    More information

答案 1 :(得分:0)

这是根据XAML Lover和Marat Khasanov的建议解决我的问题的实现。 TestCustomControl将2个TextBox对角放置。右上角的那个使用尽可能多的宽度和尽可能多的高度。左下角的那个使用尽可能多的高度和尽可能宽的宽度。

+------------+--------+
|            |        |
|            |TextBox1|
|            |        |
+------------+--------+
|  TextBox2  |        |
+------------+--------+

这种排列对于Grid来说是一个问题,因为要测量一个TextBox的大小,它需要知道另一个TextBox的大小,这是不可能的。 Grid通过使用不确定空间测量第一个TextBox,然后使用第一个TextBox的大小测量另一个TextBox,然后使用第二个的大小再次测量第一个TextBox来解决这个难题。这会导致各种问题,TestCustomControl会完全阻止这些问题。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;


namespace TestControl {


  public class TestCustomControl: Control  {

    VisualCollection visualCollection;
    Rectangle RectangleToLeft;
    TextBox TextBoxTopRight;
    TextBox TextBoxBottomLeft;
    Rectangle RectangleBottomRight;


    public TestCustomControl() {
      RectangleToLeft      = new Rectangle { Fill = Brushes.LightYellow };
      TextBoxTopRight      = new TextBox {Text = "TR", FontSize = 22, HorizontalAlignment=HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Stretch };
      TextBoxBottomLeft    = new TextBox {Text = "BL", FontSize = 22, HorizontalAlignment=HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Center };
      RectangleBottomRight = new Rectangle {Fill = Brushes.LightBlue };

      //new UIElementCollection(this, logicalParent);
      visualCollection = new VisualCollection(this);
      visualCollection.Add(RectangleToLeft);
      visualCollection.Add(TextBoxTopRight);
      visualCollection.Add(TextBoxBottomLeft);
      visualCollection.Add(RectangleBottomRight);
    }


    protected override int VisualChildrenCount {
      get {
        return visualCollection.Count;
      }
    }


    protected override System.Windows.Media.Visual GetVisualChild(int index) {
      return visualCollection[index];
    }


    protected override System.Windows.Size MeasureOverride(System.Windows.Size constraint) {
      TextBoxTopRight.Measure(constraint);
      TextBoxBottomLeft.Measure(constraint);
      Size returnedSize = constraint;
      if (double.IsInfinity(constraint.Height)) {
        returnedSize.Height = TextBoxTopRight.DesiredSize.Height + TextBoxBottomLeft.DesiredSize.Height;
      }
      if (double.IsInfinity(constraint.Width)) {
        returnedSize.Width = TextBoxTopRight.DesiredSize.Width + TextBoxBottomLeft.DesiredSize.Width;
      }
      return constraint;
    }


    protected override System.Windows.Size ArrangeOverride(System.Windows.Size arrangeBounds) {
      double remainingWidth = Math.Max(0, arrangeBounds.Width - TextBoxTopRight.DesiredSize.Width);
      double remainingHeight = Math.Max(0, arrangeBounds.Height - TextBoxBottomLeft.DesiredSize.Height);
      RectangleToLeft.Arrange(new Rect(0, 0, remainingWidth, remainingHeight));
      TextBoxTopRight.Arrange(new Rect(remainingWidth, 0, TextBoxTopRight.DesiredSize.Width, remainingHeight));
      TextBoxBottomLeft.Arrange(new Rect(0, remainingHeight, remainingWidth, TextBoxBottomLeft.DesiredSize.Height));
      RectangleBottomRight.Arrange(new Rect(remainingWidth, remainingHeight, TextBoxTopRight.DesiredSize.Width, TextBoxTopRight.DesiredSize.Height));
      return arrangeBounds;
    }


    protected override Geometry GetLayoutClip(Size layoutSlotSize) {
      if (ClipToBounds)
        return new RectangleGeometry(new Rect(RenderSize));
      else
        return null;
    }
  }
}