我需要畫兩條相鄰的顏色線。 我發現的唯一解決方案是基於兩條線,第二條是TranslateTransform。 但是,翻譯值必須根據行方向(角度)進行更改。Silverlight雙色線
有沒有辦法更容易地做到這一點?
感謝您的幫助。
我需要畫兩條相鄰的顏色線。 我發現的唯一解決方案是基於兩條線,第二條是TranslateTransform。 但是,翻譯值必須根據行方向(角度)進行更改。Silverlight雙色線
有沒有辦法更容易地做到這一點?
感謝您的幫助。
可以使用具有四個GradientStop的LinearGradientBrush繪製雙色線。例如,下面的XAML畫一條水平線是半紅半黃:
<Line X1="0" Y1="20" X2="200" Y2="20" StrokeThickness="14">
<Line.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="Red" />
<GradientStop Offset="0.5" Color="Red" />
<GradientStop Offset="0.5" Color="Yellow" />
<GradientStop Offset="1" Color="Yellow" />
</LinearGradientBrush>
</Line.Stroke>
</Line>
如果您嘗試使用帶線不是水平同一個LinearGradientBrush,你很快就會發現,它不會做你想做的事。這兩種顏色總是由一條水平線分隔,無論該線具有何種漸變,而您希望將這兩種顏色分開的線沿着您的Line
的中間線運行。要實現此目的,您需要更改LinearGradientBrush的StartPoint
和EndPoint
。這取決於線的梯度,並且它們有點難以計算。
爲了演示如何做到這一點,我組裝了一個模板化控件(下圖),繪製雙色線。如果你站在(X1
,Y1
)並朝向(X2
,Y2
)和Color2
將在您的右側,則會在左側的顏色爲Color1
。
請注意,此控件假定行的開始和結束標記爲Flat
。如果您希望使用其他類型的開始或結束上限(例如Square
或Round
),則需要調整overallWidth
和overallHeight
的計算。
TwoColorLine.cs:
public class TwoColorLine : Control
{
public static readonly DependencyProperty X1Property =
DependencyProperty.Register("X1", typeof(double), typeof(TwoColorLine), new PropertyMetadata(Coordinates_Changed));
public static readonly DependencyProperty Y1Property =
DependencyProperty.Register("Y1", typeof(double), typeof(TwoColorLine), new PropertyMetadata(Coordinates_Changed));
public static readonly DependencyProperty X2Property =
DependencyProperty.Register("X2", typeof(double), typeof(TwoColorLine), new PropertyMetadata(Coordinates_Changed));
public static readonly DependencyProperty Y2Property =
DependencyProperty.Register("Y2", typeof(double), typeof(TwoColorLine), new PropertyMetadata(Coordinates_Changed));
public static readonly DependencyProperty Color1Property =
DependencyProperty.Register("Color1", typeof(Color), typeof(TwoColorLine), new PropertyMetadata(Colors_Changed));
public static readonly DependencyProperty Color2Property =
DependencyProperty.Register("Color2", typeof(Color), typeof(TwoColorLine), new PropertyMetadata(Colors_Changed));
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register("StrokeThickness", typeof(double), typeof(TwoColorLine), null);
private LinearGradientBrush lineBrush;
public TwoColorLine()
{
this.DefaultStyleKey = typeof(TwoColorLine);
}
public double X1
{
get { return (double)GetValue(X1Property); }
set { SetValue(X1Property, value); }
}
public double Y1
{
get { return (double)GetValue(Y1Property); }
set { SetValue(Y1Property, value); }
}
public double X2
{
get { return (double)GetValue(X2Property); }
set { SetValue(X2Property, value); }
}
public double Y2
{
get { return (double)GetValue(Y2Property); }
set { SetValue(Y2Property, value); }
}
public Color Color1
{
get { return (Color)GetValue(Color1Property); }
set { SetValue(Color1Property, value); }
}
public Color Color2
{
get { return (Color)GetValue(Color2Property); }
set { SetValue(Color2Property, value); }
}
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
private static void Coordinates_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var line = obj as TwoColorLine;
if (line != null)
{
line.OnCoordinatesChanged();
}
}
private static void Colors_Changed(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var line = obj as TwoColorLine;
if (line != null)
{
line.OnColorsChanged();
}
}
private void OnCoordinatesChanged()
{
if (lineBrush != null)
{
RecalculateEndPoints();
}
}
public void OnColorsChanged()
{
if (lineBrush != null)
{
UpdateColors();
}
}
public void UpdateColors()
{
lineBrush.GradientStops[0].Color = Color1;
lineBrush.GradientStops[1].Color = Color1;
lineBrush.GradientStops[2].Color = Color2;
lineBrush.GradientStops[3].Color = Color2;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
Line line = GetTemplateChild("line") as Line;
if (line == null)
{
throw new InvalidOperationException("No line found in the template");
}
lineBrush = line.Stroke as LinearGradientBrush;
if (lineBrush == null)
{
throw new InvalidOperationException("Line does not have a LinearGradientBrush as its stroke");
}
UpdateColors();
RecalculateEndPoints();
}
private void RecalculateEndPoints()
{
double cos, sin;
if (X2 == X1)
{
cos = 0;
sin = (Y2 > Y1) ? 1 : -1;
}
else
{
double gradient = (Y2 - Y1)/(X2 - X1);
cos = Math.Sqrt(1/(1 + gradient * gradient));
sin = gradient * cos;
}
// These two lines assume flat start and end cap.
double overallWidth = Math.Abs(X2 - X1) + StrokeThickness * Math.Abs(sin);
double overallHeight = Math.Abs(Y2 - Y1) + StrokeThickness * Math.Abs(cos);
int sign = (X2 < X1) ? -1 : 1;
double xOffset = (sign * StrokeThickness * sin/2)/overallWidth;
double yOffset = (sign * StrokeThickness * cos/2)/overallHeight;
lineBrush.StartPoint = new Point(0.5 + xOffset, 0.5 - yOffset);
lineBrush.EndPoint = new Point(0.5 - xOffset, 0.5 + yOffset);
}
}
主題\ Generic.xaml:
<Style TargetType="local:TwoColorLine">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:TwoColorLine">
<Line x:Name="line" X1="{TemplateBinding X1}" Y1="{TemplateBinding Y1}" X2="{TemplateBinding X2}" Y2="{TemplateBinding Y2}" StrokeThickness="{TemplateBinding StrokeThickness}">
<Line.Stroke>
<LinearGradientBrush>
<GradientStop Offset="0" />
<GradientStop Offset="0.5" />
<GradientStop Offset="0.5" />
<GradientStop Offset="1" />
</LinearGradientBrush>
</Line.Stroke>
</Line>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
實例:
<Grid>
<local:TwoColorLine X1="190" Y1="170" X2="150" Y2="50" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="210" Y1="170" X2="250" Y2="50" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="230" Y1="190" X2="350" Y2="150" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="230" Y1="210" X2="350" Y2="250" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="210" Y1="230" X2="250" Y2="350" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="190" Y1="230" X2="150" Y2="350" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="170" Y1="210" X2="50" Y2="250" Color1="Red" Color2="Green" StrokeThickness="14" />
<local:TwoColorLine X1="170" Y1="190" X2="50" Y2="150" Color1="Red" Color2="Green" StrokeThickness="14" />
</Grid>
EDIT:修改RecalculateEndPoints()
方法把StartPoint和終點在線的邊緣而不是臨界點n在線的邊界矩形上。修改後的方法非常簡單,使用兩種以上顏色的控件更容易。
您可以用顏色創建一個小的ImageBrush,並使用它繪製一條線。
Silverlight不支持平鋪圖像畫筆。恐怕這個解決方案不適用。 –
呵呵 - 看起來像其他人也遇到過這種情況。使用着色器似乎是其他人採用的解決方法,例如http://silverscratch.blogspot.com/2010/09/tiled-image-brush-for-silverlight.html – holtavolt
偉大的解決方案!非常感謝! –
現在我試圖在兩行之間添加透明分隔符。我想我必須添加一個透明的漸變停止。此外,我需要使兩條線變得可變,取決於限制值。任何建議? –
我想我需要一個三種顏色的線與中間透明的顏色。我試圖去理解它,但是我無法管理線條上的寬度。 –