Fixed gradient with a moving rectangle?
I have a WPF 'monitor widget' that displays CPU, RAM and disk perform开发者_如何学Pythonance as small percentage bars. I use the following gradient as a resource to divide the bars into 4 sections (ie. 0% - 25%, 25% - 50%, etc.)
<LinearGradientBrush x:Key="Quarters" StartPoint="0,0" EndPoint="0,15" MappingMode="Absolute">
<GradientStop Color="LightGreen" Offset="0.0" />
<GradientStop Color="LightGreen" Offset="0.24" />
<GradientStop Color="Yellow" Offset="0.25" />
<GradientStop Color="Yellow" Offset="0.49" />
<GradientStop Color="Orange" Offset="0.5" />
<GradientStop Color="Orange" Offset="0.74" />
<GradientStop Color="Red" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
Originally, the bars' 0% position was at the top (bar.Height = 0) and 100% was at the bottom (bar.Height = 15). The bar size would change by simply adjusting its Height property. Everything worked fine, but I would prefer the bars' 0% position to be at the bottom instead, ie. the bars will 'grow' upward.
Making the bars grow upward was no problem, but the problem I do have is that the gradient now moves with the rectangle, so that the top of the rectangle is always green, no matter how small it is. I understand that this is because I am now using Canvas.SetTop to move the top of the rectangles (bars) as well as change their height. How can I force the gradient to an absolute position, regardless of the position of the rectangle?
(background opacity)Sorry, I know the image is small, but you should just be able to make out that the middle bar starts from the top (green) and grows downward, ending in orange (50% -75% value). The left bar starts at the bottom (this is what I want), but the gradient in this bar moves with the height... this is the problem. Note that I'll reverse the gradient when I can fix this problem, so that red will represent the top 25%. In this example, the bottom quarter should be red, the next quarter orange and the remainder yellow.
I can't believe that there is no simple solution for this... come on brain-boxes. :) How about moving the absolute position of the gradient with the rectangle... is this possible???
(Relating post: Determining a computer's maximum hard drive data transfer rate programmatically with C#)
Update
Clip the rectangle with values set at runtime.
<Window.Resources>
<LinearGradientBrush x:Key="Quarters" StartPoint="0,0" EndPoint="0,1" >
<GradientStop Color="LightGreen" Offset="0.0" />
<GradientStop Color="LightGreen" Offset="0.24" />
<GradientStop Color="Yellow" Offset="0.25" />
<GradientStop Color="Yellow" Offset="0.49" />
<GradientStop Color="Orange" Offset="0.5" />
<GradientStop Color="Orange" Offset="0.74" />
<GradientStop Color="Red" Offset="0.75" />
<GradientStop Color="Red" Offset="1.0" />
</LinearGradientBrush>
</Window.Resources>
<Canvas Height="100">
<Rectangle Fill="{StaticResource Quarters}" Width="30" Height="100" Canvas.Bottom="0" Canvas.Left="0">
<Rectangle.Clip>
<RectangleGeometry x:Name="ClipRect" Rect="0, 100, 30, 100" />
</Rectangle.Clip>
</Rectangle>
</Canvas>
Code:
ClipRect.Rect = new Rect(0, 20, 30, 100); //80%
ClipRect.Rect = new Rect(0, 70, 30, 100); //30%
Original Solution
Use 2 rectangles for each bar.
One rectangle with 100% height and the colored gradient. Then overlay a black rectangle over the first rectangle. Adjust the black rectangles height(as you were before) to expose the gradient below.
eg If the value is 25% set the overlay height to 75%
I solved a similar issue using clipping. Create rectangles for 100% and fill with the brush. Then use clipping to only show part of the rectangle, see sample code below which shows two rectangles:
<Window x:Class="GradientTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Window.Resources>
<LinearGradientBrush x:Key="Quarters" StartPoint="0,1" EndPoint="0,0">
<GradientStop Color="LightGreen" Offset="0.0" />
<GradientStop Color="Yellow" Offset="0.25" />
<GradientStop Color="Orange" Offset="0.5" />
<GradientStop Color="Red" Offset="0.75" />
</LinearGradientBrush>
</Window.Resources>
<Canvas Height="100">
<!--21%-->
<Rectangle Fill="{StaticResource Quarters}" Width="30" Height="100" Canvas.Bottom="0" Canvas.Left="0">
<Rectangle.Clip>
<RectangleGeometry Rect="0, 79, 30, 100" />
</Rectangle.Clip>
</Rectangle>
<!--68%-->
<Rectangle Fill="{StaticResource Quarters}" Width="30" Height="100" Canvas.Bottom="0" Canvas.Left="40">
<Rectangle.Clip>
<RectangleGeometry Rect="0, 32, 30, 100" />
</Rectangle.Clip>
</Rectangle>
</Canvas>
</Window>
Yes, the 0,0 point of gradient fill's StartPoint/EndPoint always seems to be the top left of the object. So one way around that is to rotate the object 180 degrees using a RenderTransform. Then you can just set the height of the rectangle, but the gradient fill will stay anchored to the bottom.
精彩评论