簡體   English   中英

WPF CustomControl中的FindParent返回null

[英]FindParent in WPF CustomControl return null

我正在嘗試制作一個圓形滑塊(一個自定義控件)以選擇一種顏色的色相。 我在運行演示應用程序時遇到了這個問題。 在這種情況下,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中,我在其上移動鼠標的橢圓包含在此畫布中,因此我應該能夠獲取橢圓父對象(畫布)。

任何想法 ?

謝謝

或者,“畫布有什么關系?”

我嘗試測試您的代碼,發現e.SourceHueWheel類型,這並不奇怪,該類型繼承自Slider而不是Ellipse 因此,此表達式始終返回null

e.Source as Ellipse

...因此,a) e.Source不是您認為的對象,b)下_templateCanvas語句始終將_templateCanvas設置為null

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

FindParent立即返回null ,因為您始終向其傳遞current參數的null 無論如何,這兩個畫布都不是HueWheel HueWheel (您知道-您不知道的是e.Source HueWheel但下次您要做的第一件事就是拍斷點並懸停將鼠標懸停在e.Source以查看所獲得的內容)。

現在,讓我們對其進行修復。 接下來是如何在WPF中做到這一點,除了真正聰明的人在評論中困擾我的細節之外。

我不知道您要在此處嘗試使用哪個Canvas,所以我會同時將它們都抓住。 首先,在模板中給它們x:Name屬性; 我將它們PART_FirstCanvasPART_SecondCanvas因為我沒有弄清楚語義。 我還重寫了模板,以消除內部滑塊; 我不明白為什么要將重新模板化的滑塊放在滑塊的模板中。 那里的問題是我無法調用內部滑塊的GetTemplateChild()方法,因為它是受保護的。 我的另一個選擇是編寫Slider的最小子類,該子類僅公開公開GetTemplateChild() ,並將其用於內部滑塊。 如果有充分的理由要擁有兩個對我來說不明顯的滑塊(也許一個是X坐標,另一個是Y?),我們可以更新它以這種方式進行。

<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>

接下來,我們將為這兩個名為Canvas的成員添加私有成員,並在OnApplyTemplate()的重寫中獲取它們。 然后,我們將在該mousemove事件中使用任意一個:

public class HueWheel : Slider
{
    static HueWheel()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(HueWheel), new FrameworkPropertyMetadata(typeof(HueWheel)));
    }

    private bool _isPressed = false;
    private Canvas _PART_FirstCanvas;
    private Canvas _PART_SecondCanvas;

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        //  Use () cast rather than the "as" operator because if the actual runtime 
        //  type can't be cast to the desired type, that'll throw an exception 
        //  rather than silently returning null. If you had cast (Ellipse)e.Source, 
        //  that would have blown up on you because you can't cast HueWheel to Ellipse. 
        //  That would have instantly shown you what was wrong. 
        //  But you won't get an exception here if GetTemplateChild() just returns null. 
        _PART_FirstCanvas = (Canvas)GetTemplateChild("PART_FirstCanvas");
        _PART_SecondCanvas = (Canvas)GetTemplateChild("PART_SecondCanvas");
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (_isPressed)
        {
            const double RADIUS = 150;

            //  Or _PART_SecondCanvas; whichever. 
            Point newPos = e.GetPosition(_PART_FirstCanvas);

            double angle = MyHelper.GetAngleR(newPos, RADIUS);
            //huewheel.Value = (huewheel.Maximum - huewheel.Minimum) * angle / (2 * Math.PI);
        }
    }

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

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM