I am in the codebehind file for a usercontrol. In this user control I have a grid called GBoard. I create one instance of this user control in my main XAML file and I name it GameBoard. Now I am in the codebehind as I said earlier, and I want to get the X/Y position of GameBoard. If I grab the Margin, all the values are set to 0. If I do Canvas.GetTop(this) it comes back as NaN. How do I grab these coordinates? I don't think it's a bug in my code as everything works, its just I can't seem to grab the coordinates.
Position = new Point(Canvas.GetTop(GameBoard), Canvas.GetLeft(GameBoard));
gets NaN for values.
boardMargin = GameBoard.Margin;
boardMargin is 0,0,0,0 even though its positioned in the center of the screen.
<UserControl x:Class="UserControls.Board"
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"
mc:Ignorable="d"
xmlns:controls="clr-namespace:UserControls"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Name="GBoard">
<Grid.ColumnDefinitions>
//lots of these
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
//lots of these
</Grid.RowDefinitions>
</Grid>
</UserControl>
that's the user control. I edited out the massive amount of col and row defs for space.
<Page x:Class="GUI.SGUI"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="clr-namespace:UserControls"
Title="SGUI" Height="1000" Width="1000">
<Canvas x:Name="LetterCanvas">
<controls:Board x:Name="GameBoard" Height="Auto" Canvas.Left="120" Canvas.Top="164" Width="Auto"/>
</Canvas>
</Page>
I found out that if I access the location from the main class then I can get the coordinates, if I access them from the user control's codebehind I can't. So if I have to I can make something hacky, but I'd rather get the coordinates inside of the user control.
The code in your usercontrol needs access to the Canvas in order to get the GameBoard's position because the Canvas element in WPF uses absolute positioning.
Assuming that LetterCanvas will be the parent element of the GameBoard - try using this in the code behind for your GameBoard user control:
double xPosition = Canvas.GetLeft(this);
double yPosition = Canvas.GetTop(this);
NOTE: must call from method and not constructor.
using the Grid element somewhere in your design. It provides information about the location of your controls in a very straight-forward kind of way. It works like a smarter version of a dynamicly-sizing HTML table. You can retrive ActualWidth and ActualHeight properties of any row or column - or even of the entire grid itself if you want.
Related
A little bit of background first, I have an application that uses the Microsoft AddIn Framework (MAF) that gets a WPF UI from the plugins (You can follow this Microsoft example to create one). This is up and working fine until the plugin content is large enough that the main form needs to scroll. When this happens, it scrolls outside of the bounds that it should.
In the image, you'll notice that the Plugin Label Top goes over Main Label Top when you scroll down some and at the bottom you'll only see Plugin Label Bottom. My code for the main form is the following:
<Window x:Class="WpfAddinTest.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:WpfAddinTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525" Background="DarkGray">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Main Label Top"/>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto">
<ContentControl Name="PluginHolder"/>
</ScrollViewer>
<Label Grid.Row="2" Content="Main Label Bottom"/>
</Grid>
</Window>
ContentControl is what houses the plugin UI, I don't understand why the plugin UI is going over it's parent controls. I've tried housing it in different types of controls, such as a DockPanel and Grid, everything acts the same way.
Is there a special way to get this to function correctly?
If more code is needed, I'm happy to post it, https://github.com/middas/WpfAddInTest is my complete sample project that demonstrates this.
EDIT: Loading up the form in WPF Inspector, all I can see is an AddInHost control, it doesn't show any of the individual controls inside the ContentControl. Does this have something to do with it?
EDIT 2: In trying anything I can think of, I was thinking that maybe it wasn't getting the right height when it placed the control in, so I had the plugin return the desired height and set the Height of the ContentPlaceholder manually based on what was returned; no luck. Here is what I tried:
I updated the AddIn contracts from GetInt() to GetHeight() and on the Plugin I have this method now:
public double GetHeight()
{
_Control.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
return _Control.DesiredSize.Height;
}
Then on the hosting form, I have this now:
public MainWindow()
{
_PluginPath = System.IO.Path.Combine(Environment.CurrentDirectory, "Pipeline");
_AddInPath = System.IO.Path.Combine(_PluginPath, "AddIns");
InitializeComponent();
var warnings = new List<string>(AddInStore.Update(_PluginPath));
_PluginToken = AddInStore.FindAddIns(typeof(IPlugin), _PluginPath, _AddInPath).FirstOrDefault();
_Plugin = _PluginToken.Activate<IPlugin>(AddInSecurityLevel.FullTrust);
var control = _Plugin.GetControl();
PluginHolder.Height = _Plugin.GetHeight();
PluginHolder.Content = control;
}
EDIT 3: Attempting to force the ZIndex doesn't seem to affect it either.
Panel.SetZIndex(control, -1);
I believe I've finally figured out the issue. I believe the problem is because the plugin UI is outside of the AppDomain, the ScrollViewer doesn't know how to clip the content properly. What I finally did that worked was create a callback to the main UI that the plugin can use to be given a height that it needs to fit in. If the plugin requires scrolling, the plugin can then handle it with it's own ScrollViewer.
Here is the updated Contract:
[AddInContract]
public interface IPluginContract : IContract
{
INativeHandleContract GetControl();
double GetHeight();
void SetHostCallback(IHostCallbackContract callback);
}
IHostCallbackContract:
public interface IHostCallbackContract : IContract
{
double GetHeight();
}
Now before the plugin returns the Control it can set the Height given by the main form:
public FrameworkElement GetControl()
{
if (_Callback != null)
{
_Control.SetHeight(_Callback.GetHeight());
}
return _Control;
}
I have updated my Git repo (https://github.com/middas/WpfAddInTest) with the entire working solution. The only issue with it now is that the scrolling isn't double buffered so it flickers. I'll have to live with that though since it doesn't appear there is a way to fix though due to WPF rendering via DirectX.
I'm in the process of starting a new project, using ReactiveUI and MahApps.Metro. The first hurdle I've hit is a problem of views not showing in their entirety. I have a Window, and in that Window I have a ViewModelViewHost from the RxUI library. It is a simple container for a nested view-model. The ActiveItem binding is properly binded to the view-model of the User Control, and the Button from the user control is visible on screen.
What I expect to see is a Window with a dark gray background and a button in the middle. What I see is the Window with its default background and a Button in the middle. This is not right. If I remove the button, I see nothing on the Window, only the default background.
It seems the ViewModelViewHost is only showing the actual contents of a UserControl and is disregarding what isn't considered a real Control, such as grids etc.
Has anyone come across this behaviour before?
<mah:MetroWindow x:Class="...MainWindow"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:rx="clr-namespace:ReactiveUI;assembly=ReactiveUI"
WindowStartupLocation="CenterScreen"
ShowTitleBar="False"
ShowCloseButton="False"
ShowMaxRestoreButton="False"
ShowMinButton="False"
Height="768"
Width="1024">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<rx:ViewModelViewHost ViewModel="{Binding ActiveItem}" />
</Grid>
</mah:MetroWindow>
<UserControl x:Class="...NestedView"
Name="TheUserControl"
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"
mc:Ignorable="d"
TextOptions.TextHintingMode="Auto"
TextOptions.TextRenderingMode="Auto"
d:DesignHeight="768" d:DesignWidth="1024">
<Grid Background="DarkGray">
<Button Width="200" Height="100" />
</Grid>
</UserControl>
This won't be a ReactiveUI problem, just a simple WPF one.
The ViewModelViewHost is centered in your window. While your UserControl has a DesignHeight and DesignWidth set, when it's rendered at runtime it will automatically size itself to the height and width of its content - the Button.
Add VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" to your ViewModelViewHost declaration and remove the other two Alignment attributes (they default to Stretch) and it should stretch its contents to the size of the Window while centering any item that has a fixed size.
I am completely new to WPF and have to do a bit of work on it for my job. I have a form which contains 3 element hosts each with their own child controls. I need the child controls to resize with the form so they grow and shrink when the form does.
Only the element hosts themselves seem to have the anchor property which is what I understand I need to manipulate to achieve this. How can I get the child controls to resize as well as the element hosts or am I doing this completely wrong?
Any help would be great.
I've tested with a standard text box control, and setting the Anchor property of that to Top, Left, Bottom works fine. I don't understand why it doesn't work for the element host content
<UserControl x:Class="MyControls.ucEventViewerOptions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/,arkup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="297" d:DesignWidth="128" Loaded="UserControl_Loaded">
<Grid Width="96" Height="288">
<DataGrid AutoGenerateColumns="False" Height="288" HorizontalAlignment="Left" Name="dgEventViewerOptions" VerticalAlignment="Top" Width="96" SelectionChanged="dgEventViewOptions_SelectionChanged" />
</Grid>
</UserControl>
In WPF, this type of behavior is generally caused by the HorizontalAlignment and VerticalAlignment properties. Ommitting these properties will set them to their default value "Stretch" and allows controls to resize in relation to their parent containers. This is only possible when the controls are not assigned with fixed sizes, though.
In your case, you may simply ommit these properties:
<UserControl x:Class="MyControls.ucEventViewerOptions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/,arkup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="297" d:DesignWidth="128" Loaded="UserControl_Loaded">
<Grid>
<DataGrid AutoGenerateColumns="False" Name="dgEventViewerOptions" SelectionChanged="dgEventViewOptions_SelectionChanged" />
</Grid>
</UserControl>
Unless you wish them to have a fixed height or width, of course.
If you want items to resize depending on parent elements size, you have to keep in mind that controls are implicitly inheriting parents' stretching behavior when size is not set explicitly. So to fix your problem, you need to remove setting Width and Height explicitly:
<Grid>
<DataGrid AutoGenerateColumns="False" Name="dgEventViewerOptions" SelectionChanged="dgEventViewOptions_SelectionChanged" />
</Grid>
I'm trying to create a button-like UserControl which consists of a border and a label. When adding this UserControl directly in the XAML of MainWindow, it renders correctly (it is put in a WrapPanel), but if I add it programmatically it doesn't look the same at all. There is no border, no background color, the text size of the label is wrong and so is the text color.
This is my user control:
<UserControl x:Class="Jishi.SonosPartyMode.UserControls.Player"
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"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="300"
Width="200"
Height="100">
<Border BorderBrush="#086EAA" CornerRadius="8,8,8,8" BorderThickness="4" Margin="15" Padding="15px" VerticalAlignment="Center" Background="#0A4069">
<Label Name="PlayerName" TextElement.Foreground="White" TextElement.FontSize="20px">asdasdasd</Label>
</Border>
</UserControl>
when adding it, I just invoke it like this:
var button = new Player { Content = player.Properties.RoomName, DataContext = player.Properties.UDN };
PlayerList.Children.Add( button );
PlayerList is the actual WrapPanel and Player is my UserControl. I have tried finding information regarding this, but I don't find anything. If you have another approach that I can take, please come with suggestions. All I want is a clickable area with some rounded corners that can contain text (one or more rows).
I can apply styles programatically, but the styles defined in the xaml for the UserControl isn't preserved (Border, Margins, colors etc).
First of all, you don't need to create a custom control for this, you can easily do
var button = new Border { *border properties*, Content = new Lable {Content="dfsdfsdfsd"}};
And if you use PlayerList.Children.Add( button ); then it adds to the end of Wrappanel and in XAML code you add it not as the last element (maybe)..
And the last idea is that you lost some properties that you added in XAML when test it (like aligment, margin, etc.)
Hope this helps.
I'm developing an application for windows phone using the maps control. The map control binds its center and its zoomlevel property to two properties on a viewmodel.
The map control is on a page seperate from the mainpage of the application. Every time a user moves to the map the page binds to a viewmodel. This viewmodel is a singleton (always the same instance).
the first time I move to the map navigating on the map works fine, but when I go back and navigate to the map again, navigation has some sort of bounce like it is push backed to its initial location.
To see this behaviour do the following:
Navigate to the mapPage bij clicking on the button on the mainpage. At this time the map control works as expected.
Click the back button to return to the mainpage.
Click the button on the mainpage again to navigate to the mappage for the second time. Now when sliding the map the control behaves strange by bouncing back to the original location before sliding.
The mainpage contains just a button to navigate to the map page which looks as follows:
<phone:PhoneApplicationPage
x:Class="MapTester.Map"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:maps="clr-namespace:Microsoft.Phone.Controls.Maps;assembly=Microsoft.Phone.Controls.Maps"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True"
DataContext="{Binding Path=MapViewModel, Source={StaticResource ViewModelLocator}}">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<maps:Map Center="{Binding Center, Mode=TwoWay}"
ZoomLevel="{Binding ZoomLevel,Mode=TwoWay}"
ZoomBarVisibility="Visible"
CredentialsProvider=""
ScaleVisibility="Visible"></maps:Map>
</Grid>
</phone:PhoneApplicationPage>
The MapViewModel is defined on the ViewModelLocator. I created a solution to demonstrate then problem. You can download it here https://skydrive.live.com/?cid=25374d9051083633&sc=documents&id=25374D9051083633%21344#
Does anybody have an idea how to fix this?
Thanks!
I don't see what's wrong here? Unless you're navigating backwards (and thus not setting the DataContext), Bing Maps will always do a "bounce" animation from global view to the center location. This is how the control work, so nothing you can do about that.