Connecting ScatterViewItems with a line - wpf

I want to draw lines between ScatterViewItems but it doesn't work with what I already found here. There is a Line, but not connected to the center of the ellipses. Does anybody see my mistake? Here is what I have:
<Grid>
<s:ScatterView>
<s:ScatterViewItem Height="250" Width="500" Background="Transparent" Orientation="0" HorizontalAlignment="Right" Margin="0,70,-764,-70" d:LayoutOverrides="HorizontalAlignment, Width">
<s:ScatterView Height="250" Width="500" Background="BlueViolet">
<s:ScatterViewItem Background="Transparent" Center="100,145" Orientation="0">
<Label Content="Knoten A" Background="WhiteSmoke" Foreground="Black"/>
</s:ScatterViewItem>
<s:ScatterViewItem x:Name="StartItem" CanMove="False" CanRotate="False" Margin="0" Center="10,125" Background="Transparent">
<Ellipse Width="10" Height="10" Fill="Transparent" Stroke="Black" Margin="0,0,0,0"/>
</s:ScatterViewItem>
<s:ScatterViewItem x:Name="EndItem" CanMove="False" CanRotate="False" Margin="0" Center="490,125" Background="Transparent">
<Ellipse Width="10" Height="10" Fill="Transparent" Stroke="Black" Margin="0,0,0,0"/>
</s:ScatterViewItem>
<s:ScatterViewItem Background="Transparent">
<Canvas Name="LineHost"/>
</s:ScatterViewItem>
</s:ScatterView>
</s:ScatterViewItem>
</s:ScatterView>
</Grid>
And the c#
Line line = new Line { Stroke = Brushes.Black, StrokeThickness = 2.0 };
BindLineToScatterViewItems(line, StartItem, EndItem);
LineHost.Children.Add(line);
private void BindLineToScatterViewItems(Line line, ScatterViewItem StartItem, ScatterViewItem EndItem)
{
BindingOperations.SetBinding(line, Line.X1Property,
new Binding {Source = StartItem, Path = new PropertyPath("ActualCenter.X")});
BindingOperations.SetBinding(line, Line.Y1Property,
new Binding { Source = StartItem, Path = new PropertyPath("ActualCenter.Y") });
BindingOperations.SetBinding(line, Line.X2Property,
new Binding { Source = EndItem, Path = new PropertyPath("ActualCenter.X") });
BindingOperations.SetBinding(line, Line.Y2Property,
new Binding { Source = EndItem, Path = new PropertyPath("ActualCenter.Y") });
}

The startpoint AND endpoint from your lines is ActualCenter.X/ActualCenter.Y of your Startitem. If the ActualCenter of your Startitem is 10/100, you would draw a line from 10/100 to 10/100, which is a reason why youre not seeing any line.
Instead of setting Source = Startitem in the last two lines of your BindLineToScatterViewItems method, try setting Source = EndItem.
Hope this helps.

If I use Canvas instead of ScatterView and ScatterViewItem and the order ist like this
<s:ScatterView>
<Canvas Name="LineCanvas2" Width="500" Height="250" Background="Aquamarine">
<Canvas Background="Transparent" Name="LineCanvas"/>
<s:ScatterView Width="500" Height="250" Background="Transparent">
<s:ScatterViewItem ...
there is no problem with the positioning of the connection lines.

Related

How to set borderbrush color to each border direction on different Thickness?

