Silverlight programmatically binding from C# code - silverlight

I have a Canvas and a custom control called BasicShape
After I add two BasicShape controls on the Canvas, I want programatically to connect them with a Line and I want to do this using the Binding class.
I want to connect the Bottom side of first shape with the Top side of the second one.
Initially i tried to connect only the X1 property of the Line with the Canvas.Left attached property of the fisrt BasicShape but this doesn't work. Line X1 property is not updated when I change the Canvas.SetLeft(basicShape1) value
BasicShape bs1 = canvas.Children[0] as BasicShape;
BasicShape bs2 = canvas.Children[1] as BasicShape;
Line line = new Line();
line.StrokeThickness = 1;
line.Stroke = new SolidColorBrush(Colors.Red);
line.X1 = 100;
line.Y1 = 100;
line.X2 = 200;
line.Y2 = 200;
canvas.Children.Add(line);
Binding b = new Binding("AnyName");
b.Source = bs1;
b.Path = new PropertyPath(Canvas.LeftProperty);
line.SetBinding(Line.X1Property, b);
I'm trying to create a simple UML diagram like this one
alt text http://www.invariant-corp.com/omechron/images/uml_diagram.gif

I just did it other way, without binding
This will be a permanent link
http://calciusorin.com/SilverlightDiagrams/
I decided to manually update all lines on shape Location or Size changed
private void basicShape_BasicShapeLocationSizeChangedEvent(BasicShape sender)
{
foreach (CustomLine customLine in lines)
{
if (customLine.StartFromShape(sender))
{
Point point = sender.GetLinePoint(customLine.GetStartSide());
customLine.SetStartPoint(point);
}
if (customLine.EndInShape(sender))
{
Point point = sender.GetLinePoint(customLine.GetEndSide());
customLine.SetEndPoint(point);
}
}
}
I am sure that the Binding solution is more elegant. Anyone interested in my solution, with SL Controls that can be resized, connected with lines, just contact me.

Related

Why Geometry intersection does not give the expected result with polylines with more than one line?

I need to calculate the intersection between two geometries to check if one is fully inside the other or not.
The Geometry "container", based on a System.Windows.Shapes.Polygon, is created as follows:
List<PathSegment> basePolygonSegments = new List<PathSegment> {
new PolyLineSegment(basePolygon.Points, true) };
PathGeometry baseGeometry = new PathGeometry();
baseGeometry.Figures.Add(
new PathFigure(basePolygon.Points[0], basePolygonSegments, true));
The Geometry "contained" can be:
another System.Windows.Shapes.Polygon
a System.Windows.Shapes.Polyline, that can have only one line or three lines (the shape is a |_|, or U)
The Polyline is created as follows:
Polyline bracketDrawingPolyline = new Polyline();
foreach(Point p in listOfPoints)
bracketDrawingPolyline.Points.Add(p);
LineGeometry lineGeometry =
new LineGeometry(
bracketDrawingPolyline.Points[0],
bracketDrawingPolyline.Points[bracketDrawingPolyline.Points.Count - 1]);
PathGeometry bracketGeometry = new PathGeometry();
bracketGeometry = lineGeometry.GetWidenedPathGeometry(
new Pen(Brushes.Black, 1.0));
To understand if the "contained" Geometry is contained in the "container", I do the following:
CombinedGeometry intersectionGeometry =
new CombinedGeometry(GeometryCombineMode.Intersect,
baseGeometry, bracketGeometry);
double intersectionArea =
intersectionGeometry.GetArea(0.0001, ToleranceType.Absolute);
double bracketArea = bracketGeometry.GetArea(0.0001, ToleranceType.Absolute);
if (intersectionArea < bracketArea)
{
//the second Geometry is not fully contained in the "container" Geometry
}
else
//it is fully contained
....
In case of Polygon or Polyline with only one line everything works as expected. But with Polyline U, intersectionArea and bracketArea are always the same.
I've also tried to perform the following checks:
bool result = baseGeometry.FillContains(bracketGeometry);
IntersectionDetail idtl =
baseGeometry.FillContainsWithDetail(bracketGeometry);
but I have the same results.
I've found a solution on my own, but I don't know if it is the best one.
Considered that with a single line everything works well, I just do the check for each line of the polyline, that is:
for (int i = 1; i < bracketDrawingPolyline.Points.Count; i++)
{
LineGeometry lineGeometry =
new LineGeometry(bracketDrawingPolyline.Points[i - 1],
bracketDrawingPolyline.Points[i]);
...//continue with the check of the line as described in the post...
}

How to animate ListBoxItem position

