WPF - Is it possible to have a curved input box? - wpf

I want a textbox where you can input text from keyboard but be shown as an arc. Is it possible ?

I have found this solution in codeproject. Author created TextOnAPath control which can display curved text.
Source code:
[ContentProperty("Text")]
public class TextOnAPath : Control
{
static TextOnAPath()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TextOnAPath), new FrameworkPropertyMetadata(typeof(TextOnAPath)));
Control.FontSizeProperty.OverrideMetadata(typeof(TextOnAPath),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnFontPropertyChanged)));
Control.FontFamilyProperty.OverrideMetadata(typeof(TextOnAPath),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnFontPropertyChanged)));
Control.FontStretchProperty.OverrideMetadata(typeof(TextOnAPath),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnFontPropertyChanged)));
Control.FontStyleProperty.OverrideMetadata(typeof(TextOnAPath),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnFontPropertyChanged)));
Control.FontWeightProperty.OverrideMetadata(typeof(TextOnAPath),
new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnFontPropertyChanged)));
}
static void OnFontPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextOnAPath textOnAPath = d as TextOnAPath;
if (textOnAPath == null)
return;
if (e.NewValue == null || e.NewValue == e.OldValue)
return;
textOnAPath.UpdateText();
textOnAPath.Update();
}
double[] _segmentLengths;
TextBlock[] _textBlocks;
Panel _layoutPanel;
bool _layoutHasValidSize = false;
#region Text DP
public String Text
{
get { return (String)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(String), typeof(TextOnAPath),
new PropertyMetadata(null, new PropertyChangedCallback(OnStringPropertyChanged),
new CoerceValueCallback(CoerceTextValue)));
static void OnStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextOnAPath textOnAPath = d as TextOnAPath;
if (textOnAPath == null)
return;
if (e.NewValue == e.OldValue || e.NewValue == null)
{
if (textOnAPath._layoutPanel != null)
textOnAPath._layoutPanel.Children.Clear();
return;
}
textOnAPath.UpdateText();
textOnAPath.Update();
}
static object CoerceTextValue(DependencyObject d, object baseValue)
{
if ((String)baseValue == "")
return null;
return baseValue;
}
#endregion
#region TextPath DP
public Geometry TextPath
{
get { return (Geometry)GetValue(TextPathProperty); }
set { SetValue(TextPathProperty, value); }
}
public static readonly DependencyProperty TextPathProperty =
DependencyProperty.Register("TextPath", typeof(Geometry), typeof(TextOnAPath),
new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(OnTextPathPropertyChanged)));
static void OnTextPathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextOnAPath textOnAPath = d as TextOnAPath;
if (textOnAPath == null)
return;
if (e.NewValue == e.OldValue || e.NewValue == null)
return;
textOnAPath.TextPath.Transform = null;
textOnAPath.UpdateSize();
textOnAPath.Update();
}
#endregion
#region DrawPath DP
/// <summary>
/// Set this property to True to display the TextPath geometry in the control
/// </summary>
public bool DrawPath
{
get { return (bool)GetValue(DrawPathProperty); }
set { SetValue(DrawPathProperty, value); }
}
public static readonly DependencyProperty DrawPathProperty =
DependencyProperty.Register("DrawPath", typeof(bool), typeof(TextOnAPath),
new PropertyMetadata(false, new PropertyChangedCallback(OnDrawPathPropertyChanged)));
static void OnDrawPathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextOnAPath textOnAPath = d as TextOnAPath;
if (textOnAPath == null)
return;
if (e.NewValue == e.OldValue || e.NewValue == null)
return;
textOnAPath.Update();
}
#endregion
#region DrawLinePath DP
/// <summary>
/// Set this property to True to display the line segments under the text (flattened path)
/// </summary>
public bool DrawLinePath
{
get { return (bool)GetValue(DrawLinePathProperty); }
set { SetValue(DrawLinePathProperty, value); }
}
// Using a DependencyProperty as the backing store for DrawFlattendPath. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DrawLinePathProperty =
DependencyProperty.Register("DrawLinePath", typeof(bool), typeof(TextOnAPath),
new PropertyMetadata(false, new PropertyChangedCallback(OnDrawLinePathPropertyChanged)));
static void OnDrawLinePathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextOnAPath textOnAPath = d as TextOnAPath;
if (textOnAPath == null)
return;
if (e.NewValue == e.OldValue || e.NewValue == null)
return;
textOnAPath.Update();
}
#endregion
#region ScaleTextPath DP
/// <summary>
/// If set to True (default) then the geometry defined by TextPath automatically gets scaled to fit the width/height of the control
/// </summary>
public bool ScaleTextPath
{
get { return (bool)GetValue(ScaleTextPathProperty); }
set { SetValue(ScaleTextPathProperty, value); }
}
public static readonly DependencyProperty ScaleTextPathProperty =
DependencyProperty.Register("ScaleTextPath", typeof(bool), typeof(TextOnAPath),
new PropertyMetadata(false, new PropertyChangedCallback(OnScaleTextPathPropertyChanged)));
static void OnScaleTextPathPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextOnAPath textOnAPath = d as TextOnAPath;
if (textOnAPath == null)
return;
if (e.NewValue == e.OldValue)
return;
bool value = (Boolean)e.NewValue;
if (value == false && textOnAPath.TextPath != null)
textOnAPath.TextPath.Transform = null;
textOnAPath.UpdateSize();
textOnAPath.Update();
}
#endregion
void UpdateText()
{
if (Text == null || FontFamily == null || FontWeight == null || FontStyle == null)
return;
_textBlocks = new TextBlock[Text.Length];
_segmentLengths = new double[Text.Length];
for (int i = 0; i < Text.Length; i++)
{
TextBlock t = new TextBlock();
t.FontSize = this.FontSize;
t.FontFamily = this.FontFamily;
t.FontStretch = this.FontStretch;
t.FontWeight = this.FontWeight;
t.FontStyle = this.FontStyle;
t.Text = new String(Text[i], 1);
t.RenderTransformOrigin = new Point(0.0, 1.0);
t.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
_textBlocks[i] = t;
_segmentLengths[i] = t.DesiredSize.Width;
}
}
void Update()
{
if (Text == null || TextPath == null || _layoutPanel == null || !_layoutHasValidSize)
return;
List<Point> intersectionPoints;
intersectionPoints = GeometryHelper.GetIntersectionPoints(TextPath.GetFlattenedPathGeometry(), _segmentLengths);
_layoutPanel.Children.Clear();
_layoutPanel.Margin = new Thickness(FontSize);
for (int i = 0; i < intersectionPoints.Count - 1; i++)
{
double oppositeLen = Math.Sqrt(Math.Pow(intersectionPoints[i].X + _segmentLengths[i] - intersectionPoints[i + 1].X, 2.0) + Math.Pow(intersectionPoints[i].Y - intersectionPoints[i + 1].Y, 2.0)) / 2.0;
double hypLen = Math.Sqrt(Math.Pow(intersectionPoints[i].X - intersectionPoints[i + 1].X, 2.0) + Math.Pow(intersectionPoints[i].Y - intersectionPoints[i + 1].Y, 2.0));
double ratio = oppositeLen / hypLen;
if (ratio > 1.0)
ratio = 1.0;
else if (ratio < -1.0)
ratio = -1.0;
//double angle = 0.0;
double angle = 2.0 * Math.Asin(ratio) * 180.0 / Math.PI;
// adjust sign on angle
if ((intersectionPoints[i].X + _segmentLengths[i]) > intersectionPoints[i].X)
{
if (intersectionPoints[i + 1].Y < intersectionPoints[i].Y)
angle = -angle;
}
else
{
if (intersectionPoints[i + 1].Y > intersectionPoints[i].Y)
angle = -angle;
}
TextBlock currTextBlock = _textBlocks[i];
RotateTransform rotate = new RotateTransform(angle);
TranslateTransform translate = new TranslateTransform(intersectionPoints[i].X, intersectionPoints[i].Y - currTextBlock.DesiredSize.Height);
TransformGroup transformGrp = new TransformGroup();
transformGrp.Children.Add(rotate);
transformGrp.Children.Add(translate);
currTextBlock.RenderTransform = transformGrp;
_layoutPanel.Children.Add(currTextBlock);
if (DrawLinePath == true)
{
Line line = new Line();
line.X1 = intersectionPoints[i].X;
line.Y1 = intersectionPoints[i].Y;
line.X2 = intersectionPoints[i + 1].X;
line.Y2 = intersectionPoints[i + 1].Y;
line.Stroke = Brushes.Black;
_layoutPanel.Children.Add(line);
}
}
// don't draw path if already drawing line path
if (DrawPath == true && DrawLinePath == false)
{
Path path = new Path();
path.Data = TextPath;
path.Stroke = Brushes.Black;
_layoutPanel.Children.Add(path);
}
}
public TextOnAPath()
{
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_layoutPanel = GetTemplateChild("LayoutPanel") as Panel;
if (_layoutPanel == null)
throw new Exception("Could not find template part: LayoutPanel");
_layoutPanel.SizeChanged += new SizeChangedEventHandler(_layoutPanel_SizeChanged);
}
Size _newSize;
void _layoutPanel_SizeChanged(object sender, SizeChangedEventArgs e)
{
_newSize = e.NewSize;
UpdateSize();
Update();
}
void UpdateSize()
{
if (_newSize == null || TextPath == null)
return;
_layoutHasValidSize = true;
double xScale = _newSize.Width / TextPath.Bounds.Width;
double yScale = _newSize.Height / TextPath.Bounds.Height;
if (TextPath.Bounds.Width <= 0)
xScale = 1.0;
if (TextPath.Bounds.Height <= 0)
xScale = 1.0;
if (xScale <= 0 || yScale <= 0)
return;
if (TextPath.Transform is TransformGroup)
{
TransformGroup grp = TextPath.Transform as TransformGroup;
if (grp.Children[0] is ScaleTransform && grp.Children[1] is TranslateTransform)
{
if (ScaleTextPath)
{
ScaleTransform scale = grp.Children[0] as ScaleTransform;
scale.ScaleX *= xScale;
scale.ScaleY *= yScale;
}
TranslateTransform translate = grp.Children[1] as TranslateTransform;
translate.X += -TextPath.Bounds.X;
translate.Y += -TextPath.Bounds.Y;
}
}
else
{
ScaleTransform scale;
TranslateTransform translate;
if (ScaleTextPath)
{
scale = new ScaleTransform(xScale, yScale);
translate = new TranslateTransform(-TextPath.Bounds.X * xScale, -TextPath.Bounds.Y * yScale);
}
else
{
scale = new ScaleTransform(1.0, 1.0);
translate = new TranslateTransform(-TextPath.Bounds.X, -TextPath.Bounds.Y );
}
TransformGroup grp = new TransformGroup();
grp.Children.Add(scale);
grp.Children.Add(translate);
TextPath.Transform = grp;
}
}
}
public static class GeometryHelper
{
public static List<Point> GetIntersectionPoints(PathGeometry FlattenedPath, double[] SegmentLengths)
{
List<Point> intersectionPoints = new List<Point>();
List<Point> pointsOnFlattenedPath = GetPointsOnFlattenedPath(FlattenedPath);
if (pointsOnFlattenedPath == null || pointsOnFlattenedPath.Count < 2)
return intersectionPoints;
Point currPoint = pointsOnFlattenedPath[0];
intersectionPoints.Add(currPoint);
// find point on flattened path that is segment length away from current point
int flattedPathIndex = 0;
int segmentIndex = 1;
while (flattedPathIndex < pointsOnFlattenedPath.Count - 1 &&
segmentIndex < SegmentLengths.Length + 1)
{
Point? intersectionPoint = GetIntersectionOfSegmentAndCircle(
pointsOnFlattenedPath[flattedPathIndex],
pointsOnFlattenedPath[flattedPathIndex + 1], currPoint, SegmentLengths[segmentIndex - 1]);
if (intersectionPoint == null)
flattedPathIndex++;
else
{
intersectionPoints.Add((Point)intersectionPoint);
currPoint = (Point)intersectionPoint;
pointsOnFlattenedPath[flattedPathIndex] = currPoint;
segmentIndex++;
}
}
return intersectionPoints;
}
static List<Point> GetPointsOnFlattenedPath(PathGeometry FlattenedPath)
{
List<Point> flattenedPathPoints = new List<Point>();
// for flattened geometry there should be just one PathFigure in the Figures
if (FlattenedPath.Figures.Count != 1)
return null;
PathFigure pathFigure = FlattenedPath.Figures[0];
flattenedPathPoints.Add(pathFigure.StartPoint);
// SegmentsCollection should contain PolyLineSegment and LineSegment
foreach (PathSegment pathSegment in pathFigure.Segments)
{
if (pathSegment is PolyLineSegment)
{
PolyLineSegment seg = pathSegment as PolyLineSegment;
foreach (Point point in seg.Points)
flattenedPathPoints.Add(point);
}
else if (pathSegment is LineSegment)
{
LineSegment seg = pathSegment as LineSegment;
flattenedPathPoints.Add(seg.Point);
}
else
throw new Exception("GetIntersectionPoint - unexpected path segment type: " + pathSegment.ToString());
}
return (flattenedPathPoints);
}
static Point? GetIntersectionOfSegmentAndCircle(Point SegmentPoint1, Point SegmentPoint2,
Point CircleCenter, double CircleRadius)
{
// linear equation for segment: y = mx + b
double slope = (SegmentPoint2.Y - SegmentPoint1.Y) / (SegmentPoint2.X - SegmentPoint1.X);
double intercept = SegmentPoint1.Y - (slope * SegmentPoint1.X);
// special case when segment is vertically oriented
if (double.IsInfinity(slope))
{
double root = Math.Pow(CircleRadius, 2.0) - Math.Pow(SegmentPoint1.X - CircleCenter.X, 2.0);
if (root < 0)
return null;
// soln 1
double SolnX1 = SegmentPoint1.X;
double SolnY1 = CircleCenter.Y - Math.Sqrt(root);
Point Soln1 = new Point(SolnX1, SolnY1);
// have valid result if point is between two segment points
if (IsBetween(SolnX1, SegmentPoint1.X, SegmentPoint2.X) &&
IsBetween(SolnY1, SegmentPoint1.Y, SegmentPoint2.Y))
//if (ValidSoln(Soln1, SegmentPoint1, SegmentPoint2, CircleCenter))
{
// found solution
return (Soln1);
}
// soln 2
double SolnX2 = SegmentPoint1.X;
double SolnY2 = CircleCenter.Y + Math.Sqrt(root);
Point Soln2 = new Point(SolnX2, SolnY2);
// have valid result if point is between two segment points
if (IsBetween(SolnX2, SegmentPoint1.X, SegmentPoint2.X) &&
IsBetween(SolnY2, SegmentPoint1.Y, SegmentPoint2.Y))
//if (ValidSoln(Soln2, SegmentPoint1, SegmentPoint2, CircleCenter))
{
// found solution
return (Soln2);
}
}
else
{
// use soln to quadradratic equation to solve intersection of segment and circle:
// x = (-b +/ sqrt(b^2-4ac))/(2a)
double a = 1 + Math.Pow(slope, 2.0);
double b = (-2 * CircleCenter.X) + (2 * (intercept - CircleCenter.Y) * slope);
double c = Math.Pow(CircleCenter.X, 2.0) + Math.Pow(intercept - CircleCenter.Y, 2.0) - Math.Pow(CircleRadius, 2.0);
// check for no solutions, is sqrt negative?
double root = Math.Pow(b, 2.0) - (4 * a * c);
if (root < 0)
return null;
// we might have two solns...
// soln 1
double SolnX1 = (-b + Math.Sqrt(root)) / (2 * a);
double SolnY1 = slope * SolnX1 + intercept;
Point Soln1 = new Point(SolnX1, SolnY1);
// have valid result if point is between two segment points
if (IsBetween(SolnX1, SegmentPoint1.X, SegmentPoint2.X) &&
IsBetween(SolnY1, SegmentPoint1.Y, SegmentPoint2.Y))
//if (ValidSoln(Soln1, SegmentPoint1, SegmentPoint2, CircleCenter))
{
// found solution
return (Soln1);
}
// soln 2
double SolnX2 = (-b - Math.Sqrt(root)) / (2 * a);
double SolnY2 = slope * SolnX2 + intercept;
Point Soln2 = new Point(SolnX2, SolnY2);
// have valid result if point is between two segment points
if (IsBetween(SolnX2, SegmentPoint1.X, SegmentPoint2.X) &&
IsBetween(SolnY2, SegmentPoint1.Y, SegmentPoint2.Y))
//if (ValidSoln(Soln2, SegmentPoint1, SegmentPoint2, CircleCenter))
{
// found solution
return (Soln2);
}
}
// shouldn't get here...but in case
return null;
}
static bool IsBetween(double X, double X1, double X2)
{
if (X1 >= X2 && X <= X1 && X >= X2)
return true;
if (X1 <= X2 && X >= X1 && X <= X2)
return true;
return false;
}
}
Usage:
<TextOnAPath:TextOnAPath FontSize="30" DrawPath="True"
Text="The quick brown fox jumped over the lazy hen.">
<TextOnAPath:TextOnAPath.TextPath>
<PathGeometry Figures="M0,0 C120,361 230.5,276.5 230.5,276.5
L308.5,237.50001 C308.5,237.50001 419.5,179.5002 367.5,265.49993
315.5,351.49966 238.50028,399.49924 238.50028,399.49924 L61.500017,
420.49911"/>
</TextOnAPath:TextOnAPath.TextPath>
</TextOnAPath:TextOnAPath>
</Grid>