i used visualbrush on borderbrush for setting different color to each border direction.
<Border Grid.Row="0" Grid.Column="4" BorderThickness="10,10,5,5" CornerRadius="0" HorizontalAlignment="Right" Height="50" Width="50" VerticalAlignment="Bottom" >
<Border.BorderBrush>
<VisualBrush>
<VisualBrush.Visual>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition Height="30"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="30"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Border Background="Blue" Grid.Row="1" Grid.Column="0"/>
<Border Background="Red" Grid.Row="1" Grid.Column="2"/>
<Border Background="Green" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"/>
<Border Background="Yellow" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3"/>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Border.BorderBrush>
</Border>
on xaml, this code did work well. each border direction color is different.
but on behind code,
Grid grid = new Grid();
grid.Height = this.rowHeight[r] + topHeight + bottomHeight;
grid.Width = this.columnWidth[c] + leftWidth + rightWidth;
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(topHeight) });
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(rowHeight[r])});
grid.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(bottomHeight) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(leftWidth) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(columnWidth[c])});
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(rightWidth) });
Border bdTop = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Top"]) };
Border bdBottom = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Bottom"]) };
Border bdLeft = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Left"]) };
Border bdRight = new Border() { Background = new SolidColorBrush(cellInfo["BorderBrush"]["Right"]) };
bdTop.Height = topHeight;
bdBottom.Height = bottomHeight;
bdLeft.Height = this.rowHeight[r];
bdRight.Height = this.rowHeight[r];
grid.Children.Add(bdTop);
grid.Children.Add(bdBottom);
grid.Children.Add(bdLeft);
grid.Children.Add(bdRight);
Grid.SetRow(bdTop, 0);
Grid.SetColumn(bdTop, 0);
Grid.SetColumnSpan(bdTop, 3);
Grid.SetRow(bdBottom, 2);
Grid.SetColumn(bdBottom, 0);
Grid.SetColumnSpan(bdBottom, 3);
Grid.SetRow(bdLeft, 1);
Grid.SetColumn(bdLeft, 0);
Grid.SetRow(bdRight, 1);
Grid.SetColumn(bdRight, 2);
VisualBrush vb = new VisualBrush();
vb.Visual = grid;
if all thickness not same, on behind code, each border direction use each visualbrush. border top showed whole visualbrush. border bottom showed whole visualbrush.
i don't know what's problem....
xaml code used in border UI. behind code used in tablecell border.
if you want want to make a border have 4 different colors you can layer them on top of each other which is a lot more simple to implement:
<Grid Height="50" Width="50">
<Border BorderBrush="Blue" BorderThickness="5,0,0,0"></Border>
<Border BorderBrush="Red" BorderThickness="0,0,5,0"></Border>
<Border BorderBrush="Yellow" BorderThickness="0,0,0,5"></Border>
<Border BorderBrush="Green" BorderThickness="0,5,0,0"></Border>
<Grid Margin="5">
<!-- Content here -->
</Grid>
</Grid>

How to get a element's position which in a UserControl

I have a UserControl:
<UserControl d:DesignHeight="100" d:DesignWidth="200" ...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Ellipse Name="leftEllipse" Grid.Column="0" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="Red" />
<Ellipse Name="rightEllipse" Grid.Column="1" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center" Fill="Green" />
</Grid>
</UserControl>
Here is my MainWindow:
<Window ...>
<Canvas Name="canvas1">
<my:MyUserControl x:Name="myUserControl1" Width="200" Height="100" Canvas.Top="100" Canvas.Left="100" />
</Canvas>
</Window>
I know how to get the position of myUserControl1 :
double x = Canvas.GetLeft(myUserControl1);
But can anyone tell me how to get the position of myUserControl1.leftEllipse?
And when myUserControl1 apply a RotateTransform, the myUserControl1.leftEllipse's position will changed, won't it?
Without making the generated leftEllipse field public, you could add a method to the UserControl that returns a transform object from the Ellipse's coordinates to that of an ancestor element, e.g.
public GeneralTransform LeftEllipseTransform(UIElement e)
{
return leftEllipse.TransformToAncestor(e);
}
You may then call it in your MainWindow like this:
var p = myUserControl1.LeftEllipseTransform(this).Transform(new Point());
Instead of TransformToAncestor (or TransformToVisual) you may also use TranslatePoint.
public Point GetLeftEllipsePosition(Point p, UIElement e)
{
return leftEllipse.TranslatePoint(p, e);
}
In MainWindow:
var p = myUserControl1.GetLeftEllipsePosition(new Point(), this);
Or for the center of the Ellipse (instead of its upper left corner):
var p = myUserControl1.GetLeftEllipsePosition(new Point(25, 25), this);

UserControl child fill Window

