WPF - change text anchor in Canvas - c#

Here's some XAML:
<Grid Width="200" Height="200">
<Canvas Background="Beige">
<Line X1="0" X2="200" Y1="100" Y2="100" Stroke="Black"/>
<Line X1="100" X2="100" Y1="0" Y2="200" Stroke="Black"/>
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Margin="2">
<TextBlock.RenderTransform>
<TranslateTransform X="100" Y="100"/>
</TextBlock.RenderTransform>
hello world1
<LineBreak/>
hello world2
<LineBreak/>
hello world3
</TextBlock>
</Canvas>
</Grid>
I want the text to appear in the top-right quadrant of my Canvas instead of the bottom right quadrant.
Is it possible to do in WPF?
Currently the text is drawn from topleft to bottomright, I would like it do be drawn from bottomleft to topright.
I couldn't find an answer on the internet that works inside a Canvas.
In my production code the text should be able to be of any length and height.
Edit:
I've been asked to provide a fully working sample, so here goes:
XAML:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<!--The drawing area can be anything, a grid, a panel, a canvas... Can't just use specific alignment tools so I have to use a Transform-->
<Grid x:Name="DrawingArea" Background="Beige" MouseMove="UIElement_OnMouseMove">
<TextBlock x:Name="TextBlock" Margin="2">
hello world1
<LineBreak/>
hello world2
<LineBreak/>
hello world3
</TextBlock>
</Grid>
</Grid>
</Window>
Code behind:
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApp1
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseMove(object sender, MouseEventArgs e)
{
var mousePos = e.GetPosition(DrawingArea);
TextBlock.RenderTransform = new TranslateTransform(mousePos.X, mousePos.Y);
}
}
}
Currently the text appears below the default Windows mouse cursor, I'd like it to appear above the default Windows mouse cursor.

You see it in the lower right part because of the TranslateTransform. You set it to X=100, Y=100. If you set Y=0 it should be on the top.
But you should consider some things with this code:
Why use TranslateTransform inside a canvas? You can just add the Canvas.Top and Canvas.Left properties to the TextBlock and that should do it. Use the TranslateTransform only if you're looking to animate the element, and even then, it's more convenient to set it to (0, 0), and change it only during the animation.
Why are you using the canvas at all? And more over why inside a Grid? You should be able to achieve what you want by using a single Grid, or even a DockPanel. A Canvas is used only for graphics, that should always remain in the same place. There are better solutions for data, especially if it's supposed to change during runtime.
If you want a cross in the background of your grid, you can try something like this:
<Grid
Width="200"
Height="200"
Background="Beige">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Line
X1="0"
X2="200"
Y1="100"
Y2="100"
Stroke="Black"
Grid.RowSpan="2"
Grid.ColumnSpan="2"/>
<Line
X1="100"
X2="100"
Y1="0"
Y2="200"
Stroke="Black"
Grid.RowSpan="2"
Grid.ColumnSpan="2"/>
<TextBlock
VerticalAlignment="Center"
HorizontalAlignment="Center" Margin="2"
Grid.Row="0"
Grid.Column="1">
hello world1
<LineBreak/>
hello world2
<LineBreak/>
hello world3
</TextBlock>
</Grid>

Add a grid to your canvas and set the properties
HorizontalAlignment="Right"
VerticalAlignment="Top"
<Canvas x:Name="newCanvas">
<Grid>
<Label Content="Hello World!"
HorizontalAlignment="Right"
VerticalAlignment="Top"
/>
</Grid>

Related

How do I use Light on a Control in WPF?