Related

Printing control and setting its position on A4 page

I am trying to print selected control to PDF/printer yet I have problem with positioning it on printed page.
When I changed location in Rect it doesn't affect the outcome. I want the control to be in the center of the page or at least the left top corner of the control should be in left top corner of the page, but all the time I have the same picture which starts at the middle of page.
This is my code:
private async Task PrintObjectVisual(bool canUserSelectPrinter, FrameworkElement frameworkElement)
{
if (_CreatePrinterDialog(canUserSelectPrinter, out var prnt)) return;
var offset = VisualTreeHelper.GetOffset(frameworkElement);
Transform originalScale = frameworkElement.LayoutTransform.Clone();
try
{
bool allowForceLandscape = true;
bool forceLandscape =
allowForceLandscape &&
(_starMainPage.ActPage.PresPage.PrintLandscape || frameworkElement.ActualWidth > prnt.PrintableAreaWidth)
||
(frameworkElement is IGraphViewControl || frameworkElement is IMapViewControl);
double scale = 0.0;
PageMediaSize pageSize = null;
pageSize = new PageMediaSize(PageMediaSizeName.ISOA4, CmToPx(29.7), CmToPx(21));
prnt.PrintTicket.PageMediaSize = pageSize;
if (forceLandscape)
{
prnt.PrintTicket.PageOrientation = PageOrientation.Landscape;
if (pageSize.Width != null && pageSize.Height != null)
scale = Math.Min(
(pageSize.Height.Value / frameworkElement.ActualWidth), (pageSize.Width.Value / frameworkElement.ActualHeight));
}
else
{
prnt.PrintTicket.PageOrientation = PageOrientation.Portrait;
if (pageSize.Width != null && pageSize.Height != null)
scale = Math.Min(
(pageSize.Width.Value / frameworkElement.ActualWidth), (pageSize.Height.Value / frameworkElement.ActualHeight));
}
//if (scale > 1.0)
// scale = 1.0;
frameworkElement.LayoutTransform = new ScaleTransform(scale, scale);
// after a thought i know that i might not need it
//var size = _GetPrintAreaSize(forceLandscape, pageSize);
//frameworkElement.Measure(size);
//frameworkElement.Arrange(
// new Rect(new Point(0, 0), size));
prnt.PrintVisual(frameworkElement, $"Printing Object {frameworkElement.Name}");
}
catch (Exception e)
{
PresHelper.WriteToDebug(_presBaseObject, e);
}
finally
{
frameworkElement.LayoutTransform = originalScale;
// after a thought i know that i might not need it
//Size size2 = new Size(_starMainPage.Canvas.ActualWidth, _starMainPage.Canvas.ActualHeight);
//frameworkElement.Measure(size2);
//var x = offset.X - (offset.X * 2);// offset.X
//var y = offset.Y - (offset.Y * 2);// offset.X
//frameworkElement.Arrange(new Rect(new Point(x, y), size2));
}
}
private static bool _CreatePrinterDialog(bool canUserSelectPrinter, out PrintDialog prnt)
{
prnt = new PrintDialog();
if (canUserSelectPrinter)
{
var result = prnt.ShowDialog();
if (result == false)
return true;
}
return false;
}
private Size _GetPrintAreaSize(bool forceLandscape, PageMediaSize pageSize)
{
if (pageSize.Height == null || pageSize.Width == null) throw new NullReferenceException($"Page size values are null! Can't print without it.");
Size size;
if (forceLandscape)
size = new Size(pageSize.Height.Value, pageSize.Width.Value);
else
size = new Size(pageSize.Width.Value, pageSize.Height.Value);
return size;
}
Ok, so after some time on it I have solved the problem.
I assign original Canvas.LeftProperty and TopProperty to some private class members and then assign my own (double) values.
This code is just before the printing.
Later i'm assigning old values:
frameworkElement.LayoutTransform = new ScaleTransform(scale, scale);
left = (double)frameworkElement.GetValue(Canvas.LeftProperty);
top = (double)frameworkElement.GetValue(Canvas.TopProperty);
frameworkElement.SetValue(Canvas.LeftProperty, _marginSize);
frameworkElement.SetValue(Canvas.TopProperty, _marginSize);
prnt.PrintVisual(frameworkElement, $"Printing MikObject {frameworkElement.Name}");
}
catch (Exception e)
{
PresHelper.WriteToDebug(_presBaseObject, e);
}
finally
{
frameworkElement.SetValue(Canvas.LeftProperty, left);
frameworkElement.SetValue(Canvas.TopProperty, top);
frameworkElement.LayoutTransform = originalScale;
}

