I use the following code to connect two ScatterViewItems. Unfortunately this does not work because the center property isn't asingle value. But I can't read out values x and y from the CenterProperty:
Line l = new Line();
l.Stroke = Brushes.Green;
l.StrokeThickness = 10;
Binding x1 = new Binding(); x1.Path = new PropertyPath(ScatterViewItem.CenterProperty);
x1.Converter = new MyConverter();
x1.ConverterParameter = root;
Binding y1 = new Binding(); y1.Path = new PropertyPath(ScatterViewItem.CenterProperty);
y1.Converter = new MyConverter();
y1.ConverterParameter = root;
Binding x2 = new Binding(); x2.Path = new PropertyPath(ScatterViewItem.CenterProperty);
x2.Converter = new MyConverter();
x2.ConverterParameter = level1;
Binding y2 = new Binding(); y2.Path = new PropertyPath(ScatterViewItem.CenterProperty);
y2.Converter = new MyConverter();
y2.ConverterParameter = level1;
x1.Source = y1.Source = root;
x2.Source = y2.Source = level1;
l.SetBinding(Line.X1Property, x1);
l.SetBinding(Line.Y1Property, y1);
l.SetBinding(Line.X2Property, x2);
l.SetBinding(Line.Y2Property, y2);
Dependencies.Children.Add(l);
l.Tag = new Call(focus, file);
Contacts.AddPreviewContactDownHandler(l, OnLineDown);
SizeChangedEventHandler act = (Object s, SizeChangedEventArgs args) =>
{
BindingOperations.GetBindingExpressionBase(l, Line.X1Property).UpdateTarget();
BindingOperations.GetBindingExpressionBase(l, Line.Y1Property).UpdateTarget();
BindingOperations.GetBindingExpressionBase(l, Line.X2Property).UpdateTarget();
BindingOperations.GetBindingExpressionBase(l, Line.Y2Property).UpdateTarget();
};
root.SizeChanged += act;
level1.SizeChanged += act;
I'm now using the followng solution, proposed in the Microsoft Surface Development forum by Sebastian:
XAML:
<s:SurfaceWindow
x:Class="Lines.SurfaceWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
Title="Lines"
>
<Grid>
<Canvas x:Name="LineHost"/>
<s:ScatterView x:Name="ScatterView"/>
</Grid>
</s:SurfaceWindow>
Code-behind:
private void BindLineToScatterViewItems(Line line, ScatterViewItem origin,
ScatterViewItem destination)
{
// Bind line.(X1,Y1) to origin.ActualCenter
BindingOperations.SetBinding(line, Line.X1Property, new Binding {
Source = origin, Path = new PropertyPath("ActualCenter.X") });
BindingOperations.SetBinding(line, Line.Y1Property, new Binding {
Source = origin, Path = new PropertyPath("ActualCenter.Y") });
// Bind line.(X2,Y2) to destination.ActualCenter
BindingOperations.SetBinding(line, Line.X2Property, new Binding {
Source = destination, Path = new PropertyPath("ActualCenter.X") });
BindingOperations.SetBinding(line, Line.Y2Property, new Binding {
Source = destination, Path = new PropertyPath("ActualCenter.Y") });
}
Then if you want to create a line between two ScatterViewItems, simply do this:
var origin = new ScatterViewItem();
var destination = new ScatterViewItem();
Line line = new Line { Stroke = Brushes.Black, StrokeThickness = 2.0 };
BindLineToScatterViewItems(line, origin, destination);
ScatterView.Items.Add(origin);
ScatterView.Items.Add(destination);
LineHost.Children.Add(line);
Related
I am pretty new to WPF... So I need to bind a lines X1 and Y1 properties with an ellipses canvas.left and canvas.top property......
In XAML it works fine...
XAML Code
<Ellipse x:Name="tst" Width="40" Height="40" Canvas.Left="150" Canvas.Top="150" Stroke="Blue" StrokeThickness="2" MouseMove="adjustRoute"/>
<Line X1="{Binding ElementName=tst, Path=(Canvas.Left)}" Y1="{Binding ElementName=tst, Path=(Canvas.Top)}" X2="300" Y2="200" Stroke="Blue" StrokeThickness="2"/>
But I need to do it in the Code Behind Using C#
So I did this
temp = new Line();
tempe = new Ellipse();
tempe.Fill = Brushes.Transparent;
tempe.Stroke = Brushes.Blue;
tempe.StrokeThickness = 1;
tempe.Width = 20;
tempe.Height = 20;
Canvas.SetLeft(tempe, currentPoint.X-10);
Canvas.SetTop(tempe, currentPoint.Y-10);
tempe.MouseMove += adjustRoute;
Binding binding = new Binding { Source = tempe, Path = new PropertyPath(Canvas.LeftProperty), UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged };
temp.SetBinding(Line.X1Property, binding);
Binding binding2 = new Binding { Source = tempe, Path = new PropertyPath(Canvas.TopProperty), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
temp.SetBinding(Line.Y1Property, binding2);
temp.Stroke = Brushes.Blue;
temp.StrokeThickness = 2;
temp.X1 = currentPoint.X;
temp.Y1 = currentPoint.Y;
temp.X2 = currentPoint.X + 200;
temp.Y2 = currentPoint.Y + 200;
testcanv.Children.Add(temp);
testcanv.Children.Add(tempe);
But it doesn't update the line position when I move the ellipse(in XAML it updates)....
Here currentPoint is the point I am capturing with my mouse click to draw the shapes during runtime and adjustRoute is the function to move them on drag
What did I do wrong here?
Thanks
Make sure you create the Line and Ellipse elements only once, and assign the Bindings only once. Assign the MouseMove handler to the Canvas instead of the Ellipse:
private Line line;
private Ellipse ellipse;
public MainWindow()
{
InitializeComponent();
line = new Line
{
Stroke = Brushes.Blue,
StrokeThickness = 2
};
ellipse = new Ellipse
{
Stroke = Brushes.Blue,
StrokeThickness = 1,
Width = 20,
Height = 20,
Margin = new Thickness(-10)
};
Binding xBinding = new Binding
{
Source = ellipse,
Path = new PropertyPath(Canvas.LeftProperty)
};
line.SetBinding(Line.X1Property, xBinding);
Binding yBinding = new Binding
{
Source = ellipse,
Path = new PropertyPath(Canvas.TopProperty)
};
line.SetBinding(Line.Y1Property, yBinding);
testcanv.Children.Add(line);
testcanv.Children.Add(ellipse);
testcanv.Background = Brushes.Transparent;
testcanv.MouseMove += adjustRoute;
}
private void adjustRoute(object sender, MouseEventArgs e)
{
var p = e.GetPosition(testcanv);
Canvas.SetLeft(ellipse, p.X);
Canvas.SetTop(ellipse, p.Y);
}
Hi I am looking to print a StackPanel that contains a listbox which can contain an infinite number of items and therefore needs to print over multiple pages. I found this code online and it works fine.
public static FixedDocument GetFixedDocument(FrameworkElement toPrint, PrintDialog printDialog)
{
if (printDialog == null)
{
printDialog = new PrintDialog();
}
var capabilities = printDialog.PrintQueue.GetPrintCapabilities(printDialog.PrintTicket);
var pageSize = new Size(printDialog.PrintableAreaWidth, printDialog.PrintableAreaHeight);
var visibleSize = new Size(capabilities.PageImageableArea.ExtentWidth, capabilities.PageImageableArea.ExtentHeight);
var fixedDoc = new FixedDocument();
//If the toPrint visual is not displayed on screen we neeed to measure and arrange it
toPrint.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
toPrint.Arrange(new Rect(new Point(0, 0), toPrint.DesiredSize));
//
var size = toPrint.DesiredSize;
//Will assume for simplicity the control fits horizontally on the page
double yOffset = 0;
while (yOffset < size.Height)
{
var vb = new VisualBrush(toPrint)
{
Stretch = Stretch.None,
AlignmentX = AlignmentX.Left,
AlignmentY = AlignmentY.Top,
ViewboxUnits = BrushMappingMode.Absolute,
TileMode = TileMode.None,
Viewbox = new Rect(0, yOffset, visibleSize.Width, visibleSize.Height)
};
var pageContent = new PageContent();
var page = new FixedPage();
((IAddChild)pageContent).AddChild(page);
fixedDoc.Pages.Add(pageContent);
page.Width = pageSize.Width;
page.Height = pageSize.Height;
var canvas = new Canvas();
FixedPage.SetLeft(canvas, capabilities.PageImageableArea.OriginWidth);
FixedPage.SetTop(canvas, capabilities.PageImageableArea.OriginHeight);
canvas.Width = visibleSize.Width;
canvas.Height = visibleSize.Height;
canvas.Background = vb;
page.Children.Add(canvas);
yOffset += visibleSize.Height;
}
return fixedDoc;
}
However this causes certain items of a listbox to be cut off at the bottom of a page and continued on the next page (as shown below). Is it possible to modify this code in any way to determine the size of the page and if the current listboxitem does not fit onto this page that it starts on the next page? Quite new to all this so any help would be greatly appreciated.
I had a similiar task once and came up with this code, which uses a 'dummy' renderer to determine the height of the element up front and then either adds it to the current page or creates a new one. For sure, that's not a very beautiful solution, but it did the job at the time. Maybe you can take sth. away from it.
Size A4Size = new Size(793.92, 1122.24);
Size InfiniteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
var pages = new List<FrameworkElement>();
int pageNumber = 0;
var printDate = DateTime.Now;
var size = A4Size;
var currentPage = new Report(size, printDate);
currentPage.Render();
var listElements = new Queue<ElementsToPrint>(...);
var dummyRenderer = new Viewbox();
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
var template = (DataTemplate)View.FindResource("ItemTemplate");
dummyRenderer.Child = null;
var availableHeight = currentPage.View.ActualHeight;
while (listElements.Count > 0)
{
var elementToRender = listElements.Dequeue();
dummyRenderer.Child = new ListViewItem()
{
Content = elementToRender,
ContentTemplate = template,
Foreground = Brushes.Black
};
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
var renderedItem = (ListViewItem)dummyRenderer.Child;
dummyRenderer.Child = null;
var willItFit = availableHeight > renderedItem.ActualHeight;
if (willItFit)
{
currentPage.DataListView.Items.Add(renderedItem);
availableHeight -= renderedItem.ActualHeight;
}
else
{
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
dummyRenderer.Child = null;
pages.Add(currentPage);
// Set up a new Page
pageNumber++;
currentPage = new DiaryReport(size,pageNumber,printDate,anonymous);
dummyRenderer.Child = currentPage;
dummyRenderer.Measure(InfiniteSize);
dummyRenderer.Arrange(new Rect(dummyRenderer.DesiredSize));
dummyRenderer.UpdateLayout();
dummyRenderer.Child = null;
availableHeight = currentPage.DataListView.ActualHeight;
currentPage.DataListView.Items.Add(renderedItem);
availableHeight -= renderedItem.ActualHeight;
}
I'm working with UWP and have this problem. I try to manipulate LineGeometry. When I change StartPoint or EndPoint by TranslateTransform.TransformPoint() my line is cutted by some rectangle. I think it's Bounds part, but is it possible to change it or do something to repair it?
Part to draw Violet Points
Path ellipsePoint = new Path();
ellipsePoint.Stroke = new SolidColorBrush(Colors.BlueViolet);
ellipsePoint.StrokeThickness = 3;
ellipsePoint.Fill = new SolidColorBrush(Colors.DarkViolet);
var geometry = new EllipseGeometry();
geometry.Center = point;
geometry.Transform = CompositeTransform;
geometry.RadiusX = geometry.RadiusY = 15;
ellipsePoint.Tag = isStartPoint;
ellipsePoint.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateY;
var dragTranslation = new TranslateTransform();
ellipsePoint.RenderTransform = dragTranslation;
ellipsePoint.ManipulationDelta +=
(s, e) =>
{
dragTranslation.X += e.Delta.Translation.X;
dragTranslation.Y += e.Delta.Translation.Y;
var manPoint = s as Path;
if (manPoint != null)
if ((bool)manPoint.Tag)
Line.StartPoint = dragTranslation.TransformPoint(point);
else
Line.EndPoint = dragTranslation.TransformPoint(point);
};
ellipsePoint.Data = geometry;`
Line is prepared like below
Line = new LineGeometry();
Line.StartPoint = _Points.First();
Line.EndPoint = _Points.Last();
How to animate a DropShadowEffect's color that has been already applied to an element with XAML without the need to re-apply a new DropShadowEffect?
I tried this:
private void test()
{
DropShadowEffect DS_Moon = (DropShadowEffect)Application.Current.Resources["DS_Moon"];
ColorAnimation DS_Moonlight = new ColorAnimation();
DS_Moonlight.From = new Color()
{
A = (byte)1,
R = (byte)0,
G = (byte)0,
B = (byte)0
};
DS_Moonlight.To = new Color()
{
A = (byte)1,
R = (byte)255,
G = (byte)255,
B = (byte)255
};
DS_Moon.BeginAnimation(SolidColorBrush.ColorProperty, (AnimationTimeline)DS_Moonlight);
}
But DS_Moon returns Null!!
I just realized that i can do this:
Moon.Effect.BeginAnimation(DropShadowEffect.ColorProperty, (AnimationTimeline)DS_Moonlight);
Here is my code to get values from XML file:
foreach (XmlNode node in DOC.SelectNodes("//CheckMarkObject"))
{
FbCheckMark checkmark = new FbCheckMark();
checkmark.Name = node.SelectSingleNode("Name").InnerText;
checkmark.Label = node.SelectSingleNode("Label").InnerText;
if (node.SelectSingleNode("IsChecked").InnerText == "0")
{
checkmark.IsChecked = false;
}
else
{
checkmark.IsChecked = true;
}
listCheckMarks.Add(checkmark);
}
Now the code to create control at runtime:
for (int i = 0; i < listCheckMarks.Count; i++)
{
if (listCheckMarks[i].checkMark.Equals(checkMark))
{
CheckBox cb = new CheckBox();
TextBlock cbtextblock = new TextBlock();
cbtextblock.Text = listCheckMarks[i].Label;
cbtextblock.Height = 27;
cbtextblock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
cbtextblock.Margin = new Thickness(12, 20, 0, 0);
cbtextblock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
cb.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
cb.VerticalAlignment = System.Windows.VerticalAlignment.Top;
cb.Margin = new Thickness(150, 21, 0, 0);
cb.Height = 50;
cb.Width = 100;
cb.Name = listCheckMarks[i].Name;
LayoutRoot.Children.Add(cbtextblock);
LayoutRoot.Children.Add(cb);
}
}
when i made change in my XML file i.e Create "CheckMark" tag two times. the result control overwrite on previous one. i want to arrange the new control under the previous one.
kindly suggest me what can i do ? use linear layout like in android?
thanks
Try to insert elements into StackPanel and set Orientation property for it.
Try that example:
StackPanel container = new StackPanel();
LayoutRoot.Children.Add(container);
for (int i = 0; i < listCheckMarks.Count; i++)
{
if (listCheckMarks[i].checkMark.Equals(checkMark))
{
StackPanel childContainer = new StackPanel();
childContainer.Orientation = Orientation.Horizontal;
CheckBox cb = new CheckBox();
TextBlock cbtextblock = new TextBlock();
cbtextblock.Text = listCheckMarks[i].Label;
cbtextblock.Height = 27;
cbtextblock.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
cbtextblock.Margin = new Thickness(12, 20, 0, 0);
cbtextblock.VerticalAlignment = System.Windows.VerticalAlignment.Top;
cb.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
cb.VerticalAlignment = System.Windows.VerticalAlignment.Top;
cb.Margin = new Thickness(150, 21, 0, 0);
cb.Height = 50;
cb.Width = 100;
cb.Name = listCheckMarks[i].Name;
childContainer.Children.Add(cbtextblock);
childContainer.Children.Add(cb);
container.Children.Add(childContainer);
}
}