I have a custom user control, and I'd like to add some light effects to the custom control. I was trying to go for a light to "sweep" the control when the mouse enters the control. But I'm slightly lost as to how to use WPF lights. I can use them on custom geometry I define, but I can't seem to get them to work on standard controls.
This is my xaml code for the custom control:
<UserControl x:Name="CActionTile" x:Class="App.ActionTile"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:App" Background="{DynamicResource ActionTileBackgroundBrush}"
BorderThickness="0,0,0,0.5" BorderBrush="DarkSlateGray"
mc:Ignorable="d" Height="80" d:DesignWidth="388">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" Margin="10,0,0,0" VerticalAlignment="Center">
<Run FontFamily="Segoe UI" FontWeight="Thin" FontSize="28"
Foreground="{DynamicResource ActionLabelBrush}" Text="{Binding Label, ElementName=CActionTile}" />
<LineBreak/>
<Run FontFamily="Segoe UI" FontWeight="Normal" FontSize="12"
Foreground="{DynamicResource ActionSubLabelBrush}" Text="{Binding SubLabel, ElementName=CActionTile}" />
</TextBlock>
<!-- This is where I'm kinda stuck... not sure what to do from here... -->
<Viewport3D x:Name="vp1">
<Viewport3D.Camera>
<PerspectiveCamera LookDirection="0,0,-1" Position="0,0,5" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<AmbientLight Color="White" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</Grid>
</UserControl>
Basically I'm trying to get this UWP Composition effect (https://github.com/microsoft/WindowsCompositionSamples/tree/master/SampleGallery/Samples/SDK%2014393/TextShimmer) to work in my WPF application. I'm pretty sure I can figure out the sweep effect when the pointer enters the control, but I need some help getting light effects to show on the controls themselves.

Margin for Two Boxes Isn't Correct

so I have two boxes, and the goal here is to have both boxes have the exact same margins from the edge of the window. Unfortunately, in WPF, you only get the margin from the left side, and not both, so to make sure of that, I have the following formula;
The margin of the second box is equal to the window width minus the margin of the first box minus the size of the box.
And this can be backed up with math, it does work. And so I did get my program to figure this out, since it's reactive. And so now I have this image:
WPF Window
The text in the middle is to prove that this calculation is correct. (just so you know, each box is 500px wide) So, the first number is the margin of the first box. The second is the margin of the second, and the last is the window size. Do the math and you have this equation:
(1936 - 88) - 500 = 1348
And that does work, however, if you look in the image, the box on the right is just a little bit closer to the edge than the one on the left. This happens too if you resize it, it's not just when maximized. What's up, and how can I fix this?
Here is my XAML code:
<Window x:Class="Horizon_Chat.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Horizon_Chat"
xmlns:i="clr-namespace:Horizon_Chat"
i:WindowEx.ShowIcon = "false"
mc:Ignorable="d"
Title="Horizon Chat" Height="900" Width="1280" WindowStartupLocation="CenterScreen" MinWidth="600" MinHeight="600" WindowState="Maximized">
<Grid>
<TextBlock x:Name="welcomeTitleText" HorizontalAlignment="Center" Margin="0,-200,0,0" TextWrapping="Wrap" Text="Hello Camden!" VerticalAlignment="Center" FontFamily="Muli" FontSize="60"/>
<Border x:Name="topBorder" BorderBrush="#FF646464" BorderThickness="0,0,0,4" HorizontalAlignment="Left" Height="41" VerticalAlignment="Top" Width="1273" Margin="0,32,0,0"/>
<Ellipse Fill="#FF30B44E" HorizontalAlignment="Left" Height="50" Margin="10,10,0,0" Stroke="Black" VerticalAlignment="Top" Width="50" StrokeThickness="3"/>
<Border x:Name="chatsBox" BorderBrush="Black" BorderThickness="3" HorizontalAlignment="Left" Height="250" Margin="58,594,0,0" VerticalAlignment="Top" Width="500"/>
<Border x:Name="friendsBox" BorderBrush="Black" BorderThickness="3" HorizontalAlignment="Left" Height="250" Margin="724,594,0,0" VerticalAlignment="Top" Width="500"/>
</Grid>
</Window>
What you're looking for is a grid, set the ColumnDefinition Widths to your rectangle width + the margin you want. The * used for the middle Column's Width means "Fill up the available space". The Margin parameter is set up as (Left, Top, Right, Bottom). This allows you to specify a right hand Margin.
<Window x:Class="ForStackoverflow.MainWindow"
...
xmlns:local="clr-namespace:ForStackoverflow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Rectangle Margin="15 0 0 0"
StrokeThickness="5"
Stroke="Black"
Height="80"
Grid.Column="0"/>
<Rectangle Margin="0 0 15 0"
StrokeThickness="5"
Stroke="Black"
Height="80"
Grid.Column="2"/>
</Grid>
</Window>