ScaleTransform change Not work after Use Storyboard

I change ScaleTransform with Storyboard and work fine, but after change ScaleTransform not work,
sample:
scaleTransform.ScaleX=1
after use Storyboard:
scaleTransform.ScaleX=2
when change in my code
scaleTransform.ScaleX += 1;
but scaleTransform.ScaleX=2,
private Storyboard _story = new Storyboard();
private void CreateAnimation(double x, double y, TimeSpan delay)
{
var stScaleX = new DoubleAnimation(scaleTransform.ScaleX, x, delay);
var stScaleY = new DoubleAnimation(scaleTransform.ScaleY, y, delay);
stScaleX.SetValue(Storyboard.TargetProperty, mainCanvas);
stScaleX.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("LayoutTransform.Children[0].ScaleX"));
stScaleY.SetValue(Storyboard.TargetNameProperty, mainCanvas.Name);
stScaleY.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath("LayoutTransform.Children[0].ScaleY"));
_story.Children.Add(stScaleY);
_story.Children.Add(stScaleX);
mainCanvas.Resources.Clear();
_story.Changed += St_Changed;
_story.Completed += St_Completed;
_story.Begin(mainCanvas);
}
private void St_Completed(object sender, EventArgs e)
{
_story.Changed -= St_Changed;
_story.Completed -= St_Completed;
var newXy = new Point(_scalePoint.X, _scalePoint.Y);
scrollViewer.ScrollToHorizontalOffset(newXy.X);
scrollViewer.ScrollToVerticalOffset(newXy.Y);
var zs = GetScaleTransform(mainCanvas);
ZoomLevel = zs.ScaleX;
_story.Stop();
_story.Remove();
mainCanvas.Resources.Clear();
}
private void St_Changed(object sender, EventArgs e)
{
var newXy = new Point(_scalePoint.X, _scalePoint.Y);
scrollViewer.ScrollToHorizontalOffset(newXy.X);
scrollViewer.ScrollToVerticalOffset(newXy.Y);
}
private void mainCanvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
var st = GetScaleTransform(mainCanvas);
var zoom = e.Delta > 0 ? .6 : -.6;
if (!(e.Delta > 0) && (st.ScaleX < .4 || st.ScaleY < .4))
return;
if (st.ScaleX <= 1 && zoom < 0) return;
var relativeOnImage = e.GetPosition(mainCanvas);
var relativeOnScreen = e.GetPosition(Grid1);
scaleTransform.ScaleX = st.ScaleX+zoom;
scaleTransform.ScaleY = st.ScaleY+ zoom;
if (st.ScaleX < 1) st.ScaleX = 1;
if (st.ScaleY < 1) st.ScaleY = 1;
var newSizeX = Grid1.ActualWidth*st.ScaleX;
newSizeX = ((newSizeX*relativeOnImage.X)/ Grid1.ActualWidth)- relativeOnScreen.X;
var newSizeY = Grid1.ActualHeight * st.ScaleY;
newSizeY = ((newSizeY*relativeOnImage.Y)/ Grid1.ActualHeight)- relativeOnScreen.Y;
scrollViewer.ScrollToHorizontalOffset(newSizeX);
scrollViewer.ScrollToVerticalOffset(newSizeY);
IsZooming = st.ScaleX > 1 || st.ScaleY > 1;
}
I sloved,
I change my code, and worked
var oldDataX = scaleTransform.ScaleX;
var oldDataY = scaleTransform.ScaleY;
scaleTransform.BeginAnimation(ScaleTransform.ScaleXProperty, null);
scaleTransform.BeginAnimation(ScaleTransform.ScaleYProperty, null);
scaleTransform.ScaleX = oldDataX + zoom;
scaleTransform.ScaleY = oldDataY + zoom;
for more information :
https://msdn.microsoft.com/en-us/library/aa970493(v=vs.90).aspx
http://www.codeproject.com/Tips/146505/WPF-Storyboard-animation-locks-properties-it-s-ani

