I am working on a C#/XAML Universal Windows store app and I need to plot a custom control on a Bing map control. The problem is I cannot find any method to modify the anchor point which is by default Point(0,0) which anchor the control to upper left corner. I need something equivalent to MapControl.SetNormalizedAnchorPoint in Windows Phone. I believe it is possible since the Bing Maps app controls has an anchor point at the bottom left corner. How is it done?
Edit:
Here's what my custom control looks like. What I want is for it to anchor to the location at the bottom left corner (blue circle) instead of the default top left (red circle).
Here what it looks like on the map control where it achors to the red circle instead of blue.
And here's my code behind
public void AddPushpin(BasicGeoposition location, string title, string subtitle = "")
{
var pin = new PinControl(title, subtitle);
pin.ApplyTemplate();
pin.UpdateLayout();
MapLayer.SetPosition(pin, location.ToLocation());
_pinLayer.Children.Add(pin);
}
Here's the lengthy XAML
<UserControl x:Class="ToulouseUniversal.CustomControls.PinControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ToulouseUniversal.CustomControls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="100"
d:DesignWidth="200">
<Grid>
<Grid x:Name="LayoutRoot"
VerticalAlignment="Bottom">
<Polygon x:Name="labelPointer"
Points="0,0 0,0.5 15,15.5 15,0"
Margin="-15,0,0,0"
Grid.ColumnSpan="2"
Fill="{StaticResource TisseoBrush1}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom" />
<Polygon Points="0,0 0,0.5 15,15.5 15,0"
Margin="-15,0,0,0"
Grid.ColumnSpan="2"
Fill="Black"
Opacity="0.3"
HorizontalAlignment="Left"
VerticalAlignment="Bottom" />
<Grid Margin="-15,0,0,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Rectangle Height="4"
VerticalAlignment="Bottom"
Margin="14.5,-1,0.5,-3.5"
Grid.ColumnSpan="2">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Black"
Offset="0" />
<GradientStop Offset="1" />
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle x:Name="labelGrid"
Fill="{StaticResource TisseoBrush1}"
RadiusX="0"
RadiusY="0"
Grid.ColumnSpan="2"/>
<Rectangle Fill="White"
Opacity="0.2"
Width="3"
HorizontalAlignment="Left" />
<Rectangle Fill="White"
Grid.ColumnSpan="2"
Opacity="0.2"
Width="3"
HorizontalAlignment="Right" />
<Grid>
<BitmapIcon UriSource="ms-appx:///Assets/Icons/appbar.transit.bus.png"
Width="40" />
</Grid>
<StackPanel Grid.Column="1">
<TextBlock x:Name="labelTitle"
Text="A stop"
Margin="6,3,9,0"
Foreground="White"
TextWrapping="Wrap"
MaxWidth="180"
FontSize="20"
FontWeight="SemiBold" />
<TextBlock x:Name="labelSubtitle"
Text="connecting"
Margin="6,0,9,6"
Foreground="White"
TextWrapping="Wrap"
FontSize="12"
MaxWidth="180"
FontWeight="Light" />
</StackPanel>
</Grid>
</Grid>
</Grid>
Depending on what you're trying to achieve, it might be interesting to share more of your XAML code or at least the part of the code were you're creating the pushpin object as well as the associated option.
Anyway, in order to control the anchor, it might be interesting to be able to use custom control as a pushpin so basically, if you're using a Grid as the root control representing the pushpin, you can work to display multiple things and also work with the margin on children controls to move them in the Grid.
If you look at the article here, you will see how it can be done:
http://blogs.msdn.com/b/bingdevcenter/archive/2014/06/24/using-maps-in-universal-apps.aspx
See the interesting part of the code is:
public void AddPushpin(BasicGeoposition location, string text)
{
#if WINDOWS_APP
var pin = new Pushpin()
{
Text = text
};
MapLayer.SetPosition(pin, location.ToLocation());
_pinLayer.Children.Add(pin);
#elif WINDOWS_PHONE_APP
var pin = new Grid()
{
Width = 24,
Height = 24,
Margin = new Windows.UI.Xaml.Thickness(-12)
};
pin.Children.Add(new Ellipse()
{
Fill = new SolidColorBrush(Colors.DodgerBlue),
Stroke = new SolidColorBrush(Colors.White),
StrokeThickness = 3,
Width = 24,
Height = 24
});
pin.Children.Add(new TextBlock()
{
Text = text,
FontSize = 12,
Foreground = new SolidColorBrush(Colors.White),
HorizontalAlignment = Windows.UI.Xaml.HorizontalAlignment.Center,
VerticalAlignment = Windows.UI.Xaml.VerticalAlignment.Center
});
MapControl.SetLocation(pin, new Geopoint(location));
_map.Children.Add(pin);
#endif
}
Here is a nice blog post solving your problem to simulate the anchor-point in custom control for Bing Maps.
The most interesting part:
In the XAML Bing Maps controls the easiest way to offset a pushpin or custom
UIElement that is being overlaid on the map like a pushpin is to specify
a negative margin value on the pushpin or UIElement
In your case it would be sufficient to apply the negative margin on the LayoutRoot Grid.
Related
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>
I used WindowsFormsHost control to view pdf document in same window where I had grid control.Now grid is not visible when windowsformshost is visible.I need to display both control at the same time.
Please can anyone help me to display both control together.
this is my code
ViewDocument doc = new ViewDocument("Hide", "R1B", "", "Chapters", "");
doc.windowsFormsHost1.Visibility = Visibility.Visible;
var uc = new Pdfdocument(quespath);
doc.windowsFormsHost1.Child = uc;
doc.Show();
if (fmtyp == "Hide")
{
transgrid.Visibility = Visibility.Visible;
}
XAML Code -
<Canvas Grid.ColumnSpan="9" Grid.RowSpan="6" Margin="3,0,0,1" Name="canvas1" Grid.Column="5" Grid.Row="6">
<WindowsFormsHost Name="windowsFormsHost1" Visibility="Hidden" Canvas.Left="6" Canvas.Top="0" Height="557" Width="881" />
<Grid Name="transgrid" Canvas.Left="6" Canvas.Top="0" Height="557" Width="875">
<Grid.Background>
<ImageBrush ImageSource="/RaptorHscIIBlueprint;component/Images/1409934598_Help.png" />
</Grid.Background>
</Grid>
</Canvas>
Your controls reside on top of Each other -- try this --
<StackPanel Grid.ColumnSpan="9" Grid.RowSpan="6" Margin="3,0,0,1" Name="stackPanel1" Grid.Column="5" Grid.Row="6">
<WindowsFormsHost Name="windowsFormsHost1" Visibility="Hidden" Height="557" Width="881" />
<Grid Name="transgrid" Height="557" Width="875">
<Grid.Background>
<ImageBrush ImageSource="/RaptorHscIIBlueprint;component/Images/1409934598_Help.png" />
</Grid.Background>
</Grid>
I have a custom control ButtonRow which will end up going into a different control.
It is very simple, it has one Border, on label and one button.
I need to make it so that the border will extend its width to fill up to where the button is.
This is not happening as you can see in the below image:
The XAML can be found below. I have tried fiddling about with the horizontal alignment of both he label and the border, but they will only ever re-size to fit the text content of the label.
I know there are existing question with very similar problems and names, but none have needed to do quite the same thing or have helped me solve my problem.
I have tried using a StackPanel in horizontal alignment but all it did was make the button go next to the border.
How can I make the border expand to fill the available space?
<Grid>
<DockPanel Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="dockPanel1" VerticalAlignment="Top" Width="Auto">
<Border BorderBrush="#FFDADFE1" Background="#FFECF0F1" BorderThickness="1" Height="20" Name="bdrFilter" HorizontalAlignment="Stretch">
<Label Content="Filter..." FontStyle="Italic" Foreground="#FF6C7A89" Height="20" Name="lblFilter" Padding="5,0" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" />
</Border>
<Button Style="{StaticResource FlatButtonStyle}" Content="+" Height="20" HorizontalAlignment="Right" Name="btnAddFilter" VerticalAlignment="Top" Width="20" Foreground="#FF6C7A89" ForceCursor="True" BorderBrush="{x:Null}" />
</DockPanel>
</Grid>
(The button style does not affect its alignment or any other relevant properties)
A DockPanel is not the correct Panel to use for this requirement... like a StackPanel, it does not resize its contents. Instead, just use a regular Grid (which also uses less resources than a DockPanel):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border BorderBrush="#FFDADFE1" Background="#FFECF0F1" BorderThickness="1"
Height="20" Name="bdrFilter" VerticalAlignment="Top">
<Label Content="Filter..." FontStyle="Italic" Foreground="#FF6C7A89"
Height="20" Name="lblFilter" Padding="5,0" />
</Border>
<Button Grid.Column="1" Content="+" Height="20" HorizontalAlignment="Right"
Name="btnAddFilter" VerticalAlignment="Top" Width="20" Foreground="#FF6C7A89"
ForceCursor="True" BorderBrush="{x:Null}" />
</Grid>
Please see the Panels Overview page on MSDN for more information about the different Panels in WPF.
This might help you out. Setting LastChildFill=True inside a DockPanel does exactly what the name suggests.
I have an image inside a border and I would like to show different parts of the image source in the image box at different times. Specifically, when a certain textbox gets focus, I want to change the image so it zooms to a certain portion of the image content.
Here's the XAML:
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="5" Height="504"
HorizontalAlignment="Left" Margin="20,116,0,0" Name="border1"
VerticalAlignment="Top" Width="410" ClipToBounds="True">
<Image Height="493" Name="image5" Stretch="Fill" Width="390"
ClipToBounds="True" BindingGroup="{Binding}"
Clip="{Binding ElementName=border1}"
Cursor="Hand" StretchDirection="Both" />
</Border>
For an example, my image source is 2550 x 3320 pixels. I would like the image box to show the source in a rectangle starting at point 1755,300 with width of 650 and height of 230. I do not want to use CloneBitmap to cut that rectangle out and display it because I also have a manual zoom set up for this image where the user can use the mouse wheel to zoom in and out and click & drag to pan the image. I still want to allow that after we zoom to desired area.
UPDATE:
I've tried implementing colinsmith's answer, but whenever I change the scrollviewer's offsets, It chops the image, so if I later move (click and drag to pan) it, it's empty space. I've had this working before with just the image inside the scrollviewer, but now I have an image inside a scrollviewer inside a border. The border is necessary for my zoom and pan as I have it set up now.
My updated XAML:
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="5" Height="504"
HorizontalAlignment="Left" Margin="20,116,0,0" Name="border1"
VerticalAlignment="Top" Width="410" ClipToBounds="True">
<ScrollViewer x:Name="image5scroll" VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Hidden">
<Image Height="493" Name="image5" Stretch="Fill" Width="390"
ClipToBounds="True" BindingGroup="{Binding}"
Clip="{Binding ElementName=image5scroll}" Cursor="Hand"
StretchDirection="Both" />
</ScrollViewer>
</Border>
And code behind:
public void imageZoom(Element element, int index)
{
if (element.Rectangle.Left - 100 > 0)
{
image5scroll.ScrollToHorizontalOffset(element.Rectangle.Left - 100);
image5scroll.Width = element.Rectangle.Width + 200;
image5scroll.Height = element.Rectangle.Height + 200;
border1.Width = image5scroll.Width;
border1.Height = image5scroll.Height;
image5.Width = image5scroll.Width;
image5.Height = image5scroll.Height;
image5.Stretch = System.Windows.Media.Stretch.None;
}
else
{
image5scroll.ScrollToHorizontalOffset(0);
}
if (element.Rectangle.Top - 100 > 0)
{
image5scroll.ScrollToVerticalOffset(element.Rectangle.Top - 100);
}
else
{
image5scroll.ScrollToVerticalOffset(0);
}
}
You can use a ScrollViewer to wrap your Image...then you can tell the ScrollViewer to go to a vertical and horizontal offset by calling the ScrollToVerticalOffset() and ScrollToHorizontalOffset() methods (as there isn't a property which you can set).
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Border BorderBrush="Silver" BorderThickness="1" Grid.Column="5" Height="504"
HorizontalAlignment="Left" Margin="20,116,0,0" Name="border1" VerticalAlignment="Top" Width="410">
<ScrollViewer x:Name="image5scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
<Image Height="493" Name="image5" Stretch="None" Width="390" BindingGroup="{Binding}"
Cursor="Hand" Source="http://www.noaanews.noaa.gov/stories/images/goes-12-firstimage-large081701.jpg"/>
</ScrollViewer>
</Border>
</Grid>
</Page>
However, if you must be be able to set the position of the ScrollViewer using properties instead of code-behind then a solution is to define an Attached Property which does the calls to ScrollToVerticalOffset/ScrollToHorizontalOffset for you underneath.
http://marlongrech.wordpress.com/2009/09/14/how-to-set-wpf-scrollviewer-verticaloffset-and-horizontal-offset/
I have an image inside scroll viewer and i have a control for zooming the image and in zooming event i change the scale of an image ,as below :
void zoomSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
scale.ScaleX = e.NewValue;
scale.ScaleY = e.NewValue;
//scroll is a name of scrolviewer
scroll.UpdateLayout();
}
And a xaml below
<Grid x:Name="Preview" Grid.Column="1">
<Border x:Name="OuterBorder" BorderThickness="1" BorderBrush="#A3A3A3" >
<Border x:Name="InnerBorder" BorderBrush="Transparent" Margin="2" >
<Grid Background="White" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="scroll" HorizontalScrollBarVisibility="Auto" Grid.Column="0" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Themes:ThemeManager.StyleKey="TreeScrollViewer">
<Image Source="../charge_chargeline.PNG" >
<Image.RenderTransform>
<CompositeTransform x:Name="**scale**" />
</Image.RenderTransform>
</Image>
</ScrollViewer>
<Border HorizontalAlignment="Center" CornerRadius="0,0,2,2" Width="250" Height="24" VerticalAlignment="Top">
<Border.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#CDD1D4" Offset="0.0"/>
<GradientStop Color="#C8CACD" Offset="1.0"/>
</LinearGradientBrush>
</Border.Background>
<ChargeEntry:Zoom x:Name="zoominout" />
</Border>
</Grid>
</Border>
</Border>
</Grid>
The problem here is that render transform take place much later in the rendering process. Later than the measure and arrange phases. The scroll viewer simply isn't aware of any apparent size change caused by the scaling transform, it still thinks the contained element is of the size specified by the Actual properties.
One solution might be to use the LayoutTransform object from the Silverlight Toolkit. This will apply a transform as part of its layout and hence its Actual properties will reflect the scaled size. With this inside a ScrollViewer the scroll bars should behave as expected.