I have two custom controls in wpf. One is Chart control and other is Circular Progress bar. Chart control has following relevant code.
> public int BarValue { get; set; }
> private void DrawData()
> {
> string data = File.ReadAllText(DataSource);
> string[] valueData = data.Split(';');
> string[] strValues = valueData[0].Split(',');
> string[] strYear = valueData[1].Split(',');
> double section = 525 / strValues.Length;
> rectSpace = (section * 20) / 100;
> rectWidth = (section * 80) / 100;
>
>
> for (int i = 0; i < strYear.Length; i++)
> {
>
> Rectangle rec = new Rectangle();
> rec.Width = rectWidth;
> rec.Height = Convert.ToDouble(strValues[i]);
>
> rec.Margin = new Thickness((rectSpace), (350 - rec.Height),
> 0,25);
> rec.Fill = BarsColor;
> panel.Children.Add(rec); rec.MouseDown += Rec_MouseDown; }
private void Rec_MouseDown(object sender,
> MouseButtonEventArgs e)
> {
> BarValue =Convert.ToInt32( ((Rectangle)sender).Height);
> }
Then the ProgressBar has a property Value.
I added both controls to MainWindow. If i click on one rectangle which is an mouseDown event as provided above, how i can change valueproperty of ProgressBar.
I tried
progCircle.Value = chart.BarValue;
in the mainWindow constructor. Not Working.
Any Idea.. Thanks
xml-Main
<Grid Margin="1,0,-318,-30" HorizontalAlignment="Center" Width="1418">
<Rectangle x:Name="MainRec" RadiusX="9" RadiusY="9" Margin="25,38,425,51" Opacity="0.75">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="#FF0F2A3C" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="TitleBar" Fill="#FF070E17" HorizontalAlignment="Left" Height="40" Margin="25,38,0,0" RadiusY="9" RadiusX="9" VerticalAlignment="Top" Width="968" Opacity="0.75" MouseDown="TitleBar_MouseDown"/>
<Label Content="Wools Valley" Foreground="Wheat" Margin="43,42,1225,565" Width="150" Height="30" FontSize="14"/>
<Ellipse x:Name="closeButton" HorizontalAlignment="Left" Height="20" Margin="960,52,0,0" VerticalAlignment="Top" Width="20" MouseDown="closeButton_MouseDown" Opacity="0.7" ToolTip="Close" RenderTransformOrigin="4.851,0.607">
<Ellipse.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DarkCyan" Offset="0"/>
<GradientStop Color="Black" Offset="1"/>
</LinearGradientBrush>
</Ellipse.Fill>
<Ellipse.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="closeButton"
Storyboard.TargetProperty="Opacity"
From="0.7" To="1" Duration="0:0:1"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Ellipse.Triggers>
</Ellipse>
<BarGraph2:BarGraph x:Name="bargraph" HorizontalAlignment="Left" Height="425" Margin="79,99,0,0" VerticalAlignment="Top" Width="654" DataSource="D:\\data3.txt" BarsColor="DarkCyan" AxisValueColor="Cyan" titleText="GDP Comparision" />
<ControlExamplesVS:ProgressCircle x:Name="progCircle" HorizontalAlignment="Left" Height="185" Margin="760,99,0,0" VerticalAlignment="Top" Width="184" IndicatorBrush="Cyan" BackgroundBrush="Transparent" ProgressBorderBrush="DarkCyan"/>
</Grid>
If you want to do it in code behind, add this piece of code after you added your controls in the MainWindow:
Binding bind= new Binding();
bind.Source = chart;
bind.Path = new PropertyPath("BarValue");
bind.Mode = BindingMode.TwoWay;
bind.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
BindingOperations.SetBinding(progCircle, CircuòarProgressBar.ValueProperty, bind);
If you have them already in xaml instead you can simply do the following:
<CircularProgressBar Value="{Binding ElementName = chart, Path = Value}"/>
<Chart x:Name = "chart"/>
Related
WPF
In the below code, I have a Canvas with child images. The child images are added by drag and drop and the Canvas itself is contained within an outer Grid. When using a magnifier over the child images, the source of the area being magnified is higher and left of the magnifier. (Source code adapted from: A Magnifier)
How is this fixed?
The resulting image. The center of the Magnifier should be over the "S", not down to the right of it.
XAML:
<ScrollViewer Name="TheScrollViewer" Grid.Row ="2" Grid.RowSpan="2" Grid.Column="1" Grid.ColumnSpan="2" VerticalScrollBarVisibility="Auto" >
<Grid ShowGridLines="True" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Canvas Grid.Column="1" Grid.Row="1" Background="Blue" Name="mainUI" PreviewMouseMove="OnMoveOverMainUI"
Panel.ZIndex="{Binding ImageLayer.ZIndex}" Visibility="{Binding ImageLayer.Visibility}" >
<i:Interaction.Behaviors>
<b:ImageCanvasBehavior Source ="{Binding ImageLayer.Source}" />
</i:Interaction.Behaviors>
</Canvas>
<Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1" Grid.Row="1" Panel.ZIndex="1000" >
<Canvas Name="magnifierCanvas" IsHitTestVisible="False"
Visibility="{Binding ElementName=checkEnableMagnifier,Path=IsChecked, Converter={StaticResource BoolToVis}}">
<Line StrokeThickness="30" X1="200" Y1="200" X2="300" Y2="300">
<Line.Stroke>
<LinearGradientBrush StartPoint="0.78786,1" EndPoint="1,0.78786">
<GradientStop Offset="0" Color="DarkGreen" />
<GradientStop Offset="0.9" Color="LightGreen" />
<GradientStop Offset="1" Color="Green" />
</LinearGradientBrush>
</Line.Stroke>
</Line>
<Ellipse Width="250" Height="250" Fill="White" />
<Ellipse Width="250" Height="250" Name="magnifierEllipse" StrokeThickness="3">
<Ellipse.Fill>
<VisualBrush ViewboxUnits="Absolute" Viewbox="0,0,50,50"
ViewportUnits="RelativeToBoundingBox" Viewport="0,0,1,1"/>
</Ellipse.Fill>
<Ellipse.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#AAA" />
<GradientStop Offset="1" Color="#111" />
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Ellipse Canvas.Left="2" Canvas.Top="2" StrokeThickness="4" Width="246" Height="246">
<Ellipse.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="#555" />
<GradientStop Offset="1" Color="#EEE" />
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
</Canvas>
</Canvas>
</Grid>
</ScrollViewer>
Code-Behind:
private void ZoomChanged(object sender, EventArgs e)
{
if (magnifierEllipse != null)
{
VisualBrush b = (VisualBrush)magnifierEllipse.Fill;
Rect viewBox = b.Viewbox;
double val = sliderTargetSize.Value;
viewBox.Width = val;
viewBox.Height = val;
b.Viewbox = viewBox;
}
}
private void OnMoveOverMainUI(object sender, MouseEventArgs e)
{
VisualBrush b = (VisualBrush)magnifierEllipse.Fill;
Point pos = e.MouseDevice.GetPosition(mainUI);
Rect viewBox = b.Viewbox;
double xoffset = viewBox.Width / 2.0;
double yoffset = viewBox.Height / 2.0;
viewBox.X = pos.X - xoffset;
viewBox.Y = pos.Y - yoffset;
b.Viewbox = viewBox;
Canvas.SetLeft(magnifierCanvas, pos.X - magnifierEllipse.Width / 2);
Canvas.SetTop(magnifierCanvas, pos.Y - magnifierEllipse.Height / 2);
}
Fixed the problem. This procedure works well when in its own window--not so when in a user control inside a grid.
private void OnMoveOverMainUI(object sender, MouseEventArgs e)
{
VisualBrush b = (VisualBrush)magnifierEllipse.Fill;
Point pos = e.MouseDevice.GetPosition(mainUI);
Rect viewBox = b.Viewbox;
double xoffset = viewBox.Width / 2.0;
double yoffset = viewBox.Height / 2.0;
viewBox.X = pos.X - xoffset;
viewBox.Y = pos.Y - yoffset;
b.Viewbox = viewBox;
Canvas.SetLeft(magnifierCanvas, pos.X - magnifierEllipse.Width / 2);
Canvas.SetTop(magnifierCanvas, pos.Y - magnifierEllipse.Height / 2);
}
The corrected version I needed is:
private void OnMoveOverMainUI(object sender, MouseEventArgs e)
{
// Get position of the mainUI to its ancestor the MainGrid
Point relativePoint = mainUI.TransformToAncestor(MainGrid)
.Transform(new Point(0, 0));
// Get position of the Mouse relative to the mainUI
Point pp = e.MouseDevice.GetPosition(mainUI);
// Get position of the mouse relative to the MainGrid.
Point pos = new Point(pp.X + relativePoint.X, pp.Y + relativePoint.Y);
VisualBrush b = (VisualBrush)magnifierEllipse.Fill;
Rect viewBox = b.Viewbox;
double xoffset = viewBox.Width / 2.0;
double yoffset = viewBox.Height / 2.0;
viewBox.X = pos.X - xoffset;
viewBox.Y = pos.Y - yoffset;
b.Viewbox = viewBox;
Canvas.SetLeft(magnifierCanvas, pos.X - magnifierEllipse.Width / 2 - relativePoint.X);
Canvas.SetTop(magnifierCanvas, pos.Y - magnifierEllipse.Height / 2 - relativePoint.Y);
}
I'm trying to rotate Arrow according to angle which is determined by a random number.
the arrow angle does change but the animation is not working.
<Grid>
<ed:BlockArrow x:Name="blockArrow" Fill="Black" HorizontalAlignment="Left" Height="13.299" Orientation="Left" Stroke="Black" VerticalAlignment="Top" Width="100" Margin="84.571,165.951,0,0" RenderTransformOrigin="1,0.5">
<ed:BlockArrow.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform x:Name="ArrowTransform" Angle="{Binding ElementName=MeterValueTextBox, Path=Text}" />
<TranslateTransform/>
</TransformGroup>
</ed:BlockArrow.RenderTransform>
</ed:BlockArrow>
<Ellipse Fill="Black" HorizontalAlignment="Left" Height="25" Stroke="Black" VerticalAlignment="Top" Width="25" Margin="172.865,159.568,0,0"/>
<TextBlock
Text="Type value:"
FontSize="16"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="57.976,245.873,0,0"
/>
<TextBox
x:Name="MeterValueTextBox"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="100"
Margin="140,245.873,0,0"
Text="{Binding Meter, UpdateSourceTrigger=PropertyChanged}"
>
<TextBox.Triggers>
<EventTrigger RoutedEvent="TextBox.TextChanged">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="ArrowTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="{Binding OldMeterValue}" To="{Binding Meter}" Duration="0:0:0:1"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</TextBox.Triggers>
</TextBox>
</Grid>
and the view model is:
public class MainViewModel : ViewModelBase
{
private float _meter;
public float Meter
{
get { return _meter; }
set
{
if (!Equals(_meter, value))
{
OldMeterValue = _meter;
_meter = value;
OnPropertyChanged();
}
}
}
private float _oldMeterValue;
public float OldMeterValue
{
get { return _oldMeterValue; }
set
{
if (_oldMeterValue != value)
{
_oldMeterValue = value;
OnPropertyChanged();
}
}
}
public MainViewModel()
{
DisplayName = "Benchmark Application";
OldMeterValue = 0;
Meter = 0;
var meterTimer = new Timer
{
Interval = 1000
};
meterTimer.Elapsed += MeterTimerOnElapsed;
meterTimer.Start();
}
private void MeterTimerOnElapsed(object sender, ElapsedEventArgs elapsedEventArgs)
{
var randomNumber = new Random();
var meterValue = randomNumber.Next(0, 180);
Meter = meterValue;
}
}
as for now, the arrow bounces from old value to new value but without animation.
please assist...
Duration property of your animation seems too fast (one milisecond??). Try to set it to a greater value to make it obvious, for example, 5 seconds :
<DoubleAnimation
Storyboard.TargetName="ArrowTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="{Binding OldMeterValue}" To="{Binding Meter}" Duration="0:0:5"
/>
[Reference]
I have read a XAML file using XAMLReader which refer some custom assemblies. Reading a simple XAML file is easy as I can convert the file to stream and then call XAMLReader.Load().During Xaml load code throws exception for the custom assemblies in xmlns .Below is the code added in a WPF application:
public MainWindow()
{
InitializeComponent();
StreamReader streamReader = new StreamReader(Filepath);
string s = streamReader.ReadToEnd();
var index = s.IndexOf("Canvas");
s = s.Insert(index + 6, "xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"");
var c = XamlReader.Parse(s) as Canvas;
}
and my XAML looks like:
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns:IN_SE_BlendObjects_FactoryCast_Shapes_BasicShapes="clr-namespace:IN.SE.BlendObjects.FactoryCast.Shapes.BasicShapes;assembly=IN.SE.BlendObjects.FactoryCast" xmlns:IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes="clr-namespace:IN.SE.BlendObjects.FactoryCast.Shapes.Extended_Shapes;assembly=IN.SE.BlendObjects.FactoryCast" xmlns:IN_SE_BlendObjects_FactoryCast_Control_Animation="clr-namespace:IN.SE.BlendObjects.FactoryCast.Control.Animation;assembly=IN.SE.BlendObjects.FactoryCast" Canvas.Left="0" Canvas.Top="0" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top">
<Canvas.Background>
<SolidColorBrush Color="#FFFFFFFF" />
</Canvas.Background>
<IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes:FCastLinearGauge Canvas.Left="347.632293701172" Canvas.Top="215.769805908203" Width="328.600006103516" Height="131.440002441406" Margin="0,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" LabelText="" LabelFontFamily="Arial" LabelFontSize="12" IsLabelBold="False" IsLabelItalic="False" ShapeCornerStyle="Rounded" IsBackgroundVisible="True" BorderWidth="0" MajorScaleDivision="2" MinorScaleDivision="5" ScaleContainerType="Rectangle" IsLimitScaleVisible="True" ScalePrecision="1" MajorScaleHeight="15" MinorScaleHeight="8" ScaleValueFontFamily="Arial" ScaleValueSize="13" IsScaleValueBold="False" IsScaleValueItalic="False" IsValueVisible="True" ValueFontSize="12" IsValueBold="False" IsValueItalic="False" ValueTextAlignment="Center" Variable="Name:Variable1,Type:,DefaultValue:" MinEUValue="0" MinValue="0" MaxEUValue="100" MaxValue="100" HHLimitValue="80" HLimitValue="60" LLimitValue="40" LLLimitValue="20">
<IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes:FCastLinearGauge.LabelColor>
<SolidColorBrush Color="#FF000000" />
</IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes:FCastLinearGauge.LabelColor>
<IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes:FCastLinearGauge.BackGroundColor>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" MappingMode="RelativeToBoundingBox" SpreadMethod="Pad" Opacity="1">
<GradientStop Color="#FF095050" Offset="1" />
<GradientStop Color="#FFA2B8BA" Offset="0.354999989271164" />
</LinearGradientBrush>
</IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes:FCastLinearGauge.BackGroundColor>
</IN_SE_BlendObjects_FactoryCast_Shapes_Extended_Shapes:FCastLinearGauge>
</Canvas>
I want to make a custumized Image Control like MSN with Green light in border
You should use a ContentControl with a custom template. And set the content of the control to the image you want to display.
<ContentControl Template="{DynamicResource TheTemplate}"><Image/></ContentControl>
Then define the style somewhere in your resource dictionary.
<ControlTemplate TargetType="{x:Type ContentControl}">
<Grid>
<!-- Add some fancy borders and colors here -->
<ContentPresenter/>
</Grid>
</ControlTemplate>
I would recommend a UserControl, something like this:
<UserControl x:Class="Test.UserControls.BorderedImageControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Border CornerRadius="{Binding CornerRadius}" Padding="{Binding BorderThickness}" BorderThickness="1">
<Border.BorderBrush>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFE5E5E5" Offset="0"/>
<GradientStop Color="#FF15A315" Offset="1"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="#FF67FF68" Offset="1"/>
<GradientStop Color="#FF75E476" Offset="0.496"/>
<GradientStop Color="#FF0FC611" Offset="0.509"/>
</LinearGradientBrush>
</Border.Background>
<Border.Child>
<Image Source="{Binding Source}"/>
</Border.Child>
</Border>
</UserControl>
namespace Test.UserControls
{
public partial class BorderedImageControl : UserControl
{
public static readonly DependencyProperty SourceProperty = Image.SourceProperty.AddOwner(typeof(BorderedImageControl));
public ImageSource Source
{
get { return (ImageSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty = Border.CornerRadiusProperty.AddOwner(typeof(BorderedImageControl));
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, CornerRadius); }
}
public static readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(BorderedImageControl), new UIPropertyMetadata(new Thickness()));
public Thickness BorderThickness
{
get { return (Thickness)GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
public BorderedImageControl()
{
InitializeComponent();
}
}
}
This is comparatively simple, if you want those custom curved shapes you probably need to work with paths instead of a border with corner radius.
Usage example:
<uc:BorderedImageControl Source="http://www.gravatar.com/avatar/c35af79e54306caedad37141f13de30c?s=32&d=identicon&r=PG"
CornerRadius="20" BorderThickness="10" MaxWidth="100" Margin="5"/>
Looks like this:
My problem is certainly right on my face but I can't see it...
I am building a very simple user control - a 3D ellipse - and I expose two properties: LightColor and DarkColor. I need to bind these properties to the gradient in my user control, but it is not showing any color at all. Here's my usercontrol:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestBrushes"
mc:Ignorable="d"
x:Class="TestBrushes._3DEllipse"
x:Name="UserControl"
d:DesignWidth="200" d:DesignHeight="200">
<Grid x:Name="LayoutRoot">
<Ellipse Name="MainEllipse" Stroke="{x:Null}">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,1.1">
<GradientStop Color="{Binding ElementName=UserControl, Path=LightColor}" Offset="1"/>
<GradientStop Color="{Binding ElementName=UserControl, Path=DarkColor}" Offset="0"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Name="TopReflectionEllipse" Stroke="{x:Null}" Margin="38,0,38,0" VerticalAlignment="Top" Height="90">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,0">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1" ScaleY="1"/>
<SkewTransform AngleX="0" AngleY="0" CenterX="0.5" CenterY="0.5"/>
<RotateTransform Angle="0" CenterX="0.5" CenterY="0.5"/>
<TranslateTransform X="0" Y="0"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#A5FFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</UserControl>
and here's my code-behind:
public partial class _3DEllipse
{
public _3DEllipse()
{
InitializeComponent();
}
public Color DarkColor { get; set; }
public Color LightColor { get; set; }
}
If I assign colors as opposed to the binding shown in the code, it works ok, but I want to use the properties I am exposing. What am I doing wrong?
Thanks!
Your issue is likely that you aren't notifiying the UserControl of changes made to the value of the DarkColor and LightColor properties. To do so you'll need to implement the INotifyPropertyChanged interface. The purpose of this interface is to make UI components aware of when the value they're bound to is updated; they subscribe to the PropertyChanged event that is exposed by implementing the interface.
A sample implementation is below, I've left the DarkColor property alone, but it would be updated in the same fashion.
public partial class _3DEllipse : INotifyPropertyChanged
{
private Color _lightColor;
public _3DEllipse()
{
InitializeComponent();
}
// interface implementation
public event PropertyChangedEventHandler PropertyChanged;
public Color DarkColor { get; set; }
public Color LightColor
{
get { return _lightColor; }
set
{
// only update value if its changed
if ( _lightColor == value )
{
return;
}
_lightColor = value;
OnPropertyChanged("LightColor");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if ( PropertyChanged == null ) return;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}