DataGridComboboxColumn - Get cell value

The task is the following: there is a DataGrid with ComboboxColumns. If user changes cell[2,3] and selected value!=0 then disable cell[3,2]. I wrote the following Handler:
private void grAssessment_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int x = e.Column.DisplayIndex;
int y = e.Row.GetIndex();
grAssessment.GetCell(x, y).IsEnabled = false;
grAssessment.GetCell(x, y).Background = Brushes.LightGray;
}
But it disables appropriate cell in anyway. How to add selected value!=0 condition to this code?
Thanks in advance.
Try to check this out:
1. DataGridComboBoxColumn ItemsSource (for current version only, use your own):
private ObservableCollection<ScoreData> _scores = new ObservableCollection<ScoreData>(
new List<ScoreData>
{
new ScoreData{Score = 1, ScoreVerbal = "the same"},
new ScoreData{Score = 3, ScoreVerbal = "moderate superiority"},
new ScoreData{Score = 5, ScoreVerbal = "strong superiority"},
new ScoreData{Score = 7, ScoreVerbal = "the samvery strong superioritye"},
new ScoreData{Score = 9, ScoreVerbal = "extremely superiority"},
} );
2. Handler code (the handler defined on the data grid):
private void SelectDataGrid_OnCellEditEnding(object sender,
DataGridCellEditEndingEventArgs e)
{
var editingElement = e.EditingElement as Selector;
if(editingElement == null) return;
var selectedData = editingElement.SelectedItem as ScoreData;
if(selectedData == null || selectedData.Score > 1) return;
var dataGridCell = editingElement.GetVisualParentOfType<DataGridCell>();
if(dataGridCell == null) return;
dataGridCell.IsEnabled = false;
}
3. GetVisualParentOfType code (as part of extension class):
public static class VisualTreeExtensions
{
public static T GetVisualParentOfType<T>(this DependencyObject child)
where T : DependencyObject
{
if (child is T)
return child as T;
var parentObject = VisualTreeHelper.GetParent(child);
if (parentObject == null) return null;
var parent = parentObject as T;
return parent ?? GetVisualParentOfType<T>(parentObject);
}
public static T GetChildOfType<T>(this DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
}
regards,
I found the following solution
private void grAssessment_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
int x = e.Column.DisplayIndex;
int y = e.Row.GetIndex();
DataGridCell cell = grAssessment.GetCell(y, x);
if (((System.Windows.Controls.ComboBox)(cell.Content)).Text != "")
{
grAssessment.GetCell(x, y).IsEnabled = false;
grAssessment.GetCell(x, y).Background = Brushes.LightGray;
}
else
{
grAssessment.GetCell(x, y).IsEnabled = true;
grAssessment.GetCell(x, y).Background = Brushes.White;
}
}

WPF 3D POINT DRAWING