I have a UserControl that is a portion of a wpf window.
<Window>
<Grid>
<!--some other display elements would be here-->
<local:MyUserControl x:Name="Foo" Padding="0,42,0,50"/>
</Grid>
</Window>
Inside MyUserControl I have an element that is a gallery that is normally hidden, but when visible, it should fill the entire screen.
<UserControl>
<Grid>
<!--main display elements would be here-->
<Grid Name="Gallery" Visibility="Hidden">
<Rectangle Fill="Black" Opacity="0.75"/>
<TextBlock Name="GalleryLabel" Foreground="White" TextAlignment="Center">Current Image Title</TextBlock>
<Button Name="CloseGallery" Style="{DynamicResource WhiteTextButton}" Margin="0,0,0,0" Height="25" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Click="GalleryClose_OnClick">X</Button>
<Image Name="GalleryImage" Margin="25"/>
</Grid>
</Grid>
</UserControl>
How can I set the Gallery to fill the entire Window rather than just the UserControl?
I was able to get it to work by adding Margin="0,-42,0,-50" to Gallery, but I don't like that solution. I would rather do something that doesn't involve hard-coding values in the UserControl so that I would be able to have more flexiblility in using it.
Normally it looks like:
where the green Foo area is MyUserControl, and the rest of the things in the window are other elements.
At certain points, I have a gallery display an image, which should fill the entire screen like:
which should fill the entire screen and have a black opaque overlay, along with an image displayed on top of the overlay.
Remove the Padding...
You can use:
<local:MyUserControl x:Name="Foo" VerticalAlignment="Stretch" HorizontalAligment="Stretch"/>
EDIT
I may admit that I still am not sure what you want. But I made something which does the same as you showed in the pictures. But be aware that this as an opinion based question, and the answer is my opinion, there are a lot of ways to achieve this. And this is only one of them:
MainWindow
<Window x:Class="MyProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myProject="clr-namespace:MyProject"
Title="MainWindow" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Background="Gainsboro" Grid.Row="0">
<StackPanel Orientation="Horizontal">
<Button Content="Show gallery" Width="100" Margin="10"/>
<Button Content="Do something else" Width="150" Margin="10"/>
</StackPanel>
</Border>
<myProject:SomeOtherStuff Grid.Row="1" />
<Border Grid.Row="2" Background="Gainsboro">
<StackPanel Orientation="Horizontal">
<Label Content="Buttom area, can be used for something else"/>
</StackPanel>
</Border>
<myProject:GalleryUserControl x:Name="GalleryUserControl" Grid.Row="0" Grid.RowSpan="3" Visibility="Hidden"/>
</Grid>
SomeOtherStuff UserControl
<UserControl x:Class="MyProject.SomeOtherStuff"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid Background="Green">
<Label VerticalAlignment="Center" HorizontalAlignment="Center" Content="Foo" FontSize="30" FontFamily="Verdana"/>
</Grid>
Gallery UserControl
<UserControl x:Class="XamDataGrid.GalleryUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="500" Width="800">
<Grid Background="#99000000">
<TextBlock Text="Currect image title" Foreground="White" TextAlignment="Center" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<Button Name="CloseGallery" Margin="0,0,0,0" Content="X" Height="25" VerticalAlignment="Top" HorizontalAlignment="Right" Width="25" Click="GalleryClose_OnClick"/>
<Image Margin="30"/>
</Grid>
An Adorner will be best for you. As it floats above everything else and remains outside the VisualTree too.
UserControl2
<UserControl2 ...>
<Grid>
<Grid Background="#FF709FA6" Opacity="0.3" Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}">
</Grid>
<Grid Width="600" Height="700">
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF37DAEA" Offset="0"/>
<GradientStop Color="#FFE84242" Offset="1"/>
</LinearGradientBrush>
</Grid.Background>
<!-- Gallery controls -->
<Button Content="Welcome to Gallery" HorizontalAlignment="Left" IsHitTestVisible="True" Margin="112,126,0,0" VerticalAlignment="Top" Height="68" FontSize="48" Click="Button_Click_1"/>
<TextBlock HorizontalAlignment="Left" Margin="83,42,0,0" TextWrapping="Wrap" Text="UserControl2" VerticalAlignment="Top" Foreground="#FF1B0D0D"/>
</Grid>
</Grid>
</UserControl2>
UserControl1
Code :
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// get root Window
DependencyObject current = LogicalTreeHelper.GetParent(this);
while (!(current is Window))
current = LogicalTreeHelper.GetParent(current);
Window root = current as Window;
IEnumerable children = LogicalTreeHelper.GetChildren(root);
Panel p = null;
foreach (var child in children)
{
p = child as Panel; // get first container panel in Window
break;
}
// Create UserControl2 to add to the adorner
UserControl2 ctrlGallery = new UserControl2();
AdornerLayer layer = AdornerLayer.GetAdornerLayer(p);
GalleryAdorner adorner = new GalleryAdorner(p, ctrlGallery);
layer.Add(adorner);
}
}
public class GalleryAdorner : Adorner
{
private Control _child;
VisualCollection collection;
public GalleryAdorner(UIElement elem, Control child)
: base(elem)
{
collection = new VisualCollection(this);
_child = child;
collection.Add(_child);
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Visual GetVisualChild(int index)
{
if (index != 0) throw new ArgumentOutOfRangeException();
return collection[0];
}
protected override Size MeasureOverride(Size constraint)
{
_child.Measure(constraint);
return _child.DesiredSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
_child.Arrange(new Rect(new Point(0, 0), finalSize));
return new Size(_child.ActualWidth, _child.ActualHeight);
}
}

Animate control with respecting parents/container

I have a control that I move with help of animation from the bottom to the final position. My problem is now that I want to change the behaviour of the animation, so that it respects the outer container (DarkGray).
The orange Ractangle should only be visible on the white background and not on the darkgray Grid!
Code:
MainWindow.xaml:
<Grid Background="DarkGray">
<Grid Margin="50"
Background="White">
<Rectangle x:Name="objectToMove"
VerticalAlignment="Bottom"
Fill="Orange"
Height="50"
Width="50"/>
<Button Height="20"
Width="40"
Margin="20"
Content="Move"
Click="Button_Click"
VerticalAlignment="Top"/>
</Grid>
</Grid>
MainWindow.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
var target = objectToMove;
var heightOfControl = target.ActualHeight;
var trans = new TranslateTransform();
target.RenderTransform = trans;
var myAnimation = new DoubleAnimation(heightOfControl, 0, TimeSpan.FromMilliseconds(600));
trans.BeginAnimation(TranslateTransform.YProperty, myAnimation);
}
Current:
Desired solution:
Use ClipToBounds Property for this.
<Grid Margin="50"
Background="White"
ClipToBounds="True">