wpf resize of a usercontrol through thumb is not proportional to dragging

I'm trying to resize a custom usercontrol through a thumb positioned inside the usercontrol itself.
This is the usercontrol:
<UserControl x:Class="ER.Entity"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ER"
mc:Ignorable="d"
Name="entityRoot">
<Grid Name="entityGrid">
<Thumb x:Name="resizeThumb" Height="10" Width="10" Margin="200,90,-15,-10" DragDelta="Resize" />
<Border Opacity="100" BorderThickness="5" BorderBrush="Black">
<TextBlock x:Name="textBox1" TextWrapping="Wrap" Text="{Binding ElementName=entityRoot, Path=EntityName}" VerticalAlignment="Top" PreviewMouseDown="EntityPreviewMouseDownHandler" PreviewMouseMove="EntityPreviewMouseMoveHandler" PreviewMouseUp="EntityPreviewMouseUpHandler" />
</Border>
</Grid>
And this is the method triggered by the DragDelta event:
private void Resize(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
entityGrid.SetValue(WidthProperty, entityGrid.ActualWidth + e.HorizontalChange);
entityGrid.SetValue(HeightProperty, entityGrid.ActualHeight + e.VerticalChange);
}
The problem is that, when i drag the thumb, the resizing of the usercontrol is much bigger than the mouse movement.
The problem is that because your Thumb object is referenced to the left and top of the Grid, when you change the size of the Grid that in turn causes an effective relative movement of the Thumb in addition to the movement caused by the mouse.
Changing the Thumb alignment to be Right and Bottom, and moving the Thumb positioning from the Thumb.Margin to the Grid's Width and Height properties allows the Thumb to resize the Grid as intended:
<Grid Name="entityGrid" Width="200" Height="90">
<Thumb x:Name="resizeThumb" Height="10" Width="10"
HorizontalAlignment="Right" VerticalAlignment="Bottom"
Margin="0,0,-15,-10" DragDelta="Resize" />
<Border Opacity="100" BorderThickness="2" BorderBrush="Black">
<TextBlock x:Name="textBox1" TextWrapping="Wrap"
Text="{Binding ElementName=entityRoot, Path=EntityName}"
VerticalAlignment="Top"
PreviewMouseDown="EntityPreviewMouseDownHandler"
PreviewMouseMove="EntityPreviewMouseMoveHandler"
PreviewMouseUp="EntityPreviewMouseUpHandler" />
</Border>
</Grid>

Get Fill Color of Rectangle in Coded UI for Windows Phone

I'm writing some Coded UI tests for a simple application and cannot seem to get the code to find Rectangle objects. In the specific case I have the color of the rectangle presents whether two strings match or not based on the fill color.
When trying to find the rectangle using the Coded UI Test Builder the parent object is being found instead of the rectangle. I am also seeing that the code returns that it is unable to find the rectangle when I have it search manually.
Below is the XAML for the page I am trying to test against:
<Page
x:Class="TestApp.ButtonTester"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid x:Name="LayoutRoot">
<Grid.ChildrenTransitions>
<TransitionCollection>
<EntranceThemeTransition/>
</TransitionCollection>
</Grid.ChildrenTransitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Title Panel -->
<StackPanel Grid.Row="0" Margin="19,0,0,0">
<TextBlock Text="{StaticResource AppName}" Style="{ThemeResource TitleTextBlockStyle}" Margin="0,12,0,0"/>
<TextBlock Name="pageTitle" Text="Button Tester" Margin="0,-6.5,0,26.5" Style="{ThemeResource HeaderTextBlockStyle}" CharacterSpacing="{ThemeResource PivotHeaderItemCharacterSpacing}"/>
</StackPanel>
<!--TODO: Content should be placed within the following grid-->
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">
<StackPanel Name="buttonValidator">
<TextBlock Name="verifyText" Text="Hi" HorizontalAlignment="Center" Style="{StaticResource LargeText}"/>
<Button Name="changeText" Content="Change Text" HorizontalAlignment="Center" Click="changeText_Click"/>
<TextBox Name="guessText" Text="Enter Text From Above" TextAlignment="Center" GotFocus="guessText_GotFocus" KeyDown="guessText_KeyDown"/>
<Button Name="verifyMatch" Content="Verify" HorizontalAlignment="Center" Click="verifyMatch_Click"/>
<Rectangle Name="matchAlert" Height="50" Width="50" Fill="Black" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</Grid>
And here is the test code I currently have:
[TestMethod]
public void TestVerifyIncorrect()
{
UITestControl verifyMatch = new UITestControl(myApp);
verifyMatch.TechnologyName = "UIA";
verifyMatch.SearchProperties.Add("ControlType", "Button");
verifyMatch.SearchProperties.Add("AutomationId", "verifyMatch");
Gesture.Tap(verifyMatch);
UITestControl matchAlert = new UITestControl(myApp);
matchAlert.TechnologyName = "UIA";
matchAlert.SearchProperties.Add("ControlType", "Rectangle");
matchAlert.SearchProperties.Add("AutomationId", "matchAlert");
var fillColor = matchAlert.GetProperty("Fill");
}
I am also seeing the Test Builder unable to detect a rectangle even when it is being used as a control.
I also looked into the Rectangle class vs the Button class and it appears the first common link in their inheritance chains is with Windows.UI.Xaml.FrameworkElement. I'm unaware of what type of ojects the Coded UI is able to detect to know if that may be the cause of the issue.