I need to draw a point in 3D using WPF. I am using class ScreenSpaceLines3D to draw a line in 3D, but I'm not able to draw point in 3D (while model zooming). Can anybody help me? Some example code would be appreciated. Thanks
Use PointsVisual3D class from helixtoolkit, with it you can add points on viewport with color, size. Even you can apply transforms, too.
A point can't be seen, because it has no surface area. WPF 3d is not a ray tracing engine, unfortunately.
However, someone built a pretty nice ray-tracing starter library. This project is a good starting point if you want to do ray-tracing with WPF: http://raytracer.codeplex.com/.
It is not so complicated task.
Download the Helix3D Library
Find the sphere mesh code in samples
Attach the scphere's radius to zooming realization.
i can create a PointVisual3d Own Class. The code of PointVisual3D is below i think this one is helpful for you...
public class PointVisual3D:ModelVisual3D
{
private readonly GeometryModel3D _model;
private readonly MeshGeometry3D _mesh;
private Matrix3D _visualToScreen;
private Matrix3D _screenToVisual;
public PointVisual3D()
{
_mesh = new MeshGeometry3D();
_model = new GeometryModel3D();
_model.Geometry = _mesh;
SetColor(this.Color);
this.Content = _model;
this.Points = new Point3DCollection();
CompositionTarget.Rendering += OnRender;
}
private void OnRender(object sender, EventArgs e)
{
if (Points.Count == 0 && _mesh.Positions.Count == 0)
{
return;
}
if (UpdateTransforms() && MainWindow.mousedown==false)
{
RebuildGeometry();
}
}
public static readonly DependencyProperty ColorProperty = DependencyProperty.Register("Color", typeof(Color), typeof(PointVisual3D), new PropertyMetadata(Colors.White, OnColorChanged));
private static void OnColorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
((PointVisual3D)sender).SetColor((Color)args.NewValue);
}
private void SetColor(Color color)
{
MaterialGroup unlitMaterial = new MaterialGroup();
unlitMaterial.Children.Add(new DiffuseMaterial(new SolidColorBrush(Colors.Black)));
unlitMaterial.Children.Add(new EmissiveMaterial(new SolidColorBrush(color)));
unlitMaterial.Freeze();
_model.Material = unlitMaterial;
_model.BackMaterial = unlitMaterial;
}
public Color Color
{
get { return (Color)GetValue(ColorProperty); }
set { SetValue(ColorProperty, value); }
}
//public static readonly DependencyProperty ThicknessProperty = DependencyProperty.Register("Thickness", typeof(double), typeof(PointVisual3D), new PropertyMetadata(1.0, OnThicknessChanged));
//private static void OnThicknessChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
//{
// ((PointVisual3D)sender).GeometryDirty();
//}
//public double Thickness
//{
// get { return (double)GetValue(ThicknessProperty); }
// set { SetValue(ThicknessProperty, value); }
//}
public static readonly DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(Point3DCollection), typeof(PointVisual3D), new PropertyMetadata(null, OnPointsChanged));
private static void OnPointsChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
((PointVisual3D)sender).GeometryDirty();
}
public Point3DCollection Points
{
get { return (Point3DCollection)GetValue(PointsProperty); }
set { SetValue(PointsProperty, value); }
}
private void GeometryDirty()
{
_visualToScreen = MathUtils.ZeroMatrix;
}
private void RebuildGeometry()
{
//double halfThickness = Thickness / 2.0;
//int numLines = Points.Count / 2;
//Point3DCollection positions = new Point3DCollection(numLines * 4);
//for (int i = 0; i < numLines; i++)
//{
// int startIndex = i * 2;
// Point3D startPoint = Points[startIndex];
// Point3D endPoint = Points[startIndex + 1];
// AddSegment(positions, startPoint, endPoint, halfThickness);
//}
//positions.Freeze();
//_mesh.Positions = positions;
Int32Collection indices = new Int32Collection(Points.Count * 6);
for (int i = 0; i < Points.Count; i++)
{
indices.Add(i * 4 + 2);
indices.Add(i * 4 + 1);
indices.Add(i * 4 + 0);
indices.Add(i * 4 + 2);
indices.Add(i * 4 + 3);
indices.Add(i * 4 + 1);
}
indices.Freeze();
_mesh.TriangleIndices = indices;
_mesh.Positions = CreatePositions(this.Points, this.Size, 0.0);
}
public Point3DCollection CreatePositions(IList<Point3D> points, double size = 1.0, double depthOffset = 0.0)
{
double halfSize = size / 2.0;
int numPoints = points.Count;
var outline = new[]
{
new Vector(-halfSize, halfSize), new Vector(-halfSize, -halfSize), new Vector(halfSize, halfSize),
new Vector(halfSize, -halfSize)
};
var positions = new Point3DCollection(numPoints * 4);
for (int i = 0; i < numPoints; i++)
{
var screenPoint = (Point4D)points[i] * this._visualToScreen;
double spx = screenPoint.X;
double spy = screenPoint.Y;
double spz = screenPoint.Z;
double spw = screenPoint.W;
if (!depthOffset.Equals(0))
{
spz -= depthOffset * spw;
}
var p0 = new Point4D(spx, spy, spz, spw) * this._screenToVisual;
double pwinverse = 1 / p0.W;
foreach (var v in outline)
{
var p = new Point4D(spx + v.X * spw, spy + v.Y * spw, spz, spw) * this._screenToVisual;
positions.Add(new Point3D(p.X * pwinverse, p.Y * pwinverse, p.Z * pwinverse));
}
}
positions.Freeze();
return positions;
}
/// <summary>
/// Identifies the <see cref="Size"/> dependency property.
/// </summary>
public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
"Size", typeof(double), typeof(PointVisual3D), new UIPropertyMetadata(1.0, GeometryChanged));
protected static void GeometryChanged(object sender, DependencyPropertyChangedEventArgs e)
{
((PointVisual3D)sender).GeometryDirty();
}
public double Size
{
get
{
return (double)this.GetValue(SizeProperty);
}
set
{
this.SetValue(SizeProperty, value);
}
}
//private void AddSegment(Point3DCollection positions, Point3D startPoint, Point3D endPoint, double halfThickness)
//{
// Vector3D lineDirection = endPoint * _visualToScreen - startPoint * _visualToScreen;
// lineDirection.Z = 0;
// lineDirection.Normalize();
// Vector delta = new Vector(-lineDirection.Y, lineDirection.X);
// delta *= halfThickness;
// Point3D pOut1, pOut2;
// Widen(startPoint, delta, out pOut1, out pOut2);
// positions.Add(pOut1);
// positions.Add(pOut2);
// Widen(endPoint, delta, out pOut1, out pOut2);
// positions.Add(pOut1);
// positions.Add(pOut2);
//}
//private void Widen(Point3D pIn, Vector delta, out Point3D pOut1, out Point3D pOut2)
//{
// Point4D pIn4 = (Point4D)pIn;
// Point4D pOut41 = pIn4 * _visualToScreen;
// Point4D pOut42 = pOut41;
// pOut41.X += delta.X * pOut41.W;
// pOut41.Y += delta.Y * pOut41.W;
// pOut42.X -= delta.X * pOut42.W;
// pOut42.Y -= delta.Y * pOut42.W;
// pOut41 *= _screenToVisual;
// pOut42 *= _screenToVisual;
// pOut1 = new Point3D(pOut41.X / pOut41.W, pOut41.Y / pOut41.W, pOut41.Z / pOut41.W);
// pOut2 = new Point3D(pOut42.X / pOut42.W, pOut42.Y / pOut42.W, pOut42.Z / pOut42.W);
//}
private bool UpdateTransforms()
{
Viewport3DVisual viewport;
bool success;
Matrix3D visualToScreen = MathUtils.TryTransformTo2DAncestor(this, out viewport, out success);
if (!success || !visualToScreen.HasInverse)
{
_mesh.Positions = null;
return false;
}
if (visualToScreen == _visualToScreen)
{
return false;
}
_visualToScreen = _screenToVisual = visualToScreen;
_screenToVisual.Invert();
return true;
}
}