I am having some trouble animating the items in my ListBox. Animations on the OpacityProperty work great but when i try to animate the position of my ListBoxItem it simply does not move an inch (No exceptions are thrown, not even a log message indicating error).
Here is the code i am using:
private void deletAnimation()
{
Todo todoToDelete = App.ViewModel.Todos[1];
Storyboard storyboard = new Storyboard();
DoubleAnimation alphaAnim = new DoubleAnimation();
alphaAnim.From = 1;
alphaAnim.To = 0;
alphaAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
ListBoxItem target = TodoList.ItemContainerGenerator.ContainerFromItem(todoToDelete) as ListBoxItem;
Storyboard.SetTarget(alphaAnim, target);
Storyboard.SetTargetProperty(alphaAnim, new PropertyPath(UIElement.OpacityProperty));
storyboard.Children.Add(alphaAnim);
for (int i = App.ViewModel.Todos.IndexOf(todoToDelete) + 1; i < App.ViewModel.Todos.Count; i++)
{
Todo todo = App.ViewModel.Todos[i];
target = TodoList.ItemContainerGenerator.ContainerFromItem(todo) as ListBoxItem;
DoubleAnimation translateAnim = new DoubleAnimation();
translateAnim.From = target.RenderTransformOrigin.Y;
translateAnim.To = target.RenderTransformOrigin.Y - target.ActualHeight;
translateAnim.Duration = new Duration(TimeSpan.FromMilliseconds(500));
translateAnim.BeginTime = TimeSpan.FromMilliseconds(500);
Storyboard.SetTarget(translateAnim, target);
Storyboard.SetTargetProperty(translateAnim, new PropertyPath(TranslateTransform.YProperty));
storyboard.Children.Add(translateAnim);
}
storyboard.Begin();
}
Some things i have noticed while debugging:
The RenderTransformOrigin.Y property is always 0 no matter which ListBoxItem is referenced.
The Height property is NaN though the ActualHeight property is 67
The parent property of the ListBoxItem is null
These two things make me wonder if i am given a reference to a ListBoxItem that is not rendered of the screen? But as the Opacity animation works perfectly and all of my list is visible(only contains 3 items at the moment) i do not see how this could be the case.
I have also tried using a PointAnimation and animating the RenderTransformOrigin property directly but this gave the same result (nothing that is).
Any help is appreciated, thanks!
Please check out this link:
http://blogs.msdn.com/b/jasongin/archive/2011/01/03/wp7-reorderlistbox-improvements-rearrange-animations-and-more.aspx
Someone has created a class that you can easily incorporate into your app. This has animations for adding/removing items from your list.
This should save you a lot of time and frustration.

WPF - Text box that grows vertically to accommodate all text

The problem: I am not getting a textbox setting that will have a horizontally wordwrap and vertically auto grow functionality. I wish to do that by writing a code. I have written following code that creates a text box at mouse dblclick with wordwrap:
TextBox text2 = new TextBox();
text2.Width = 500;
text2.Visibility = Visibility.Visible;
text2.Focus();
text2.Height = 30;
text2.HorizontalAlignment = HorizontalAlignment.Left;
text2.VerticalAlignment = VerticalAlignment.Top;
Point p = e.GetPosition(LayoutRoot);
text2.Margin = new Thickness(p.X, p.Y, 0, 0);
LayoutRoot.Children.Add(text2);
But, textbox does not grow vertically.
Can somebody suggest me a code in C# to do exactly what I desire?
try using this
Grid grid = new Grid();
grid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
grid.RowDefinitions.Add(new RowDefinition());
TextBox textBox = new TextBox() { Width = 100, TextWrapping = TextWrapping.Wrap };
textBox.SetValue(Grid.RowProperty, 0);
grid.Children.Add(textBox);
window.Content = grid;
where window is the Name assigned to Window(root).
One way to accomplish the growth you're looking for is to use a string measuring mechanism which you would run any time the text in your text box changes. Simply measure and resize your text box accordingly with any change to the contents.
Have you tried this?
text2.Height = double.NaN; // or don't set the property, but some custom styles might give a default value ..
text2.TextWrapping = TextWrapping.Wrap;
text2.MinHeight = 30; // or not if you want the styles default
instead of
text2.Height = 30;
not setting it or using double.NaN is the same as using 'Auto' in xaml.

Silverlight specific Image shifting to the right

