I have a program that loads pictures from an erp document handling source and allows them to be moved and resized by touch or mouse. There is a class called Picture:
using System.Windows;
using System.Windows.Controls;
namespace DocumentHandlingTouch
{
/// <summary>
/// Interaction logic for Picture.xaml
/// </summary>
public partial class Picture : UserControl
{
public Picture()
{
InitializeComponent();
DataContext = this;
}
public string ImagePath
{
get { return (string)GetValue(ImagePathProperty); }
set { SetValue(ImagePathProperty, value); }
}
public string ImageName
{
get { return (string)GetValue(ImageNameProperty); }
set { SetValue(ImageNameProperty, value); }
}
public static readonly DependencyProperty ImageNameProperty =
DependencyProperty.Register("ImageName", typeof(string), typeof(Picture), new UIPropertyMetadata(""));
// Using a DependencyProperty as the backing store for ImagePath. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImagePathProperty =
DependencyProperty.Register("ImagePath", typeof(string), typeof(Picture), new UIPropertyMetadata(""));
public string OriginalImagePath
{
get { return (string)GetValue(OriginalImagePathProperty); }
set { SetValue(OriginalImagePathProperty, value); }
}
public static readonly DependencyProperty OriginalImagePathProperty =
DependencyProperty.Register("OriginalImagePath", typeof(string), typeof(Picture), new UIPropertyMetadata(""));
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
// Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty =
DependencyProperty.Register("Angle", typeof(double), typeof(Picture), new UIPropertyMetadata(0.0));
public double ScaleX
{
get { return (double)GetValue(ScaleXProperty); }
set { SetValue(ScaleXProperty, value); }
}
// Using a DependencyProperty as the backing store for ScaleX. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScaleXProperty =
DependencyProperty.Register("ScaleX", typeof(double), typeof(Picture), new UIPropertyMetadata(1.0));
public double ScaleY
{
get { return (double)GetValue(ScaleYProperty); }
set { SetValue(ScaleYProperty, value); }
}
// Using a DependencyProperty as the backing store for ScaleY. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ScaleYProperty =
DependencyProperty.Register("ScaleY", typeof(double), typeof(Picture), new UIPropertyMetadata(1.0));
public double X
{
get { return (double)GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
// Using a DependencyProperty as the backing store for X. This enables animation, styling, binding, etc...
public static readonly DependencyProperty XProperty =
DependencyProperty.Register("X", typeof(double), typeof(Picture), new UIPropertyMetadata(0.0));
public double Y
{
get { return (double)GetValue(YProperty); }
set { SetValue(YProperty, value); }
}
// Using a DependencyProperty as the backing store for Y. This enables animation, styling, binding, etc...
public static readonly DependencyProperty YProperty =
DependencyProperty.Register("Y", typeof(double), typeof(Picture), new UIPropertyMetadata(0.0));
}
}
Here is the class that loads the pictures. It uses a textbox under the picture to display the filename:
private void LoadPictures()
{
_canvas.Children.Clear();
double x = -10;
double y = 0;
foreach (DictionaryEntry filePath in files)
{
try
{
Picture p = new Picture();
ToolTip t = new ToolTip();
t.Content = filePath.Value;
p.ToolTip = t;
///////////////////Heres where the textblock is set////////////////
TextBlock tb = new TextBlock();
tb.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
tb.FontWeight = FontWeights.UltraBlack;
tb.TextWrapping = TextWrapping.WrapWithOverflow;
tb.Width = filePath.Value.ToString().ToString().Length * 12;// 125;
tb.Height = 25;
tb.Text = filePath.Value.ToString();
Canvas.SetTop(tb, y+ 25);
Canvas.SetLeft(tb, x + 25);
//////////////////////////////////////////////////////////////////
//External Program
if (Path.GetExtension(filePath.Key.ToString()) == ".pdf")
{
var path = new Uri("pack://application:,,,/Document%20Handling%20Viewer;component/Resources/pdf.png", UriKind.Absolute);
p.ImagePath = path.ToString();
p.OriginalImagePath = filePath.Key.ToString();
p.ImageName = filePath.Value.ToString();
}
else
{
p.ImagePath = filePath.Key.ToString();
p.OriginalImagePath = filePath.Key.ToString();
p.ImageName = filePath.Value.ToString();
}
p.Width = 100;
p.X = x;
p.Y = y;
x = x + p.Width + 5;
if (x + p.Width >= System.Windows.SystemParameters.PrimaryScreenWidth)
{
y = y + 150;
x = 0;
}
Dispatcher.Invoke((Action)(() => _canvas.Children.Add(p)));
}
catch (Exception ex)
{
MessageBox.Show("Error:" + ex.Message, "File Load Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
The problem is the textblock doesn't change its style...its not bold, its not vertically placed on the bottom and it doesnt wrap. It just hugs the picture in a plain old font.
What am I doing wrong here?
Edit I commented out the TextBlock and the image path still shows up. Is it the ImagePath dependency property that's showing up? i'm confused
You forgot to add textblock to canvas:
_canvas.Children.Add(tb);
Edit
if you have textblock in Picture usercontrol, you must not create new in code behind.
in Picture.xaml you should define name of the textblock:
<TextBlock x:Name="TextBlock1 />
in the c# code replace line: TextBlock tb = new TextBlock(); with:
TextBlock tb = p.TextBlock1;
Related
I am creating an application based on one of the example applications in the HelixToolkit (SurfacePlot) found in the ExampleBrwoser.
The SurfacePlotVisual3D class has three dependency properties, I tried to add another one simply by copying/renaming an existing one, but it does not work.
XAML
<h:HelixViewport3D ZoomExtentsWhenLoaded="True" ShowCoordinateSystem="True">
<local:SurfacePlotVisual3D CurrentX="{Binding CurrentX}" Points="{Binding Data}" ColorValues="{Binding ColorValues}" SurfaceBrush="{Binding SurfaceBrush}" />
</h:HelixViewport3D>
The "CurrentX" property is the one I tried to add.
SurfacePlotVisual3D.cs
public class SurfacePlotVisual3D : ModelVisual3D
{
public static readonly DependencyProperty CurrentXProperty =
DependencyProperty.Register("CurrentX", typeof(double), typeof(SurfacePlotVisual3D),
new UIPropertyMetadata(ModelChanged));
public static readonly DependencyProperty PointsProperty =
DependencyProperty.Register("Points", typeof(Point3D[,]), typeof(SurfacePlotVisual3D),
new UIPropertyMetadata(null, ModelChanged));
public static readonly DependencyProperty ColorValuesProperty =
DependencyProperty.Register("ColorValues", typeof(double[,]), typeof(SurfacePlotVisual3D),
new UIPropertyMetadata(null, ModelChanged));
public static readonly DependencyProperty SurfaceBrushProperty =
DependencyProperty.Register("SurfaceBrush", typeof(Brush), typeof(SurfacePlotVisual3D),
new UIPropertyMetadata(null, ModelChanged));
...
...
public Brush SurfaceBrush
{
get { return (Brush)GetValue(SurfaceBrushProperty); }
set { SetValue(SurfaceBrushProperty, value); }
}
public double CurrentX
{
get { return (double)GetValue(CurrentXProperty); }
set { SetValue(CurrentXProperty, value); }
}
private static void ModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((SurfacePlotVisual3D)d).UpdateModel();
}
MainWindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.DataContext = new MainViewModel();
}
}
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
...
...
public Func<double, double, double> Function { get; set; }
public Point3D[,] Data { get; set; }
public double[,] ColorValues { get; set; }
public double CurrentX { get; set; }
public MainViewModel()
{
CurrentX = 6;
MinX = 0;
MaxX = 3;
MinY = -2;
MaxY = 2;
Rows = 100;
Columns = 50;
Function = (x, y) => Math.Pow(Math.E, (-1) * Math.Pow(y, 2)) * 3*Math.Sin(2*x) + 2;
ColorCoding = ColorCoding.ByGradientX;
UpdateModel();
}
...
...
}
I can change "Data", "ColorValues" and "Function" in the MainViewModel and the effect is immediately visible in the plot, but the CurrentX property wont do anything.
As the comment of Anton suggested the missing default value was the problem.
public static readonly DependencyProperty CurrentXProperty =
DependencyProperty.Register("CurrentX", typeof(double), typeof(SurfacePlotVisual3D),
new UIPropertyMetadata((double)0, ModelChanged));
This fixed the problem. The (double)0 cast is needed because without it you will get an exception because "object" is not "double" (in my case). So thanks a lot Anton, made my day!
First,I need to draw a vertical line and a horizontal line. I used the GeometryGroup to realize this.It looks like this
The custom class code:
public class QuadrantGate1 : Shape
{
#region Constructors
/// <summary>
/// Instantiate a new instance of a line.
/// </summary>
public QuadrantGate1()
{
}
#endregion
#region Dynamic Properties
public double VerticalY1
{
get { return (double)GetValue(VerticalY1Property); }
set { SetValue(VerticalY1Property, value); }
}
// Using a DependencyProperty as the backing store for VerticalY1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VerticalY1Property =
DependencyProperty.Register("VerticalY1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double VerticalY2
{
get { return (double)GetValue(VerticalY2Property); }
set { SetValue(VerticalY2Property, value); }
}
// Using a DependencyProperty as the backing store for VerticalY2. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VerticalY2Property =
DependencyProperty.Register("VerticalY2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double VerticalX
{
get { return (double)GetValue(VerticalXProperty); }
set { SetValue(VerticalXProperty, value); }
}
// Using a DependencyProperty as the backing store for VerticalX1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VerticalXProperty =
DependencyProperty.Register("VerticalX", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double HorizontalX1
{
get { return (double)GetValue(HorizontalX1Property); }
set { SetValue(HorizontalX1Property, value); }
}
// Using a DependencyProperty as the backing store for HorizontalX1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HorizontalX1Property =
DependencyProperty.Register("HorizontalX1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double HorizontalX2
{
get { return (double)GetValue(HorizontalX2Property); }
set { SetValue(HorizontalX2Property, value); }
}
// Using a DependencyProperty as the backing store for HorizontalX2. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HorizontalX2Property =
DependencyProperty.Register("HorizontalX2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double HorizontalY
{
get { return (double)GetValue(HorizontalYProperty); }
set { SetValue(HorizontalYProperty, value); }
}
// Using a DependencyProperty as the backing store for HorizontalY. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HorizontalYProperty =
DependencyProperty.Register("HorizontalY", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
#endregion
#region Protected Methods and Properties
protected override Geometry DefiningGeometry
{
get
{
_geometryGroup = new GeometryGroup();
_geometryGroup.FillRule = FillRule.Nonzero;
DrawTwoLinesGeometry(_geometryGroup);
_path = new Path();
_path.Data = _geometryGroup;
return _geometryGroup;
}
}
private void DrawTwoLinesGeometry(GeometryGroup geometryGroup)
{
try
{
_lineGeometry1 = new LineGeometry()
{
StartPoint = new Point { X = HorizontalX1, Y = HorizontalY },
EndPoint = new Point { X = HorizontalX2, Y = HorizontalY }
};
_lineGeometry2 = new LineGeometry()
{
StartPoint = new Point { X = VerticalX, Y = VerticalY1 },
EndPoint = new Point { X = VerticalX, Y = VerticalY2 }
};
_geometryGroup.Children.Add(_lineGeometry1);
_geometryGroup.Children.Add(_lineGeometry2);
}
catch (Exception e)
{
}
}
#endregion
#region Private Methods and Members
private GeometryGroup _geometryGroup;
private LineGeometry _lineGeometry1;
private LineGeometry _lineGeometry2;
private Path _path;
#endregion
}
The xaml code:
Second,I need to move the two lines. When the mouse is on the horizontal line,the horizontal line can be moved up or down,the vertical line stays still.
When the mouse is on the vertical line,the vertical line can be moved left or right,the horizontal line stays still.
When the mouse is on the cross point of the two lines,both of the two lines can be moved,and the horizontal line moved up and down,the vertical line moved left and right.
I want to move two lines first,so the custom class code:
public class QuadrantGate1 : Shape
{
#region Constructors
/// <summary>
/// Instantiate a new instance of a line.
/// </summary>
public QuadrantGate1()
{
this.MouseDown += QuadrantGate_MouseDown;
this.MouseMove += QuadrantGate_MouseMove;
this.MouseLeftButtonUp += QuadrantGate_MouseLeftButtonUp;
}
#endregion
#region Dynamic Properties
public double VerticalY1
{
get { return (double)GetValue(VerticalY1Property); }
set { SetValue(VerticalY1Property, value); }
}
// Using a DependencyProperty as the backing store for VerticalY1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VerticalY1Property =
DependencyProperty.Register("VerticalY1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double VerticalY2
{
get { return (double)GetValue(VerticalY2Property); }
set { SetValue(VerticalY2Property, value); }
}
// Using a DependencyProperty as the backing store for VerticalY2. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VerticalY2Property =
DependencyProperty.Register("VerticalY2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double VerticalX
{
get { return (double)GetValue(VerticalXProperty); }
set { SetValue(VerticalXProperty, value); }
}
// Using a DependencyProperty as the backing store for VerticalX1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VerticalXProperty =
DependencyProperty.Register("VerticalX", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double HorizontalX1
{
get { return (double)GetValue(HorizontalX1Property); }
set { SetValue(HorizontalX1Property, value); }
}
// Using a DependencyProperty as the backing store for HorizontalX1. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HorizontalX1Property =
DependencyProperty.Register("HorizontalX1", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double HorizontalX2
{
get { return (double)GetValue(HorizontalX2Property); }
set { SetValue(HorizontalX2Property, value); }
}
// Using a DependencyProperty as the backing store for HorizontalX2. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HorizontalX2Property =
DependencyProperty.Register("HorizontalX2", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(256.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
public double HorizontalY
{
get { return (double)GetValue(HorizontalYProperty); }
set { SetValue(HorizontalYProperty, value); }
}
// Using a DependencyProperty as the backing store for HorizontalY. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HorizontalYProperty =
DependencyProperty.Register("HorizontalY", typeof(double), typeof(QuadrantGate1), new FrameworkPropertyMetadata(128.0, FrameworkPropertyMetadataOptions.AffectsMeasure));
#endregion
#region Protected Methods and Properties
protected override Geometry DefiningGeometry
{
get
{
_geometryGroup = new GeometryGroup();
_geometryGroup.FillRule = FillRule.Nonzero;
DrawTwoLinesGeometry(_geometryGroup);
_path = new Path();
_path.Data = _geometryGroup;
return _geometryGroup;
}
}
private void DrawTwoLinesGeometry(GeometryGroup geometryGroup)
{
try
{
_lineGeometry1 = new LineGeometry()
{
StartPoint = new Point { X = HorizontalX1, Y = HorizontalY },
EndPoint = new Point { X = HorizontalX2, Y = HorizontalY }
};
_lineGeometry2 = new LineGeometry()
{
StartPoint = new Point { X = VerticalX, Y = VerticalY1 },
EndPoint = new Point { X = VerticalX, Y = VerticalY2 }
};
_geometryGroup.Children.Add(_lineGeometry1);
_geometryGroup.Children.Add(_lineGeometry2);
}
catch (Exception e)
{
}
}
#endregion
#region Events Methods
private void QuadrantGate_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(QuadrantGate1))
{
this.mouseBefore = e.GetPosition(this);
QuadrantGate1 quadrantGate = (QuadrantGate1)e.OriginalSource;
startBefore.X = VerticalX;
startBefore.Y = HorizontalY;
quadrantGate.CaptureMouse();
}
}
GeometryCollection GeometryGroupChildren(GeometryGroup geometryGroup)
{
GeometryCollection geometries = new GeometryCollection();
if (geometryGroup == null)
return null;
else
{
geometries = geometryGroup.Children;
return geometries;
}
}
private void QuadrantGate_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
if (e.OriginalSource != null && e.OriginalSource.GetType() == typeof(QuadrantGate1))
{
QuadrantGate1 quadrantGate = (QuadrantGate1)e.OriginalSource;
Point p = e.GetPosition(this);
VerticalX = startBefore.X + (p.X - mouseBefore.X);
HorizontalY = startBefore.Y + (p.Y - mouseBefore.Y);
}
}
}
private void QuadrantGate_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource.GetType() == typeof(QuadrantGate1))
{
QuadrantGate1 quadrantGate = (QuadrantGate1)e.OriginalSource;
quadrantGate.ReleaseMouseCapture();
}
}
#endregion
#region Private Methods and Members
private GeometryGroup _geometryGroup;
private LineGeometry _lineGeometry1;
private LineGeometry _lineGeometry2;
private Path _path;
Point mouseBefore;
Point startBefore;
#endregion
}
But the two lines don't move as I want.The movement of lines is inconsistent with mouse.
The strange part is if one of these lines _geometryGroup.Children.Add(_lineGeometry1);or this _geometryGroup.Children.Add(_lineGeometry2); is commented out, the rest line can be moved sucessfully. This is the horizontal line:
,
and the vertical line:
By implementing your code, I see render issue and you could also see if you just do the mouse down & minimize the screen, open it again you can see the line moved to a different location.
Instead of GeometryGroup, could you try StreamGeometryContext, below is the code DefiningGeometry get Property.
protected override Geometry DefiningGeometry
{
get
{
StreamGeometry geometry = new StreamGeometry();
geometry.FillRule = FillRule.EvenOdd;
using (StreamGeometryContext ctx = geometry.Open())
{
ctx.BeginFigure(new Point(HorizontalX1, HorizontalY), true /* is filled */, true /* is closed */);
ctx.LineTo(new Point(HorizontalX2, HorizontalY), true /* is stroked */, false /* is smooth join */);
ctx.BeginFigure(new Point(VerticalX, VerticalY1), true /* is filled */, true /* is closed */);
ctx.LineTo(new Point(VerticalX, VerticalY2), true /* is stroked */, false /* is smooth join */);
}
//geometry.Freeze();
_path = new Path();
_path.Data = geometry;
return geometry;
}
}
I've been interested in WPF bindings in c# and tried to bind a control to the mouse position, but after getting a frustrating "The name "[control]" does not exist in the namespace "clr-namespace:[namespace]" every time I pasted the xaml code into the editor I decided it wasn't worth the time to investigate the quirk.
Now I am attempting to simply implement a binded Arc drawing example from Stack Overflow and am getting the same eror again. (All the code for a short runnable example can be found there)
So I've combed through all the Stack Overflow solution to this issue (it actually seems rather widespread) with what appear to be sporadic and inexpiable workarounds and fixes.
This question says that
If nothing else is possible, comment the lines which use the namespace, rebuild, and then build the full project again.
I also tried rebuilding the project, reopening Visual Studio. Nothing
helped. I finally commented xaml, rebuilt the project, uncommented
xaml and it finally worked! Strange issue.
This one said to set the project to release mode and another answer-er on the same question said to define the assembly: (xmlns:Local="clr-namespace:MusicPlayer.Controls;assembly=MusicPlayer") which did not work for me either.
This person recommended changing the build target platform (x86 - x64)
I've tried pretty much all of these solution to no avail. ReSharper seems to know that Arc class exists in the namespace assigned to Local, but Visual Studio does not.
<Local:Arc Center="{Binding Path=PreviousMousePositionPixels}"
Stroke="White"
StrokeDashArray="4 4"
SnapsToDevicePixels="True"
StartAngle="0"
EndAngle="{Binding Path=DeltaAngle}"
SmallAngle="True"
Radius="40"/>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
public sealed class Arc : Shape
{
public Point Center
{
get { return (Point)GetValue(CenterProperty); }
set { SetValue(CenterProperty, value); }
}
// Using a DependencyProperty as the backing store for Center. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CenterProperty =
DependencyProperty.Register("Center", typeof(Point), typeof(Arc)
, new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsRender));
public double StartAngle
{
get { return (double)GetValue(StartAngleProperty); }
set { SetValue(StartAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StartAngleProperty =
DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double EndAngle
{
get { return (double)GetValue(EndAngleProperty); }
set { SetValue(EndAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EndAngleProperty =
DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(Math.PI/2.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double Radius
{
get { return (double)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
// Using a DependencyProperty as the backing store for Radius. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender));
public bool SmallAngle
{
get { return (bool)GetValue(SmallAngleProperty); }
set { SetValue(SmallAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for SmallAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SmallAngleProperty =
DependencyProperty.Register("SmallAngle", typeof(bool), typeof(Arc)
, new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
static Arc()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Arc), new FrameworkPropertyMetadata(typeof(Arc)));
}
protected override Geometry DefiningGeometry
{
get
{
var a0 = StartAngle < 0 ? StartAngle + 2 * Math.PI : StartAngle;
var a1 = EndAngle < 0 ? EndAngle + 2 * Math.PI : EndAngle;
if (a1<a0)
{
a1 += Math.PI * 2;
}
SweepDirection d = SweepDirection.Counterclockwise;
bool large;
if (SmallAngle)
{
large = false;
double t = a1;
if ((a1-a0)>Math.PI)
{
d = SweepDirection.Counterclockwise;
}
else
{
d = SweepDirection.Clockwise;
}
}else{
large = (Math.Abs(a1 - a0) < Math.PI);
}
Point p0 = Center + new Vector(Math.Cos(a0), Math.Sin(a0)) * Radius;
Point p1 = Center + new Vector(Math.Cos(a1), Math.Sin(a1)) * Radius;
List<PathSegment> segments = new List<PathSegment>(1);
segments.Add(new ArcSegment(p1, new Size(Radius, Radius), 0.0, large, d, true));
List<PathFigure> figures = new List<PathFigure>(1);
PathFigure pf = new PathFigure(p0, segments, true);
pf.IsClosed = false;
figures.Add(pf);
Geometry g = new PathGeometry(figures, FillRule.EvenOdd, null);
return g;
}
}
}
Define Arc inside a namespace as suggested by RobCroll. Check below code, I have included it in the Arc_Learning namespace which is referred in XAML as local.
<Window x:Class="Arc_Learning.MainWindow"
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:Arc_Learning"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:Arc
Stroke="White"
StrokeDashArray="4 4"
SnapsToDevicePixels="True"
StartAngle="0"
EndAngle="{Binding Path=DeltaAngle}"
SmallAngle="True"
Radius="40"/>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Arc_Learning
{
public sealed class Arc : Shape
{
public Point Center
{
get { return (Point)GetValue(CenterProperty); }
set { SetValue(CenterProperty, value); }
}
// Using a DependencyProperty as the backing store for Center. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CenterProperty =
DependencyProperty.Register("Center", typeof(Point), typeof(Arc)
, new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsRender));
public double StartAngle
{
get { return (double)GetValue(StartAngleProperty); }
set { SetValue(StartAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StartAngleProperty =
DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double EndAngle
{
get { return (double)GetValue(EndAngleProperty); }
set { SetValue(EndAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EndAngleProperty =
DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(Math.PI / 2.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double Radius
{
get { return (double)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
// Using a DependencyProperty as the backing store for Radius. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender));
public bool SmallAngle
{
get { return (bool)GetValue(SmallAngleProperty); }
set { SetValue(SmallAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for SmallAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SmallAngleProperty =
DependencyProperty.Register("SmallAngle", typeof(bool), typeof(Arc)
, new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
static Arc()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Arc), new FrameworkPropertyMetadata(typeof(Arc)));
}
protected override Geometry DefiningGeometry
{
get
{
var a0 = StartAngle < 0 ? StartAngle + 2 * Math.PI : StartAngle;
var a1 = EndAngle < 0 ? EndAngle + 2 * Math.PI : EndAngle;
if (a1 < a0)
{
a1 += Math.PI * 2;
}
SweepDirection d = SweepDirection.Counterclockwise;
bool large;
if (SmallAngle)
{
large = false;
double t = a1;
if ((a1 - a0) > Math.PI)
{
d = SweepDirection.Counterclockwise;
}
else
{
d = SweepDirection.Clockwise;
}
}
else {
large = (Math.Abs(a1 - a0) < Math.PI);
}
Point p0 = Center + new Vector(Math.Cos(a0), Math.Sin(a0)) * Radius;
Point p1 = Center + new Vector(Math.Cos(a1), Math.Sin(a1)) * Radius;
List<PathSegment> segments = new List<PathSegment>(1);
segments.Add(new ArcSegment(p1, new Size(Radius, Radius), 0.0, large, d, true));
List<PathFigure> figures = new List<PathFigure>(1);
PathFigure pf = new PathFigure(p0, segments, true);
pf.IsClosed = false;
figures.Add(pf);
Geometry g = new PathGeometry(figures, FillRule.EvenOdd, null);
return g;
}
}
}
}
try to add local reference to your window as follow:
in the opening tag of your window add this reference
xmlns:local="clr-namespace:CustomControlTest"
in code behind C# Code you missing the namespace definition
add the missing namespace line before the class definition so your code should be like this:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
namespace CustomControlTest
{
public sealed class Arc : Shape
{
public Point Center
{
get { return (Point)GetValue(CenterProperty); }
set { SetValue(CenterProperty, value); }
}
// Using a DependencyProperty as the backing store for Center. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CenterProperty =
DependencyProperty.Register("Center", typeof(Point), typeof(Arc)
, new FrameworkPropertyMetadata(new Point(0, 0), FrameworkPropertyMetadataOptions.AffectsRender));
public double StartAngle
{
get { return (double)GetValue(StartAngleProperty); }
set { SetValue(StartAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for StartAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty StartAngleProperty =
DependencyProperty.Register("StartAngle", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double EndAngle
{
get { return (double)GetValue(EndAngleProperty); }
set { SetValue(EndAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for EndAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty EndAngleProperty =
DependencyProperty.Register("EndAngle", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(Math.PI/2.0, FrameworkPropertyMetadataOptions.AffectsRender));
public double Radius
{
get { return (double)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
// Using a DependencyProperty as the backing store for Radius. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius", typeof(double), typeof(Arc)
, new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender));
public bool SmallAngle
{
get { return (bool)GetValue(SmallAngleProperty); }
set { SetValue(SmallAngleProperty, value); }
}
// Using a DependencyProperty as the backing store for SmallAngle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SmallAngleProperty =
DependencyProperty.Register("SmallAngle", typeof(bool), typeof(Arc)
, new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
static Arc()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Arc), new FrameworkPropertyMetadata(typeof(Arc)));
}
protected override Geometry DefiningGeometry
{
get
{
var a0 = StartAngle < 0 ? StartAngle + 2 * Math.PI : StartAngle;
var a1 = EndAngle < 0 ? EndAngle + 2 * Math.PI : EndAngle;
if (a1<a0)
{
a1 += Math.PI * 2;
}
SweepDirection d = SweepDirection.Counterclockwise;
bool large;
if (SmallAngle)
{
large = false;
double t = a1;
if ((a1-a0)>Math.PI)
{
d = SweepDirection.Counterclockwise;
}
else
{
d = SweepDirection.Clockwise;
}
}else{
large = (Math.Abs(a1 - a0) < Math.PI);
}
Point p0 = Center + new Vector(Math.Cos(a0), Math.Sin(a0)) * Radius;
Point p1 = Center + new Vector(Math.Cos(a1), Math.Sin(a1)) * Radius;
List<PathSegment> segments = new List<PathSegment>(1);
segments.Add(new ArcSegment(p1, new Size(Radius, Radius), 0.0, large, d, true));
List<PathFigure> figures = new List<PathFigure>(1);
PathFigure pf = new PathFigure(p0, segments, true);
pf.IsClosed = false;
figures.Add(pf);
Geometry g = new PathGeometry(figures, FillRule.EvenOdd, null);
return g;
}
}
}
}
add this namespace CustomControlTest and then it contains the class
I have problem with binding in code.
I have Control with X, Y double properties and dependency properties.
public double X
{
get { return (double)GetValue(XProperty); }
set
{
SetValue(XProperty, value);
}
}
public double Y
{
get { return (double)GetValue(YProperty); }
set
{
SetValue(YProperty, value);
}
}
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(VisualPin));
In other control I have Line and I try to use binding to Line end point like this:
var xBinding = new Binding("XProperty") {Source = _startPin};
var yBinding = new Binding("YProperty") {Source = _startPin};
Line.SetBinding(Line.X1Property, xBinding);
Line.SetBinding(Line.Y1Property, yBinding);
All data in all properties are OK, I checked that, but binding doesn't work. I don't have idea why... (All controls are on one Canvas)
Thank you very much!
To debug this kind of situation you should look at the XAML by using a tool like snoop WPF. This will show what the actual bindings are.
It might be your binding is there, but not updating. To fix this your class should implement INotifyPropertyChanged. Whenever you want to update the value, like after setting the value, call the following function with the name of the property:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I am sorry, my fault. Problem was in first parameter in register dependency property.
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(VisualPin));
Instead of:
public static readonly DependencyProperty XProperty = DependencyProperty.Register("XProperty", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("YProperty", typeof(double), typeof(VisualPin));
I'm creating a simple User Control with three properties. For simplicity let's assume these are A, B and C. Moreover C = A + B. I want to display all of them in TextBoxes (A, B - User Editable, C - read only). Whenever a user modifies A or B, the value of C should be updated.
I've already created Dependency Properties for A and B in MyControl.xaml.cs file.
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(0.0));
public double A
{
get { return (double)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(0.0));
public double B
{
get { return (double)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
My question is: what shall I do with C and where its definition should be kept ? Should the logic be coded inside a control or maybe it's a user's responsibility to remember about the relationship between the properties ?
You should declare another DependencyProperty for C in the UserControl and add property change handlers to your A and B properties to update the value of C when their values change. This should do the job:
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new UIPropertyMetadata(0.0, OnAOrBPropertyChanged));
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new UIPropertyMetadata(0.0, OnAOrBPropertyChanged));
public static void OnAOrBPropertyChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
dependencyObject.SetValue(CProperty, (double)dependencyObject.GetValue(AProperty) +
(double)dependencyObject.GetValue(BProperty));
}
You might like to view the Read-Only Dependency Properties page on MSDN for help with declaring a read-only DependencyProperty.
You need to make another dependency property for C also
You can try this:
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(OnAorBChange));
public double A
{
get { return (double)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(OnAorBChange));
public double B
{
get { return (double)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
public static readonly DependencyProperty CProperty =
DependencyProperty.Register("C", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(null));
public double C
{
get { return (double)GetValue(CProperty); }
set { SetValue(CProperty, value); }
}
private static void OnAorBChange(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
var obj1 = obj as MyControl;
obj1.C = obj1.A + obj1.B;
}
I assume you did the proper binding :)