ListBox List Rotation

I want to create a ListBox that basically displays a circular list. For example a list with three items:
1
2
3 <- (Selector on item 3)
will rotate the list and have the selector over item 1 after passing item 3:
2
3
1 <- (Selector on item 1)
This is similar to the menu paradigm of the Windows Media Center.
What part of the ListBox should I be tweaking???
Well, I updated the Items... not sure it's the right way, but, anyhow, if you want to take a look at my implementation... here it is:
using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using System.Collections.ObjectModel;
using ScrollLimit;
using System.Windows.Controls.Primitives;
using System.Text.RegularExpressions;
namespace ScrollLimit
{
public enum ScrollLimitBehaviour { Springs, Circular };
}
namespace SmoothScroll
{
[TemplatePart(Name = "PART_Border", Type = typeof(Border))]
[TemplatePart(Name = "PART_ScrollViewer", Type = typeof(ScrollViewer))]
[TemplatePart(Name = "PART_StackPanel", Type = typeof(StackPanel))]
public class SmoothScrollViewer : ListBox
{
private double move_init, scroll_init, scroll_offset, scroll_t0, scroll_span, scroll_v0, scroll_offset0, backOffset, adjustLimit, stopWindowCoord, hitOffset;
private bool scroll_mouseDown = false, scroll_direction = false, scroll_out = false, scrollLessThanZero = false, scrollMoreThanEnd = false, selectionAllowed = false, canUpdate = true, external = true;
private DispatcherTimer scroll_timerClock = new DispatcherTimer();
private EventHandler decelerateEventHandler, adjustEventHandler;
private int selectedIndex;
private ScrollViewer sv;
private Rectangle stopWindow;
private StackPanel sp;
private ListBoxItem lbi;
private Grid g;
private TextBox filterEdit;
//proprietatea de orientare a listei
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register("Orientation",
typeof(Orientation),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(Orientation.Vertical,
new PropertyChangedCallback(OnOrientationChanged),
new CoerceValueCallback(OnCoerceOrientation))
);
private static object OnCoerceOrientation(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceOrientation((Orientation)value);
else return value;
}
private static void OnOrientationChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnOrientationChanged((Orientation)e.OldValue, (Orientation)e.NewValue);
}
protected virtual Orientation OnCoerceOrientation(Orientation value)
{
return value;
}
protected virtual void OnOrientationChanged(Orientation oldValue, Orientation newValue)
{
}
public Orientation Orientation
{
get
{
return (Orientation)GetValue(OrientationProperty);
}
set
{
SetValue(OrientationProperty, value);
}
}
//proprietatea de multiplicator de deplasament a chenarului de oprire a elementului evidentiat
public static readonly DependencyProperty StopWindowOffsetProperty =
DependencyProperty.Register("StopWindowOffset",
typeof(double),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(-1.0,
new PropertyChangedCallback(OnStopWindowOffsetChanged),
new CoerceValueCallback(OnCoerceStopWindowOffset))
);
private static object OnCoerceStopWindowOffset(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceStopWindowOffset((double)value);
else return value;
}
private static void OnStopWindowOffsetChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnStopWindowOffsetChanged((double)e.OldValue, (double)e.NewValue);
}
protected virtual double OnCoerceStopWindowOffset(double value)
{
return value;
}
protected virtual void OnStopWindowOffsetChanged(double oldValue, double newValue)
{
}
public double StopWindowOffset
{
get
{
return (double)GetValue(StopWindowOffsetProperty);
}
set
{
SetValue(StopWindowOffsetProperty, value);
}
}
//proprietatea de comportament la capete
public static readonly DependencyProperty ScrollLimitBehaviourProperty =
DependencyProperty.Register("ScrollLimitBehaviour",
typeof(ScrollLimitBehaviour),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(ScrollLimitBehaviour.Springs,
new PropertyChangedCallback(OnScrollLimitBehaviourChanged),
new CoerceValueCallback(OnCoerceScrollLimitBehaviour))
);
private static object OnCoerceScrollLimitBehaviour(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceScrollLimitBehaviour((ScrollLimitBehaviour)value);
else return value;
}
private static void OnScrollLimitBehaviourChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnScrollLimitBehaviourChanged((ScrollLimitBehaviour)e.OldValue, (ScrollLimitBehaviour)e.NewValue);
}
protected virtual ScrollLimitBehaviour OnCoerceScrollLimitBehaviour(ScrollLimitBehaviour value)
{
return value;
}
protected virtual void OnScrollLimitBehaviourChanged(ScrollLimitBehaviour oldValue, ScrollLimitBehaviour newValue)
{
}
public ScrollLimitBehaviour ScrollLimitBehaviour
{
get
{
return (ScrollLimitBehaviour)GetValue(ScrollLimitBehaviourProperty);
}
set
{
SetValue(ScrollLimitBehaviourProperty, value);
}
}
//proprietatea de existenta a filtrarii
public static readonly DependencyProperty CanFilterProperty =
DependencyProperty.Register("CanFilter",
typeof(bool),
typeof(SmoothScrollViewer),
new UIPropertyMetadata(false,
new PropertyChangedCallback(OnCanFilterChanged),
new CoerceValueCallback(OnCoerceCanFilter))
);
private static object OnCoerceCanFilter(DependencyObject o, Object value)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) return ssw.OnCoerceCanFilter((bool)value);
else return value;
}
private static void OnCanFilterChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
SmoothScrollViewer ssw = o as SmoothScrollViewer;
if (ssw != null) ssw.OnCanFilterChanged((bool)e.OldValue, (bool)e.NewValue);
}
protected virtual bool OnCoerceCanFilter(bool value)
{
return value;
}
protected virtual void OnCanFilterChanged(bool oldValue, bool newValue)
{
}
public bool CanFilter
{
get
{
return (bool)GetValue(CanFilterProperty);
}
set
{
SetValue(CanFilterProperty, value);
}
}
//previne scroll-ul prin drag in afara listei
protected override void OnMouseMove(MouseEventArgs e)
{
}
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e)
{
}
//copie ItemsSource in Items
protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
{
base.OnItemsSourceChanged(oldValue, newValue);
if (ItemsSource != null)
{
ObservableCollection<object> temp = new ObservableCollection<object>();
foreach (object o in ItemsSource) temp.Add(o);
ItemsSource = null;
for (int i = 0; i < temp.Count; i++) Items.Add(temp[i]);
}
}
//returneaza elementul primit ca parametru ca ListBoxItem
private ListBoxItem getListBoxItem(UIElement element)
{
if (element is ListBoxItem) return element as ListBoxItem;
while (element != this && element != null)
{
element = VisualTreeHelper.GetParent(element) as UIElement;
if (element is ListBoxItem) return element as ListBoxItem;
}
return null;
}
//la aplicarea sablonului vizual au loc asocierile de evenimente si initializarile
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
sv = GetTemplateChild("PART_ScrollViewer") as ScrollViewer;
sp = GetTemplateChild("PART_StackPanel") as StackPanel;
g = GetTemplateChild("PART_Grid") as Grid;
if ((ScrollBarVisibility)GetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty) == ScrollBarVisibility.Disabled) sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
if ((ScrollBarVisibility)GetValue(ScrollViewer.VerticalScrollBarVisibilityProperty) == ScrollBarVisibility.Disabled) sv.VerticalScrollBarVisibility = ScrollBarVisibility.Hidden;
sp.PreviewMouseDown += new MouseButtonEventHandler(l_MouseDown);
sp.PreviewMouseMove += new MouseEventHandler(l_MouseMove);
sp.PreviewMouseUp += new MouseButtonEventHandler(l_MouseUp);
sp.MouseLeave += new MouseEventHandler(l_MouseLeave);
sp.PreviewMouseWheel += new MouseWheelEventHandler(l_PreviewMouseWheel);
sp.PreviewKeyDown += new KeyEventHandler(sp_PreviewKeyDown);
if (Orientation == Orientation.Vertical)
{
sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
HorizontalContentAlignment = HorizontalAlignment.Stretch;
}
else
{
sv.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
VerticalContentAlignment = VerticalAlignment.Stretch;
}
scroll_timerClock.Interval = new TimeSpan(0, 0, 0, 0, 1);
decelerateEventHandler = new EventHandler(scroll_timerClock_Tick);
adjustEventHandler = new EventHandler(adjust_timerClock_Tick);
scroll_timerClock.Tick += decelerateEventHandler;
LayoutUpdated += new EventHandler(l_LayoutUpdated);
PreviewMouseDown += new MouseButtonEventHandler(SmoothScrollViewer_MouseDown);
}
//prin interactiunea cu mouse-ul asupra listei, se initiaza o actiune de
//selectie non-externa
void SmoothScrollViewer_MouseDown(object sender, MouseButtonEventArgs e)
{
external = false;
}
//functie de scroll la element specificat
public void ScrollTo(object item)
{
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
int indexOfItem = Items.IndexOf(item);
int nrItemsToMove = 0,
i = 0;
double cummulativeSize = 0;
do
{
lbi = (ListBoxItem)(ItemContainerGenerator.ContainerFromIndex(i));
cummulativeSize += (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
i++;
nrItemsToMove++;
}
while (cummulativeSize <= ((Orientation == Orientation.Vertical) ? sv.ViewportHeight : sv.ViewportWidth));
if (indexOfItem > Items.Count - nrItemsToMove || indexOfItem == 0)
{
for (i = 0; i <= nrItemsToMove; i++)
{
object elt = Items[0];
Items.RemoveAt(0);
Items.Add(elt);
}
indexOfItem = Items.IndexOf(item);
}
double scrollAmount = 0;
for (i = 0; i < indexOfItem - 1; i++)
{
lbi = (ListBoxItem)(ItemContainerGenerator.ContainerFromIndex(i));
scrollAmount += (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
}
if (Orientation == Orientation.Vertical) sv.ScrollToVerticalOffset(scrollAmount);
else sv.ScrollToHorizontalOffset(scrollAmount);
selectionAllowed = true;
SelectedItem = item;
selectionAllowed = false;
scroll_out = false;
}
}
//Manipularea listei din tastele sageti
void sp_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (((e.Key == Key.Right || e.Key == Key.Left) && Orientation == Orientation.Horizontal) || ((e.Key == Key.Up || e.Key == Key.Down) && Orientation == Orientation.Vertical))
{
adjustLimit = 0;
scrollLessThanZero = false;
scrollMoreThanEnd = false;
SelectedIndex = -1;
backOffset = ((Orientation == Orientation.Vertical) ? (sv.ExtentHeight - sv.ViewportHeight) : (sv.ExtentWidth - sv.ViewportWidth));
scroll_mouseDown = false;
scroll_v0 = (e.Key == Key.Right || e.Key == Key.Up ? -1 : 1);
scroll_t0 = Environment.TickCount;
scroll_direction = (scroll_v0 >= 0);
scroll_offset0 = ((Orientation == Orientation.Vertical) ? sv.VerticalOffset - sp.Margin.Top : sv.HorizontalOffset - sp.Margin.Left);
scroll_timerClock.IsEnabled = true;
}
else
if (e.Key == Key.Return && stopWindow == null)
{
UIElement elt = InputHitTest(new Point(ActualWidth / 2, ActualHeight / 2)) as UIElement;
if (elt != null)
{
lbi = getListBoxItem(elt);
selectionAllowed = true;
SelectedIndex = ItemContainerGenerator.IndexFromContainer(lbi);
}
}
e.Handled = true;
}
//la ficare actualizare a randarii controlului, se initializeaza/redimensioneaza chenarul
//de oprire a elementului selectabil si campul editabil de filtrare in cazul in care acesta
//exista
void l_LayoutUpdated(object sender, EventArgs e)
{
try
{
if (StopWindowOffset >= 0)
{
lbi = (ListBoxItem)(ItemContainerGenerator.ContainerFromIndex(((SelectedIndex > 0) ? SelectedIndex : selectedIndex)));
hitOffset = (Orientation == Orientation.Vertical) ? lbi.ActualHeight / 4 : lbi.ActualWidth / 4;
stopWindowCoord = StopWindowOffset * ((Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth);
if (stopWindow == null)
{
stopWindow = new Rectangle();
stopWindow.SetValue(Grid.RowProperty, 1);
stopWindow.HorizontalAlignment = HorizontalAlignment.Left;
stopWindow.VerticalAlignment = VerticalAlignment.Top;
stopWindow.Fill = BorderBrush;
stopWindow.Opacity = 0.5;
stopWindow.IsHitTestVisible = false;
g.Children.Add(stopWindow);
}
stopWindow.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, stopWindowCoord, 0, 0) : new Thickness(stopWindowCoord, 0, 0, 0);
stopWindow.Width = lbi.ActualWidth;
stopWindow.Height = lbi.ActualHeight;
}
if (CanFilter)
{
if (filterEdit == null)
{
filterEdit = new TextBox();
filterEdit.HorizontalAlignment = HorizontalAlignment.Center;
filterEdit.VerticalAlignment = VerticalAlignment.Top;
filterEdit.Margin = new Thickness(3);
filterEdit.TextChanged += new TextChangedEventHandler(filterEdit_TextChanged);
filterEdit.PreviewKeyDown += new KeyEventHandler(filterEdit_KeyDown);
g.Children.Add(filterEdit);
}
filterEdit.Width = ActualWidth - 20;
}
}
catch (Exception) { }
}
//La apasarea tastei sageata jos in filtru, se coboara in lista
void filterEdit_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
sp.Focusable = true;
Keyboard.Focus(sp);
}
}
//textul dupa care are loc filtrarea
void filterEdit_TextChanged(object sender, TextChangedEventArgs e)
{
Items.Filter = new Predicate<object>(PassesFilter);
}
public bool PassesFilter(Object value)
{
if (filterEdit.Text != "")
{
Regex regex = new Regex("^" + Regex.Escape(filterEdit.Text).Replace("\\*", ".*").Replace("\\?", ".") + ".*$");
return regex.IsMatch(extractText(value as UIElement));
}
else return true;
}
//tratarea evenimentului de selectie asupra unui element din lista
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
//MessageBox.Show(selectedIndex+" "+SelectedIndex);
if (!external)
{
//MessageBox.Show(SelectedIndex + "");
if (!selectionAllowed)
{
if (SelectedIndex != -1)
{
selectedIndex = SelectedIndex;
SelectedIndex = -1;
}
}
}
else selectionAllowed = false;
external = true;
base.OnSelectionChanged(e);
}
//Extrage textul care apare in interiorul oricarui control
private string extractText(UIElement item)
{
if (item is TextBlock) return ((TextBlock)item).Text;
if (item is TextBox) return ((TextBox)item).Text;
if (item is ContentControl)
{
object content = ((ContentControl)item).Content;
if (content is UIElement) return extractText(content as UIElement);
else return content.ToString();
}
else
{
string result = "";
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(item); i++)
result += extractText(VisualTreeHelper.GetChild(item, i) as UIElement) + " ";
return result;
}
}
//scroll prin rotita mouse-ului
void l_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
sp.Focusable = true;
Keyboard.Focus(sp);
adjustLimit = 0;
scrollLessThanZero = false;
scrollMoreThanEnd = false;
SelectedIndex = -1;
backOffset = ((Orientation == Orientation.Vertical) ? (sv.ExtentHeight - sv.ViewportHeight) : (sv.ExtentWidth - sv.ViewportWidth));
scroll_mouseDown = false;
scroll_v0 = -e.Delta / 100;
scroll_t0 = Environment.TickCount;
scroll_direction = (scroll_v0 >= 0);
scroll_offset0 = ((Orientation == Orientation.Vertical) ? sv.VerticalOffset - sp.Margin.Top : sv.HorizontalOffset - sp.Margin.Left);
scroll_timerClock.IsEnabled = true;
}
//la parasirea controlului de catre cursorul mouse-ului, cu butonul apasat, se simuleaza
//invocarea unui eveniment de eliberare a butonului mouse-ului
private void l_MouseLeave(object sender, MouseEventArgs e)
{
if (scroll_mouseDown)
{
MouseButtonEventArgs e1 = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, MouseButton.Left);
e1.RoutedEvent = MouseLeaveEvent;
l_MouseUp(sender, e1);
}
}
//scroll controlat de miscarea mouse-ului
private void l_MouseMove(object sender, MouseEventArgs e)
{
if (scroll_mouseDown)
{
scroll_offset = scroll_init - ((Orientation == Orientation.Vertical) ? e.GetPosition(this).Y : e.GetPosition(this).X);
if (scroll_offset < 0)
if (ScrollLimitBehaviour == ScrollLimitBehaviour.Springs) sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, -scroll_offset, 0, 0) : new Thickness(-scroll_offset, 0, 0, 0);
else
{
if (canUpdate)
{
object elt = Items[Items.Count - 1];
Items.RemoveAt(Items.Count - 1);
Items.Insert(0, elt);
lbi = (ListBoxItem)ItemContainerGenerator.ContainerFromIndex(Items.Count - 1);
double adjust = (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
scroll_init += adjust;
canUpdate = false;
}
}
else
if (scroll_offset - backOffset > 0)
if (ScrollLimitBehaviour == ScrollLimitBehaviour.Springs) sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, 0, 0, scroll_offset - backOffset) : new Thickness(0, 0, scroll_offset - backOffset, 0);
else
{
if (canUpdate)
{
object elt = Items[0];
Items.RemoveAt(0);
Items.Add(elt);
lbi = (ListBoxItem)ItemContainerGenerator.ContainerFromIndex(0);
double adjust = (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.ActualWidth;
scroll_init -= adjust;
canUpdate = false;
}
}
else canUpdate = true;
if ((Orientation == Orientation.Vertical)) sv.ScrollToVerticalOffset(scroll_offset);
else sv.ScrollToHorizontalOffset(scroll_offset);
}
}
//comportamentul la eliberarea butonului mouse-ului; daca miscarea efectuata este una
//minora, se recurge la selectarea elementului vizat, altfel se continua cu initierea
//miscarii inertiale induse de acceleratia impusa de miscarea pana in acest moment
private void l_MouseUp(object sender, MouseButtonEventArgs e)
{
double move_offset = move_init - ((Orientation == Orientation.Vertical) ? e.GetPosition(this).Y : e.GetPosition(this).X);
selectionAllowed = (Math.Abs(move_offset) <= 10 && SelectedIndex != selectedIndex && StopWindowOffset < 0);
if (selectionAllowed) SelectedIndex = selectedIndex;
adjustLimit = 0;
if (scroll_mouseDown && move_offset != 0)
{
scroll_mouseDown = false;
scroll_span = Environment.TickCount - scroll_t0;
if (scroll_span > 0) scroll_v0 = move_offset / scroll_span;
else scroll_v0 = 0;
scroll_t0 = Environment.TickCount;
scroll_direction = (move_offset >= 0);
scroll_offset0 = ((Orientation == Orientation.Vertical) ? sv.VerticalOffset - sp.Margin.Top : sv.HorizontalOffset - sp.Margin.Left);
scroll_timerClock.IsEnabled = true;
}
else
{
scroll_mouseDown = false;
if (move_offset == 0) scrollStopped();
}
}
//timer-ul responsabil cu actualizarea deplasamentului de derulare in urma miscarii
//uniform incetinite de dupa eliberarea butonului mouse-ului
private void scroll_timerClock_Tick(object sender, EventArgs e)
{
double scroll_a = (scroll_direction ? -1 : 1) * ((scroll_out) ? 0.005 : 0.003),
scroll_t = Environment.TickCount - scroll_t0,
scroll = 0.5 * scroll_a * scroll_t * scroll_t + scroll_v0 * scroll_t + scroll_offset0,
scroll_v = scroll_a * scroll_t + scroll_v0;
if (scroll > 0 && scroll < Math.Abs(backOffset))
if (scroll_out)
{
sp.Margin = new Thickness(0, 0, 0, 0);
scroll_out = false;
scrollStopped();
}
else
{
if (Orientation == Orientation.Vertical) sv.ScrollToVerticalOffset(scroll);
else sv.ScrollToHorizontalOffset(scroll);
if ((scroll_v <= 0) == scroll_direction) scrollStopped();
}
else
if (ScrollLimitBehaviour == ScrollLimitBehaviour.Springs)
{
if (scroll < 0) scrollLessThanZero = true;
else scrollMoreThanEnd = true;
if (scrollLessThanZero && scrollMoreThanEnd)
{
sp.Margin = new Thickness(0, 0, 0, 0);
scrollLessThanZero = false;
scrollMoreThanEnd = false;
scroll_out = false;
scrollStopped();
}
else
{
scroll_out = true;
if (scroll > 0) sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, 0, 0, scroll - backOffset) : new Thickness(0, 0, scroll - backOffset, 0);
else sp.Margin = (Orientation == Orientation.Vertical) ? new Thickness(0, -scroll, 0, 0) : new Thickness(-scroll, 0, 0, 0);
if (Orientation == Orientation.Vertical) sv.ScrollToVerticalOffset(scroll);
else sv.ScrollToHorizontalOffset(scroll);
}
}
else
{
scroll_out = false;
if (scroll <= 0)
{
object elt = Items[Items.Count - 1];
Items.RemoveAt(Items.Count - 1);
Items.Insert(0, elt);
lbi = (ListBoxItem)ItemContainerGenerator.ContainerFromIndex(Items.Count - 1);
double adjust = (Orientation == Orientation.Vertical) ? lbi.ActualHeight : lbi.A

Resources