How to create a background that each row has a border even when there is no data?

Please take a look at image above.
I want my xaml page background to be as such. Each and every row should always have border. I've already achieved the objective using itemControl and dump a dummy list. Although I get what I want, but it looks redundant so I'm trying to see if there is better way of doing it. Please don't suggest me to create an image that looks as such and use it as background.
Below is what I did:
<ItemControl DataContext="{Binding [someViewmodel]}" BorderThickness="0,0,1,0" BorderBrush="#E6E6E6"
ItemSource="{Binding DummyList}">
<ItemsControl.ItemTempalte>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="#E6E6E6" Background="White">
<StackPanel Height="50">
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemControl>
In my viewmodel:
for(int i=0;i<10;i++)
{
Object haha = new Object();
this.DummyList.add(haha);
}
EDIT again:
If it is just a background you could add lines based on height of the screen, and add a line for every x pixels in the codebehind. If you want something on the lines use the datatemplate of items control of your choice like you did. And, of course create your own control for that so you don't mangle the codebehind of a page :)
If you can live with using an image use a vector image so the lines are nice and crisp and background transparent. Either crop the image to the screen size, crop the overflow, or place the image in a ViewBox and let it stretch to the size of the screen. There are many options, it really depends on what you and need.
EDIT:
Anoyher way is to draw the lines manually (if you use the grid). Abstract this to your own control
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Line Grid.Row="1" X1="0" Y1="0" X2="1" Y2="0" Stroke="DarkSlateBlue" StrokeThickness="3" Stretch="Uniform" VerticalAlignment="Top"/>
<Line Grid.Row="2" X1="0" Y1="0" X2="1" Y2="0" Stroke="DarkSlateBlue" StrokeThickness="3" Stretch="Uniform" VerticalAlignment="Top"/>
<Line Grid.Row="3" X1="0" Y1="0" X2="1" Y2="0" Stroke="DarkSlateBlue" StrokeThickness="3" Stretch="Uniform" VerticalAlignment="Top"/>
</Grid>
I assume you want to use a grid since you said rows? Here is how you do it with the grid, simple set ShowGridLines to true. (notice dashed lines)
Code
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
Image:
All you need to do is to not draw all four sides of your Border. You can do that by adjusting the Border.BorderThickness property. Try this instead:
<ItemControl DataContext="{Binding [someViewmodel]}" BorderThickness="0,0,1,0"
BorderBrush="#E6E6E6"
ItemSource="{Binding DummyList}">
<ItemsControl.ItemTempalte>
<DataTemplate>
<Border BorderThickness="0,0,0,1" BorderBrush="#E6E6E6" Background="White">
<StackPanel Height="50">
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemControl>
If you want the lines to extend further, then just add some empty items to your data bound collection.
If I have misunderstood your problem (quite possible as your question is not clear), then please let me know in detail... it looks redundant so I'm trying to see if there is better way of doing it is not very descriptive an will not help anyone to understand your problem.

Categories

Resources