在UserControl中重新评估属性

时间:2017-01-27 13:40:30

标签: c# wpf user-controls

我在C#-WPF工作。

我制作了自己的UserControl,这是一个简单的交叉。使用坐标,我可以在图像上绘制X.

参数是:

  • CenterPoint:十字架中心
  • 前景:十字架的颜色
  • 厚度:十字架的厚度

我的Cross.xaml:

<UserControl x:Name="userControl"
             x:Class="Project.Cross">
    <Grid>
        <Line Stroke="{Binding Foreground, ElementName=userControl}"
              StrokeThickness="{Binding Thickness, ElementName=userControl}"
              X1="{Binding X1, ElementName=userControl, Mode=OneWay}"
              X2="{Binding X2, ElementName=userControl, Mode=OneWay}"
              Y1="{Binding Y1, ElementName=userControl, Mode=OneWay}"
              Y2="{Binding Y2, ElementName=userControl, Mode=OneWay}" />

        <Line Stroke="{Binding Foreground, ElementName=userControl}"
              StrokeThickness="{Binding Thickness, ElementName=userControl}"
              X1="{Binding X2, ElementName=userControl, Mode=OneWay}"
              X2="{Binding X1, ElementName=userControl, Mode=OneWay}"
              Y1="{Binding Y1, ElementName=userControl, Mode=OneWay}"
              Y2="{Binding Y2, ElementName=userControl, Mode=OneWay}"/>
    </Grid>
</UserControl>

我的Cross.xaml.cs:

public partial class Cross : UserControl
{
    public Cross()
    {
        InitializeComponent();
    }

    public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint",
        typeof(PointF), typeof(Cross),
        new PropertyMetadata(default(PointF)));

    public PointF CenterPoint
    {
        get { return (PointF)GetValue(CenterPointProperty); }
        set { SetValue(CenterPointProperty, value); }
    }

    public readonly static DependencyProperty ThicknessProperty = DependencyProperty.Register("Thickness",
        typeof(int), typeof(Cross),
        new PropertyMetadata(2));

    public int Thickness
    {
        get { return (int)GetValue(ThicknessProperty); }
        set { SetValue(ThicknessProperty, value); }
    } 

    public float X1
    {
        get
        {
            return (float)(CenterPoint.X - (Width / 2));
        }
    }
    public float X2
    {
        get
        {
            return (float)(CenterPoint.X + (Width / 2));
        }
    }
    public float Y1
    {
        get
        {
            return (float)(CenterPoint.Y - (Height / 2));
        }
    }
    public float Y2
    {
        get
        {
            return (float)(CenterPoint.Y + (Height / 2));
        }
    }
}

我可以这样称呼:

<local:Cross CenterPoint="{Binding Point}" Thickness="8" Foreground="Yellow" Height="40" Width="40"/>

我遇到问题,不显示十字架。我添加了断点,当我更改CenterPoint时,似乎值X1,X2,...不会刷新。如何强制C#重新评估这些值? (希望这能解决我的问题)

谢谢

2 个答案:

答案 0 :(得分:2)

如果希望在将CenterPoint依赖项属性设置为新值时刷新X1,X2,Y1和Y2只读属性,则UserControl应实现INotifyPropertyChanged接口。然后,您可以为依赖项属性注册PropertyChangedCallback,并为只读属性引发PropertyChanged事件:

public partial class Cross : UserControl, INotifyPropertyChanged
{
    public Cross()
    {
        InitializeComponent();
    }

    public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint",
        typeof(PointF), typeof(Cross),
        new PropertyMetadata(default(PointF), new PropertyChangedCallback(OnCenterPointUpdated))));

    private static void OnCenterPointUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Cross cross = d as Cross;
        cross.NotifyPropertyChanged("X1");
        cross.NotifyPropertyChanged("X2");
        cross.NotifyPropertyChanged("Y1");
        cross.NotifyPropertyChanged("Y2");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    ...
}

答案 1 :(得分:1)

mm8的方法可用于更新X1等,但还需要解决其他问题才能使控制工作。

我正在使用另一种方法来更新坐标属性:将X1等转换为read-only dependency properties,让用户控件在CenterPoint更改时以及控件的大小更改时更新它们。

我还将您的winforms PointF更改为WPF System.Windows.Pointdouble使用XY,我已更改{ {1}}到Thickness,因为WPF使用float来表示线条粗细,您也可以充分利用它。

我正在更新float事件的坐标,这是至关重要的,因为否则,只有当实际大小为0 x 0时才会在控件创建时设置坐标属性,SizeChanged WidthHeight

