Reputation: 19
I am trying to create a Linear Gauge that can also rotate on itself, using C#/WPF. The filling percentage of the gauge, as well as its direction will depend on 2 parameters that will be updated through data binding.
I approached the problem by creating a flexible grid with 2 columns that have widths that depend on a parameter (this will be the percentage by which the gauge is filled; it my example I vary it over time). I have a black rectangle filling the 2 columns at all time; its size is therefore constant; and an orange rectangle that only fills the first column; its width depends on the grid width and vary over time.
When I Try to rotate both rectangles based on another parameter (in my code it's a constant of 45 degrees), it gives me troubles. The Black and Orange rectangles are not aligned anymore (they remain parallel though). They are aligned only when the Orange rectangle fills the entire space. I tried to translate the Orange rectangle to the Black one, but it does not seem to work. I am not even sure if this is a correct approach. Does any of you have a way to fix this code or maybe suggest another approach?
XAML:
<Grid x:Name="AdjustableGrid" Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ThrusterPower}" />
<ColumnDefinition Width="{Binding ThrusterPowerOpposite}" />
</Grid.ColumnDefinitions>
<Rectangle x:Name="GaugeBackground" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Stretch="Fill" Fill="Black" RenderTransformOrigin="0.5,0.5">
<Rectangle.RenderTransform>
<RotateTransform Angle="45" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="Gauge" Grid.Row="1" Stretch="Fill" Fill="Orange" Margin="0,3,0,3" RenderTransformOrigin="0.5,0.5" >
<Rectangle.RenderTransform>
<RotateTransform Angle="45" />
</Rectangle.RenderTransform>
</Rectangle>
</Grid>
</Grid>
Main:
void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (Tpower <= 100 && Tdir)
{
Tpower += dt;
}
else
{
Tdir = false;
}
if (Tpower >= 0 && !Tdir)
{
Tpower -= dt;
}
else
{
Tdir = true;
}
appData.UpdateThrusterPower(Tpower.ToString());
appData.UpdateThrusterPowerOpposite((100 - Tpower).ToString());
Point relative_distance = GaugeBackground.TranslatePoint(new Point(0, 0), Gauge);
Console.WriteLine(relative_distance);
TranslateTransform translateTransform1 = new TranslateTransform();
RotateTransform rotateTransform1 = new RotateTransform();
translateTransform1.X = relative_distance.X;
translateTransform1.Y = relative_distance.Y;
rotateTransform1.Angle = 45;
TransformGroup transformGroup1 = new TransformGroup();
transformGroup1.Children.Add(translateTransform1);
transformGroup1.Children.Add(rotateTransform1);
Gauge.RenderTransform = transformGroup1;
}
Upvotes: 0
Views: 1281
Reputation: 16128
A ProgressBar is probably a better idea, it's specifically designed for this sort of thing. Here's a very simple one with a border wrapped around it...the trigger/storyboard animation code is for illustrative purposes only and can be stripped out:
<Border Width="200" Height="50" BorderBrush="Black" BorderThickness="5" HorizontalAlignment="Center" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<RotateTransform x:Name="theTransform" Angle="0" />
</Border.RenderTransform>
<Border.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="theTransform" Storyboard.TargetProperty="Angle"
From="0" To="360" Duration="0:0:5" RepeatBehavior="Forever" />
<DoubleAnimation
Storyboard.TargetName="theProgressBar" Storyboard.TargetProperty="Value"
From="0" To="100" Duration="0:0:5" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<ProgressBar Name="theProgressBar" Minimum="0" Maximum="100" Value="0" Foreground="Orange" Background="DarkGray" BorderThickness="0" />
</Border>
Upvotes: 1