您好,我制作了此XYController,当父控件DockPanel的可见性设置为折叠时,该XYController不能正确绑定。隐藏它时,它工作正常。

ThumbPosXThumbPosY应该移动,因为属性SatVal是从不同位置控制的。但是,当返回到可见时,它们总是返回到[0,0]。

public class XYController : Control
{
    static XYController()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(XYController), new FrameworkPropertyMetadata(typeof(XYController)));
        EventManager.RegisterClassHandler(typeof(XYController), Thumb.DragDeltaEvent, new DragDeltaEventHandler(XYController.OnThumbDragDelta));
    }

    #region Private Members
    private const string ThumbName = "PART_Thumb";
    private TranslateTransform m_thumbTransform = new TranslateTransform();
    private Thumb m_thumb;
    #endregion


    #region Dependency Properties
    public Color SelectedColor
    {
        get { return (Color)GetValue(SelectedColorProperty); }
        set { SetValue(SelectedColorProperty, value); }
    }
    public static readonly DependencyProperty SelectedColorProperty =
    DependencyProperty.Register("SelectedColor", typeof(Color), typeof(XYController),
        new PropertyMetadata(Colors.Transparent));


    public double ThumbPosX
    {
        get { return (double)GetValue(ThumbPosXProperty); }
        set { SetValue(ThumbPosXProperty, value); }
    }
    public static readonly DependencyProperty ThumbPosXProperty =
    DependencyProperty.Register("ThumbPosX", typeof(double), typeof(XYController),
        new PropertyMetadata(0.0, new PropertyChangedCallback(OnThumbPosChanged)));


    public double ThumbPosY
    {
        get { return (double)GetValue(ThumbPosYProperty); }
        set { SetValue(ThumbPosYProperty, value); }
    }
    public static readonly DependencyProperty ThumbPosYProperty =
    DependencyProperty.Register("ThumbPosY", typeof(double), typeof(XYController),
        new PropertyMetadata(0.0, new PropertyChangedCallback(OnThumbPosChanged)));


    private static void OnThumbPosChanged(DependencyObject relatedObject, DependencyPropertyChangedEventArgs e)
    {
        XYController xycontroller = relatedObject as XYController;
        if (xycontroller != null)
        {
            xycontroller.m_thumbTransform.X = xycontroller.ThumbPosX * xycontroller.ActualWidth;
            xycontroller.m_thumbTransform.Y = xycontroller.ThumbPosY * xycontroller.ActualHeight;
        }
    }
    #endregion

    private void UpdatePosition(double positionX, double positionY)
    {
        positionX = LimitValue(positionX, ActualWidth);
        positionY = LimitValue(positionY, ActualHeight);

        m_thumbTransform.X = positionX;
        m_thumbTransform.Y = positionY;

        ThumbPosX = map(positionX, 0, ActualWidth, 0, 1);
        ThumbPosY = map(positionY, 0, ActualHeight, 0, 1);
    }

    #region Event Handlers
    private void OnThumbDragDelta(DragDeltaEventArgs e)
    {
        double offsetX = m_thumbTransform.X + e.HorizontalChange;
        double offsetY = m_thumbTransform.Y + e.VerticalChange;
        UpdatePosition(offsetX, offsetY);
    }

    private static void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
    {
        XYController hsvControl = sender as XYController;
        hsvControl.OnThumbDragDelta(e);
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        if (m_thumb != null)
        {
            Point position = e.GetPosition(this);
            UpdatePosition(position.X, ActualHeight - position.Y); //Check canvas scale in style
            m_thumb.RaiseEvent(e);
        }
        base.OnMouseLeftButtonDown(e);
    }

    protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
    {
        m_thumbTransform.X = ThumbPosX * ActualWidth;
        m_thumbTransform.Y = ThumbPosY * ActualHeight;
        base.OnRenderSizeChanged(sizeInfo);
    }
    #endregion

    private double LimitValue(double value, double max)
    {
        if (value < 0)
            value = 0;
        if (value > max)
            value = max;
        return value;
    }

    private double map(double value, double fromLow, double fromHigh, double toLow, double toHigh)
    {
        return (value - fromLow) * (toHigh - toLow) / (fromHigh - fromLow) + toLow;
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();
        m_thumb = GetTemplateChild(ThumbName) as Thumb;
        if (m_thumb != null)
        {
            UpdatePosition(this.ThumbPosX, this.ThumbPosY);
            m_thumb.RenderTransform = m_thumbTransform;
        }
    }
}