Silverlight - What does my datacontext/binding path need to be here?

I've been working a bit with an image editor in Silverlight for the past week or so. It's my first encounter with it and I still haven't fully gotten my head around data bindings and datacontext or mvvm. I have a rotation method and I want to be able to pass the angle value from a text box on my MainPage.xaml to the method.I have an initial value set of 90 and my function rotates the image 90 degrees when I click it. The textbox is empty at runtime and also is clearly not updating my rotation angle.
MainPage.xaml
<Grid DataContext="{Binding Path=Project}" Height="70" Name="grid1" Width="200">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="84*" />
<ColumnDefinition Width="57*" />
<ColumnDefinition Width="59*" />
</Grid.ColumnDefinitions>
<Button Command="{Binding Path=RotateCWElementCommand}"
Height="30" Name="btnRotCW" Width="30" Grid.Column="2" Margin="15,0,14,5" Grid.Row="1">
<Image Source="../Assets/Images/Icons/object-rotate-right.png" Grid.Column="1"
Grid.Row="4" Height="20" HorizontalAlignment="Left" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="20" />
</Button>
<TextBlock FontWeight="Bold" HorizontalAlignment="Left" Margin="10,10,0,8" Text="Rotate" VerticalAlignment="Center" />
<TextBlock FontWeight="Bold" HorizontalAlignment="Left" Margin="34,9,0,10" Text="Angle:" VerticalAlignment="Center" Grid.Row="1" />
<TextBox Text="{Binding Path=RotateElement.Angle, Mode=TwoWay}" Height="24" Name="textBox1" Width="52" Grid.Column="1" Margin="0,6,5,5" Grid.Row="1" />
</Grid>
(Relevant code from)
Project.cs-
namespace ImageEditor.Client.BLL
{
public class Project : INotifyPropertyChanged
{
#region Properties
private RotateTransform rotateElement;
public RotateTransform RotateElement
{
get { return rotateElement; }
set
{
rotateElement = value;
NotifyPropertyChanged("RotateElement");
}
}
#endregion
#region Methods
private void RotateCWElement(object param)
{
FrameworkElement element = this.SelectedElement;
RotateTransform RotateElement = new RotateTransform();
RotateElement.Angle = 90;
RotateElement.CenterX = element.ActualWidth * 0.5;
RotateElement.CenterY = element.ActualHeight * 0.5;
element.RenderTransform = RotateElement;
}
What am I doing wrong here? Is it my datacontext or my binding path that is the problem? What should they be? Formatting is a little off sorry
the UI does not know that a property in your object has changed, since you only notify when your object changes, but not the properties in it:
private void RotateCWElement(object param)
{
FrameworkElement element = this.SelectedElement;
if (this.RotateElement == null) this.RotateElement = new RotateTransform();
RotateElement.Angle = 90;
RotateElement.CenterX = element.ActualWidth * 0.5;
RotateElement.CenterY = element.ActualHeight * 0.5;
element.RenderTransform = RotateElement;
//tell the UI that this property has changed
NotifyPropertyChanged("RotateElement");
}

Categories

Resources