我正在尝试制作一个圆形滑块(自定义控件)来选择颜色的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中,我正在鼠标上的椭圆包含在这个画布中,所以我应该能够获得椭圆父(画布)。
有什么想法吗?
谢谢
答案 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:Name
和PART_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()