所以我发布了整个内容,因为我不知道缺少了什么。我还制作了“自定义滑块”,当它们合拢时它们可以正常工作。

我用这种方式:

    <DockPanel
        Visibility="{Binding Path=IsChecked, ElementName=HueRadio, Converter={StaticResource BoolToVisibility}}">
        <local:ColorSlider
            Minimum="0"
            Maximum="360"
            Orientation="Vertical"
            Style="{DynamicResource HueSliderVertical}"
            Value="{Binding Hue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            Margin="0, 4, 16, 4"
            />
        <local:XYController
            x:Name="HueColorControl"
            Style="{StaticResource HueController}"
            SelectedColor="{Binding SelectedColor}"
            ThumbPosX="{Binding Sat, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            ThumbPosY="{Binding Val, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            Margin="0, 4"
            Height="200"
            />
    </DockPanel>


只需绑定到RadioButton。如前所述,即使CustomControl折叠,也是DockPanel的ColorSlider仍在移动。

我试图将可见性直接设置为XYController而不是DockPanel,但是问题仍然相同。

这里缺少什么吗?

谢谢

最佳答案

位置值的计算涉及ActualHeightActualWidth作为参数。当Visibility设置为Visibility.Collapsed时,这些值为0。 LimitValue将始终返回max参数的值(为0)。同样,OnThumbPosChanged会将m_thumbTransform设置为0。

您必须检测到折叠状态并立即停止计算:

private static void OnThumbPosChanged(DependencyObject relatedObject, DependencyPropertyChangedEventArgs e)
{
    if (this.Visibility == Visibility.Collapsed)
    {
       return
    }

    XYController xycontroller = relatedObject as XYController;
    if (xycontroller != null)
    {
        xycontroller.m_thumbTransform.X = xycontroller.ThumbPosX * xycontroller.ActualWidth;
        xycontroller.m_thumbTransform.Y = xycontroller.ThumbPosY * xycontroller.ActualHeight;
    }
}




private void UpdatePosition(double positionX, double positionY)
{
    if (this.Visibility == Visibility.Collapsed)
    {
       return;
    }

    positionX = LimitValue(positionX, ActualWidth);
    positionY = LimitValue(positionY, ActualHeight);

    m_thumbTransform.X = positionX;
    m_thumbTransform.Y = positionY;

    ThumbPosX = map(positionX, 0, ActualWidth, 0, 1);
    ThumbPosY = map(positionY, 0, ActualHeight, 0, 1);
}


Visibility设置回Visibility.Visible将恢复崩溃前的最后一个值。要立即更新位置值,您需要为PropertyChanged属性注册一个Visibility回调:

static XYController()
{
    UIElement.VisibilityProperty.OverrideMetadata(
    typeof(XYController),
    new PropertyMetadata(Visibility.Visible, OnVisibililtyChanged));


    DefaultStyleKeyProperty.OverrideMetadata(typeof(XYController), new FrameworkPropertyMetadata(typeof(XYController)));
    EventManager.RegisterClassHandler(typeof(XYController), Thumb.DragDeltaEvent, new DragDeltaEventHandler(XYController.OnThumbDragDelta));
}

private static void OnVisibililtyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  // Update control
  OnThumbPosChanged(d, null);

  // Do more updates
}

关于c# - WPF CustomControl折叠后会失去绑定(bind),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57857691/

10-16 09:38