WPF CustomControl中的FindParent返回null

时间:2016-08-04 12:37:13

标签: c# wpf

我正在尝试制作一个圆形滑块(自定义控件)来选择颜色的HUE。我在运行我的演示应用程序时遇到了这个问题。在这种情况下,FindParent“_templateCanvas”始终为null,但无法找出原因。

以下是HueWheel课程的一部分:

public class HueWheel : Slider
{
    static HueWheel()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(HueWheel), new FrameworkPropertyMetadata(typeof(HueWheel)));
    }
    private bool _isPressed = false;
    private Canvas _templateCanvas = null;

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        _isPressed = true;
    }

    protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
    {
        _isPressed = false;
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (_isPressed)
        {
            if (_templateCanvas == null)
            {
                _templateCanvas = MyHelper.FindParent<Canvas>(e.Source as Ellipse);
                if (_templateCanvas == null) return;
            }

            const double RADIUS = 150;
            Point newPos = e.GetPosition(_templateCanvas);
            double angle = MyHelper.GetAngleR(newPos, RADIUS);
            //huewheel.Value = (huewheel.Maximum - huewheel.Minimum) * angle / (2 * Math.PI);
        }
    }
}

这是找到父母的类:

public static class MyHelper
{
    public static T FindParent<T>(FrameworkElement current) where T : FrameworkElement
    {
            do
            {
                current = VisualTreeHelper.GetParent(current) as FrameworkElement;
                if (current is T)
                {
                    return (T)current;
                }
            }
            while (current != null);
            return null;
    }

以下是我在Generic.xaml中的内容

<Style TargetType="{x:Type local:HueWheel}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:HueWheel}">
                <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <Slider Name="huewheel">
                        <Slider.Template>
                            <ControlTemplate>
                                <Viewbox>
                                    <Canvas Width="300" Height="300">
                                        <Image Stretch="Fill" Source="Assets/HueCircle.PNG" Focusable="False" Height="300" Width="300" RenderTransformOrigin="0.5,0.5">
                                            <Image.RenderTransform>
                                                <TransformGroup>
                                                    <ScaleTransform/>
                                                    <SkewTransform/>
                                                    <RotateTransform Angle="270"/>
                                                    <TranslateTransform/>
                                                </TransformGroup>
                                            </Image.RenderTransform>
                                        </Image>
                                        <Ellipse Fill="Transparent" Width="300" Height="300" Canvas.Left="0" Canvas.Top="0"/>
                                        <Canvas>
                                            <Line Stroke="Transparent" StrokeThickness="5" X1="150" Y1="150" X2="150" Y2="0"/>
                                            <Ellipse Fill="Black" Width="20" Height="20" Canvas.Left="140" Canvas.Top="30"/>
                                            <Canvas.RenderTransform>
                                                <RotateTransform CenterX="150" CenterY="150">
                                                    <RotateTransform.Angle>
                                                        <MultiBinding Converter="{StaticResource ValueAngleConverter}">
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/>
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/>
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/>
                                                        </MultiBinding>
                                                    </RotateTransform.Angle>
                                                </RotateTransform>
                                            </Canvas.RenderTransform>
                                        </Canvas>
                                    </Canvas>
                                </Viewbox>
                            </ControlTemplate>
                        </Slider.Template>
                    </Slider>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

画布存在于xaml中,我正在鼠标上的椭圆包含在这个画布中,所以我应该能够获得椭圆父(画布)。

有什么想法吗?

谢谢

1 个答案:

答案 0 :(得分:2)

或者,“帆布的重要性是什么?”

我尝试过对您的代码进行测试,我发现e.Source的类型为HueWheel,并且继承自Slider而非Ellipse,我并不感到惊讶。因此,此表达式始终返回null

e.Source as Ellipse

...因此,a)e.Source不是您认为的对象,b)下一个语句始终将_templateCanvas设置为null

_templateCanvas = MyHelper.FindParent<Canvas>(e.Source as Ellipse);

FindParent会立即返回null,因为您始终会为null参数传递current。无论如何,canvas都不是HueWheel(你知道 - 你不知道的是e.Source {{{ 1}} - 但是你下次要知道的第一件事是在断点处拍打并将鼠标悬停在HueWheel上以查看你得到的内容。

现在让我们解决它。接下来的是你如何在WPF中做到这一点,除了真正的聪明人在评论中讨论的任何细节之外。

我不知道你要抓住哪个Canvas,所以我会抓住你们两个。首先,在模板中提供e.Source个属性;我会称它们为x:NamePART_FirstCanvas,因为我没有弄清楚语义。我还重写了你的模板以消除内部滑块;我不明白为什么你把一个重新设置的滑块放在滑块的模板中。麻烦的是我无法调用内部滑块的PART_SecondCanvas方法,因为它受到保护。我的另一个选择是编写GetTemplateChild()的最小子类,它只是公开地公开Slider,并将其用于内部滑块。如果有一个很好的理由让两个滑块对我来说不明显(可能是一个X坐标而另一个是Y?),我们可以更新这个以这样做。

GetTemplateChild()

接下来,我们将为这两个名为Canvases添加私有成员,并在覆盖<ControlTemplate TargetType="{x:Type test:HueWheel}" > <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" > <Viewbox> <Canvas Width="300" Height="300" x:Name="PART_FirstCanvas" > <Image Stretch="Fill" Source="Assets/HueCircle.PNG" Focusable="False" Height="300" Width="300" RenderTransformOrigin="0.5,0.5" > <Image.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform Angle="270"/> <TranslateTransform/> </TransformGroup> </Image.RenderTransform> </Image> <Ellipse Fill="Transparent" Width="300" Height="300" Canvas.Left="0" Canvas.Top="0"/> <Canvas x:Name="PART_SecondCanvas"> <Line Stroke="Transparent" StrokeThickness="5" X1="150" Y1="150" X2="150" Y2="0"/> <Ellipse Fill="Black" Width="20" Height="20" Canvas.Left="140" Canvas.Top="30"/> <Canvas.RenderTransform> <RotateTransform CenterX="150" CenterY="150"> <RotateTransform.Angle> <MultiBinding Converter="{StaticResource ValueAngleConverter}"> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value"/> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum"/> <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum"/> </MultiBinding> </RotateTransform.Angle> </RotateTransform> </Canvas.RenderTransform> </Canvas> </Canvas> </Viewbox> </Border> </ControlTemplate> 时抓取它们。然后我们将在mousemove事件中使用我们想要的任何一个:

OnApplyTemplate()