I am generating a set images to form a human body so that I can use for a physics engine.
The images generated are in a specific user control in where I set the dimentions and co-ordinates of each image. That usercontrol is then loaded in another user control but for some reason when the images are loaded, one specific image which I named (rightBicep) is shifting to the right. Here is a screenshot :
alt text http://img193.imageshack.us/img193/592/imageshift.jpg
I illustrated the positions of the images with dotted lines, the green dotted line is refering to where the image should be located, and the red dotted line is where the image is being shown.
The weird thing is the image beneath it (called rightForearm) take's it's LeftPosition from it, and when during debugging they have the exact same leftProperty value. Here's the syntax :
public void generateRightBicep(string imageUrl)
{
rightBicep = new Image();
rightBicep.Name = CharacterName + "rightbicep";
Uri imageUri = new Uri(imageUrl, UriKind.Relative);
LayoutRoot.Children.Add(rightBicep);
rightBicep.Source = new BitmapImage(imageUri);
rightBicep.ImageOpened += new EventHandler<RoutedEventArgs>(bodyPart_ImageOpened);
}
public void rightBicepLoaded()
{
var bi = waitTillImageLoad(rightBicep.Name);
rightBicep.Height = elbowToArmpit + (2 * palm);
rightBicep.Width = ratio(bi.PixelHeight, bi.PixelHeight, rightBicep.Height); // to be determined
Vector2 topVector;
topVector.X = (float)(Convert.ToDouble(torso.GetValue(Canvas.LeftProperty)) - palm);
topVector.Y = (float)(Convert.ToDouble(neck.GetValue(Canvas.TopProperty)) + neck.Height);
if (!faceRight)
{
perspectiveVectorHeight(ref topVector, ref rightBicep, torso.Width);
rightBicep.Width = ratio(bi.PixelHeight, bi.PixelHeight, rightBicep.Height);
}
rightBicep.SetValue(Canvas.LeftProperty, Convert.ToDouble(topVector.X));
rightBicep.SetValue(Canvas.TopProperty, Convert.ToDouble(topVector.Y));
rightBicep.SetValue(Canvas.ZIndexProperty, rightBicepZindex);
generateRightShoulder();
}
public void generateRightForearm(string imageUrl)
{
rightForearm = new Image();
rightForearm.Name = CharacterName + "rightforearm";
Uri imageUri = new Uri(imageUrl, UriKind.Relative);
LayoutRoot.Children.Add(rightForearm);
rightForearm.Source = new BitmapImage(imageUri);
rightForearm.ImageOpened += new EventHandler<RoutedEventArgs>(bodyPart_ImageOpened);
}
public void rightForearmLoaded()
{
var bi = waitTillImageLoad(rightForearm.Name);
rightForearm.Height = (elbowToHandTip - handLength) + palm;
rightForearm.Width = ratio(bi.PixelHeight, bi.PixelWidth, rightForearm.Height);
Vector2 topVector;
if (faceRight)
{
topVector.X = (float)(Convert.ToDouble(rightBicep.GetValue(Canvas.LeftProperty)));
topVector.Y = (float)(Convert.ToDouble(rightBicep.GetValue(Canvas.TopProperty)) + rightBicep.Height - palm);
}
else
{
topVector.X = (float)(Convert.ToDouble(leftBicep.GetValue(Canvas.LeftProperty)));
topVector.Y = (float)(Convert.ToDouble(leftBicep.GetValue(Canvas.TopProperty)) + leftBicep.Height - palm);
perspectiveVectorHeight(ref topVector, ref rightForearm, torso.Width);
rightForearm.Width = ratio(bi.PixelHeight, bi.PixelWidth, rightForearm.Height);
}
rightForearm.SetValue(Canvas.LeftProperty, Convert.ToDouble(topVector.X));
rightForearm.SetValue(Canvas.TopProperty, Convert.ToDouble(topVector.Y));
rightForearm.SetValue(Canvas.ZIndexProperty, rightForearmZIndex);
generateRightElbow();
}
Now all the values I am adding together are a group of doubles I preset, and the property faceRight is to dertmine if the human body is facing right or left to determine where the positions of the body parts (since if the right hand looks on the left hand side when the human body turns the other way).
If you notice the rightforearm is taking the leftproperty of the rightbicep, so technically it should display direcrly underneath which it isn't. I also debugged the user control and both have the left property of -3.
PS. I call the methods rightbicepLoaded and rightforearmLoaded when an event is called when all the imageOpened events all have been triggered.
Any ideas on why this is happening?
Found out why , in my method ratio it should take hieght and width, and I put and i put 2 hieghts instead

Silverlight data binding in the code behind

I am doing something like this in a Silverlight 3 datagrid:
for (int x = 0; x < ThisForecast.Periods.Count; x++)
{
var TextColumn = new DataGridTextColumn();
TextColumn.Header = ThisForecast.Periods[x].Name;
TextColumn.Binding = new Binding(String.Format("Periods[{0}].Quantity", x));
TextColumn.Binding.Mode = BindingMode.TwoWay;
TextColumn.IsReadOnly = false;
dgItemForecast.Columns.Add(TextColumn);
}
And it works great, but I want to change the ready only to something more like:
TextColumn.IsReadOnly = new Binding(String.Format("Periods[{0}].IsReadOnly", x));
And while it seems easy to do in XAML, I can't figure out the correct method to do this in the code behind. Obviously I can't set it to a 'binding', but where would I be able to set something like that?
EDIT #1:
I looked at the BindingOperations.SetBinding() given below, but could not find a DependencyProperty for IsReadOnly. Is there a way to inject/add one?
BindingOperations.SetBinding(textColumn, DataGridTextColumn.IsReadOnlyProperty, new Binding(...));

Resources