如何解决设置属性时由于递归导致的问题?
How do I fix this issue caused due to recursion while setting Properties?
我有一个这样的自定义控件:
public class UIButton : Button
{
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Brush Background {get; set;}
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Color MOBG { get; set; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Color MDBG { get; set; }
public Brush BackgroundBrush
{
get { return base.GetValue(BackgroundBrushProperty) as Brush; }
set
{
base.SetValue(BackgroundBrushProperty, value);
MOBG = Functions.getLighterShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
MDBG = Functions.getDarkerShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
}
}
public static readonly DependencyProperty BackgroundBrushProperty =
DependencyProperty.Register("BackgroundBrush", typeof(Brush), typeof(UIButton));
public UIButton()
{
SetTemplate();
SetEvents();
}
public void SetEvents()
{
this.PreviewMouseDown += UIButton_PreviewMouseDown;
}
void UIButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Storyboard sb = new Storyboard();
ColorAnimation c = new ColorAnimation();
Storyboard.SetTargetProperty(c, new PropertyPath("BackgroundBrush.Color"));
Storyboard.SetTarget(c, this);
c.To = MDBG;
c.Duration = new Duration(TimeSpan.FromSeconds(0.1));
sb.Children.Add(c);
sb.Begin();
}
public void SetTemplate()
{
ControlTemplate template = new ControlTemplate();
FrameworkElementFactory root = new FrameworkElementFactory(typeof(Border)); root.Name = "border";
root.SetBinding(Border.BackgroundProperty, new Binding("BackgroundBrush") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
root.SetBinding(Border.WidthProperty, new Binding("Width") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
root.SetBinding(Border.HeightProperty, new Binding("Height") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
root.SetValue(Border.CornerRadiusProperty, new CornerRadius(5));
FrameworkElementFactory content = new FrameworkElementFactory(typeof(TextBlock)); content.Name = "tx";
content.SetValue(TextBlock.HorizontalAlignmentProperty, System.Windows.HorizontalAlignment.Center);
content.SetValue(TextBlock.VerticalAlignmentProperty, System.Windows.VerticalAlignment.Center);
content.SetBinding(TextBlock.TextProperty, new Binding("Content") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetBinding(TextBlock.FontFamilyProperty, new Binding("FontFamily") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetBinding(TextBlock.FontWeightProperty, new Binding("FontWeight") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetBinding(TextBlock.FontSizeProperty, new Binding("FontSize") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetValue(TextBlock.ForegroundProperty, Brushes.White);
root.AppendChild(content);
template.VisualTree = root;
SetValue(TemplateProperty, template);
}
}
我的函数Class:
static class Functions
{
public static Color getLighterShade(Color color)
{
float correctionFactor = 0.5f;
float red = (255 - color.R) * correctionFactor + color.R;
float green = (255 - color.G) * correctionFactor + color.G;
float blue = (255 - color.B) * correctionFactor + color.B;
System.Drawing.Color lighterColor = System.Drawing.Color.FromArgb(color.A, (int)red, (int)green, (int)blue);
return Color.FromArgb(lighterColor.A, lighterColor.R, lighterColor.G, lighterColor.B);
}
public static Color getDarkerShade(Color color)
{
System.Drawing.Color c1 = System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B);
System.Drawing.Color c2 = System.Drawing.Color.FromArgb(c1.A,
(int)(c1.R * 0.5), (int)(c1.G * 0.5), (int)(c1.B * 0.5));
return Color.FromArgb(c2.A, c2.R, c2.G, c2.B);
}
public static LinearGradientBrush newGradientBrush(params Color[] colors)
{
GradientStopCollection gsc = new GradientStopCollection();
float f = 1f / (float)(colors.Length - 1);
float y = 0;
for (int x = 0; x <= colors.Length - 1; x++)
{
gsc.Add(new GradientStop(colors[x], y));
y += f;
}
return new LinearGradientBrush(gsc);
}
}
最后是扩展 class:
public static class Extensions
{
public static Color ToSysDrawCol(this System.Windows.Media.Color col)
{
return System.Drawing.Color.FromArgb(col.A, col.R, col.G, col.B);
}
}
使用自定义控件,我想说的应该很清楚
MOBG
和 MDBG
是鼠标悬停和鼠标按下的颜色。在BackgroundBrushProperty
的setter中,我根据当前背景的浅色和深色来设置这两种颜色。
现在如您所见,在 MouseDown
事件中,我为控件的背景 属性 设置了动画。但正因为如此,MDBG 也再次发生了变化。因此最终,颜色变得透明。我该如何解决这个问题?
设置BackgroundBrush
时不要设置MOBG
& MDBG
,而是对两个属性实现get:
public Color MDBG
{
get
{
return Functions.getDarkerShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
};
// no set
// set;
}
如果 Functions.getDarkerShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
太慢(我怀疑),使用一个成员变量 Color? _MDBG
你可以用作缓存(当它为空时计算一次,并且 return 的值每个以下得到)。
在这种情况下,当 BackgroundBrush
发生变化时,您必须实施适当的 _MDBG = null;
(即,不只是设置 when,而是将 when 设置为与之前的值不同的值)
我有一个这样的自定义控件:
public class UIButton : Button
{
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Brush Background {get; set;}
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Color MOBG { get; set; }
[EditorBrowsable(EditorBrowsableState.Never), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Color MDBG { get; set; }
public Brush BackgroundBrush
{
get { return base.GetValue(BackgroundBrushProperty) as Brush; }
set
{
base.SetValue(BackgroundBrushProperty, value);
MOBG = Functions.getLighterShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
MDBG = Functions.getDarkerShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
}
}
public static readonly DependencyProperty BackgroundBrushProperty =
DependencyProperty.Register("BackgroundBrush", typeof(Brush), typeof(UIButton));
public UIButton()
{
SetTemplate();
SetEvents();
}
public void SetEvents()
{
this.PreviewMouseDown += UIButton_PreviewMouseDown;
}
void UIButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Storyboard sb = new Storyboard();
ColorAnimation c = new ColorAnimation();
Storyboard.SetTargetProperty(c, new PropertyPath("BackgroundBrush.Color"));
Storyboard.SetTarget(c, this);
c.To = MDBG;
c.Duration = new Duration(TimeSpan.FromSeconds(0.1));
sb.Children.Add(c);
sb.Begin();
}
public void SetTemplate()
{
ControlTemplate template = new ControlTemplate();
FrameworkElementFactory root = new FrameworkElementFactory(typeof(Border)); root.Name = "border";
root.SetBinding(Border.BackgroundProperty, new Binding("BackgroundBrush") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
root.SetBinding(Border.WidthProperty, new Binding("Width") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
root.SetBinding(Border.HeightProperty, new Binding("Height") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
root.SetValue(Border.CornerRadiusProperty, new CornerRadius(5));
FrameworkElementFactory content = new FrameworkElementFactory(typeof(TextBlock)); content.Name = "tx";
content.SetValue(TextBlock.HorizontalAlignmentProperty, System.Windows.HorizontalAlignment.Center);
content.SetValue(TextBlock.VerticalAlignmentProperty, System.Windows.VerticalAlignment.Center);
content.SetBinding(TextBlock.TextProperty, new Binding("Content") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetBinding(TextBlock.FontFamilyProperty, new Binding("FontFamily") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetBinding(TextBlock.FontWeightProperty, new Binding("FontWeight") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetBinding(TextBlock.FontSizeProperty, new Binding("FontSize") { RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent) });
content.SetValue(TextBlock.ForegroundProperty, Brushes.White);
root.AppendChild(content);
template.VisualTree = root;
SetValue(TemplateProperty, template);
}
}
我的函数Class:
static class Functions
{
public static Color getLighterShade(Color color)
{
float correctionFactor = 0.5f;
float red = (255 - color.R) * correctionFactor + color.R;
float green = (255 - color.G) * correctionFactor + color.G;
float blue = (255 - color.B) * correctionFactor + color.B;
System.Drawing.Color lighterColor = System.Drawing.Color.FromArgb(color.A, (int)red, (int)green, (int)blue);
return Color.FromArgb(lighterColor.A, lighterColor.R, lighterColor.G, lighterColor.B);
}
public static Color getDarkerShade(Color color)
{
System.Drawing.Color c1 = System.Drawing.Color.FromArgb(color.A, color.R, color.G, color.B);
System.Drawing.Color c2 = System.Drawing.Color.FromArgb(c1.A,
(int)(c1.R * 0.5), (int)(c1.G * 0.5), (int)(c1.B * 0.5));
return Color.FromArgb(c2.A, c2.R, c2.G, c2.B);
}
public static LinearGradientBrush newGradientBrush(params Color[] colors)
{
GradientStopCollection gsc = new GradientStopCollection();
float f = 1f / (float)(colors.Length - 1);
float y = 0;
for (int x = 0; x <= colors.Length - 1; x++)
{
gsc.Add(new GradientStop(colors[x], y));
y += f;
}
return new LinearGradientBrush(gsc);
}
}
最后是扩展 class:
public static class Extensions
{
public static Color ToSysDrawCol(this System.Windows.Media.Color col)
{
return System.Drawing.Color.FromArgb(col.A, col.R, col.G, col.B);
}
}
使用自定义控件,我想说的应该很清楚
MOBG
和 MDBG
是鼠标悬停和鼠标按下的颜色。在BackgroundBrushProperty
的setter中,我根据当前背景的浅色和深色来设置这两种颜色。
现在如您所见,在 MouseDown
事件中,我为控件的背景 属性 设置了动画。但正因为如此,MDBG 也再次发生了变化。因此最终,颜色变得透明。我该如何解决这个问题?
设置BackgroundBrush
时不要设置MOBG
& MDBG
,而是对两个属性实现get:
public Color MDBG
{
get
{
return Functions.getDarkerShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
};
// no set
// set;
}
如果 Functions.getDarkerShade((GetValue(BackgroundBrushProperty) as SolidColorBrush).Color);
太慢(我怀疑),使用一个成员变量 Color? _MDBG
你可以用作缓存(当它为空时计算一次,并且 return 的值每个以下得到)。
在这种情况下,当 BackgroundBrush
发生变化时,您必须实施适当的 _MDBG = null;
(即,不只是设置 when,而是将 when 设置为与之前的值不同的值)