【问题标题】:A class derived Control that has a Canvas in template, I want to work like canvas一个类派生控件在模板中有一个画布,我想像画布一样工作
【发布时间】:2020-09-08 04:30:56
【问题描述】:

我有一个派生自Windows.Controls.Control 的类Tableau,它的模板包含一个Canvas

    <Style TargetType="{x:Type local:Tableau}">
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:Tableau}">
                    <Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <ScrollViewer x:Name="ScrollViewer"
                                      HorizontalScrollBarVisibility="{Binding RelativeSource={RelativeSource TemplatedParent},Path=HorizontalScrollBarVisibility}" 
                                      VerticalScrollBarVisibility="{Binding RelativeSource={RelativeSource TemplatedParent},Path=VerticalScrollBarVisibility}"
                                      >
                            <Canvas x:Name="Diagram" 
                                    HorizontalAlignment="Stretch" 
                                    VerticalAlignment="Stretch"
                                    Background="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}"
                                    >
                                <Canvas.RenderTransform>
                                    <ScaleTransform CenterX="0"
                                                    CenterY="0"
                                                    ScaleX="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Scale}"
                                                    ScaleY="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Scale}"
                                                    />
                                </Canvas.RenderTransform>
                            </Canvas>
                        </ScrollViewer>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Tableau 类是:

    public class Tableau:Control
    {
        private Canvas _canvas;
        public Canvas Canvas
        {
            get { return _canvas; }
        }

        static Tableau()
        {
            FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
                typeof(Tableau), new FrameworkPropertyMetadata(typeof(Tableau)));
        }

        public Tableau()
            : base()
        {
            this.Loaded += Tableau_Loaded;
        }

        private void Tableau_Loaded(object sender, RoutedEventArgs e)
        {
            _canvas = (Canvas)this.Template.FindName("Diagram", this);
        }
    }

我想把它用作画布,像这样:

    <local:Tableau>
            <Rectangle Fill="AliceBlue" Stroke="Black" Width="100" Height="100" Canvas.Top="10"/>
            <Rectangle Fill="AliceBlue" Stroke="Black" Width="100" Height="100" Canvas.Left="130" Canvas.Top="50"/>
    </local:Tableau>

有没有可能,如果有怎么办?

【问题讨论】:

  • 您可以从 ItemsControl 派生,并通过 Style 设置 ItemsPanel 属性。
  • 如果您已经看到我的答案,我只是做了更多的测试并更新了它。现在应该是更完整的解决方案了。

标签: c# wpf templates canvas controls


【解决方案1】:

您可以定义一个属性Children,让它从内部Canvas 返回Children 集合,然后应用ContentProperty 属性。这是我测试的类的修改版本:

[ContentProperty(nameof(Children))]
public class Tableau : Control
{
    static Tableau()
    {
        FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
            typeof(Tableau), new FrameworkPropertyMetadata(typeof(Tableau)));
    }

    public Tableau() : base()
    {
        UpdateDefaultStyle();
    }

    private Canvas canvas;
    public Canvas Canvas
    {
        get
        {
            if (canvas == null) { ApplyTemplate(); }
            return canvas;
        }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        canvas = (Canvas)GetTemplateChild("Diagram");
    }

    public UIElementCollection Children
    {
        get { return Canvas.Children; }
    }
}

请注意,我使用OnApplyTemplate 而不是Loaded,这样我就可以在Tableau 加载之前获得内部Canvas(以及Children 集合)。我还在构造函数中使用了UpdateDefaultStyle,以确保可以尽早加载默认模板。

【讨论】:

  • 谢谢,但它不起作用。这个“public UIElementCollection Children { get { return Canvas.Children; }”有错误。我将 Canvas.Children 更改为 canvas.Children 但不起作用。
  • @Davoud 哇,我不知道我以前认为它是如何工作的。嗯,第三次的魅力。我做了另一个更改并再次测试它。告诉我它现在是否适合你。
  • 感谢您的关注。但不像画布那样工作。当我使用类似这样的 <tableau horizo ...><b><tableau.children><rectangle width="81" height="67" fill="Aqua" margin="100"></rectangle></tableau.children></b> </tableau> 在设计时一切正常,除了移动项目必须使用边距而不是 Canvas.SetLeft 和顶部。在运行时我有这个错误:{“对象引用未设置为对象的实例。”} at get { return Canvas.Children; }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 1970-01-01
  • 1970-01-01
  • 2015-08-12
  • 2015-02-15
  • 1970-01-01
相关资源
最近更新 更多