最后,您应该使用NaNActualWidth,这些更新为“实时”,而不是ActualHeightHeight,它们是设计时属性值。如果您给它一个固定的WidthWidth,效果将是相同的;使用HeightActualWidth允许它伸展以适合容器(如果需要)。

ActualHeight

最后,您不需要明确地设置绑定public partial class Cross : UserControl { public Cross() { InitializeComponent(); SizeChanged += Cross_SizeChanged; } private void Cross_SizeChanged(object sender, SizeChangedEventArgs e) { UpdateXYProperties(); } protected void UpdateXYProperties() { X1 = (float)(CenterPoint.X - (ActualWidth / 2)); X2 = (float)(CenterPoint.X + (ActualWidth / 2)); Y1 = (float)(CenterPoint.Y - (ActualHeight / 2)); Y2 = (float)(CenterPoint.Y + (ActualHeight / 2)); } public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register(nameof(CenterPoint), typeof(Point), typeof(Cross), new PropertyMetadata(default(Point), CenterPoint_PropertyChanged)); private static void CenterPoint_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { ((Cross)obj).UpdateXYProperties(); } public Point CenterPoint { get { return (Point)GetValue(CenterPointProperty); } set { SetValue(CenterPointProperty, value); } } public readonly static DependencyProperty ThicknessProperty = DependencyProperty.Register(nameof(Thickness), typeof(float), typeof(Cross), new PropertyMetadata(2.0F)); public float Thickness { get { return (float)GetValue(ThicknessProperty); } set { SetValue(ThicknessProperty, value); } } #region Read-Only Properties #region X1 Property public float X1 { get { return (float)GetValue(X1Property); } protected set { SetValue(X1PropertyKey, value); } } internal static readonly DependencyPropertyKey X1PropertyKey = DependencyProperty.RegisterReadOnly("X1", typeof(float), typeof(Cross), new PropertyMetadata(0.0F)); public static readonly DependencyProperty X1Property = X1PropertyKey.DependencyProperty; #endregion X1 Property #region X2 Property public float X2 { get { return (float)GetValue(X2Property); } protected set { SetValue(X2PropertyKey, value); } } internal static readonly DependencyPropertyKey X2PropertyKey = DependencyProperty.RegisterReadOnly("X2", typeof(float), typeof(Cross), new PropertyMetadata(0.0F)); public static readonly DependencyProperty X2Property = X2PropertyKey.DependencyProperty; #endregion X2 Property #region Y1 Property public float Y1 { get { return (float)GetValue(Y1Property); } protected set { SetValue(Y1PropertyKey, value); } } internal static readonly DependencyPropertyKey Y1PropertyKey = DependencyProperty.RegisterReadOnly("Y1", typeof(float), typeof(Cross), new PropertyMetadata(0.0F)); public static readonly DependencyProperty Y1Property = Y1PropertyKey.DependencyProperty; #endregion Y1 Property #region Y2 Property public float Y2 { get { return (float)GetValue(Y2Property); } protected set { SetValue(Y2PropertyKey, value); } } internal static readonly DependencyPropertyKey Y2PropertyKey = DependencyProperty.RegisterReadOnly("Y2", typeof(float), typeof(Cross), new PropertyMetadata(0.0F)); public static readonly DependencyProperty Y2Property = Y2PropertyKey.DependencyProperty; #endregion Y2 Property #endregion Read-Only Properties } ,因为Mode=OneWay等无法更新绑定源(在这种情况下,这是您自己的Line.X1等),所以默认情况下它们已经X1

OneWay

最后,几乎可以肯定:<Grid> <Line Stroke="{Binding Foreground, ElementName=userControl}" StrokeThickness="{Binding Thickness, ElementName=userControl}" X1="{Binding X1, ElementName=userControl}" X2="{Binding X2, ElementName=userControl}" Y1="{Binding Y1, ElementName=userControl}" Y2="{Binding Y2, ElementName=userControl}" /> <Line Stroke="{Binding Foreground, ElementName=userControl}" StrokeThickness="{Binding Thickness, ElementName=userControl}" X1="{Binding X2, ElementName=userControl}" X2="{Binding X1, ElementName=userControl}" Y1="{Binding Y1, ElementName=userControl}" Y2="{Binding Y2, ElementName=userControl}" /> </Grid> 设计的效果是,如果它不是控件的实际中心,则偏移控件边界外的交叉。如果这是你的意图,不要费心阅读本段的其余部分。如果这不是您的意图,您可以按如下方式重写CenterPoint并丢失UpdateXYProperties()属性:

CenterPoint

但这取决于你和圣安德鲁。