I need to add several user controls to a Canvas. The size of the UserControl depends on the number of items present in the ItemsControl of the UserControl. To position the controls properly and to draw interconnecting lines between the usercontrols, I need the absolute width/height w.r.t the parent canvas. How to get these? ActualHeight and ActualWidth are returning 0.
I had asked similar question earlier, but could not get the right answer.
EDIT: Adding XAML od UserControl
<UserControl x:Class="SilverlightApplication2.MyControl"
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"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}" Loaded="UserControl_Loaded">
<Grid x:Name="LayoutRoot" Background="White">
<Border CornerRadius="3" BorderThickness="1" BorderBrush="LightGray">
<Grid Name="grid1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" >
<Grid.RowDefinitions>
<RowDefinition Height="40*" />
<RowDefinition Height="136*" />
</Grid.RowDefinitions>
...
<Grid Name="gridPC" Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="55*" />
<RowDefinition Height="*" />
<RowDefinition Height="55*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
....
<ItemsControl x:Name="pitems" ItemsSource="{Binding RowsP}" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Width="250" Orientation="Horizontal">
<TextBlock Text="{Binding X}" Width="100" />
<TextBlock Text="{Binding Y}" Width="130" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
......
</Grid>
</Grid>
</Border>
</Grid>
You have few options you can do this, forcing to call Window.Measure and Window.Arrange will make all values to be calculated, or you can get those values in the Window.Loaded event. This same issue is discussed already on this question.
If you are sizing to content:
window.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
window.Arrange(new Rect(0, 0, window.DesiredWidth, window.DesiredHeight));
If you are using an explicit window size:
window.Measure(new Size(Width, Height));
window.Arrange(new Rect(0, 0, window.DesiredWidth, window.DesiredHeight));
or
public MyWindow()
{
Loaded += delegate
{
// access ActualWidth and ActualHeight here
};
}
ActualWidth and ActualHeight work only after the control has been rendered.
To get the desired size of a control, you need to let it measure itself by calling it's Measure method. After that, you can use DesiredSize property which will contain the values you seek.
There is also a good article by Charles Petzold handling a similar situation:
Thinking Outside the Grid
I am actively creating a Silverlight timeline control and I don't do a measure as the previous posters advised. I simply wait for the final onsize call or other dependent properties OnChanged event.
Here is what I do to load my control which has a canvas:
Subscribe to the user control's Loaded event (which is the target for all dependent load events calls and on size event in (step #2)).
Subscribe to the Size Changed event (which calls the controls loaded event as mentioned in #1).
All dependent properties OnXXXPropertyChanged event call the OnLoad (#1).
Within the loaded event I check for this.ActualWidth to be set (non zero) along with whether all of my dependent properties are valid. (If they are all not set and also my boolean global flag states that it hasn't been loaded yet; it does nothing and exits (waiting a subsequent call).
Once my load event detects all dependent properties have been set and ActualWidth is not zero, it then begins the process of using the width and the dependent properties to begin to create my sub controls.
HTH
It has been a long time but I did something similar a few years ago. I don't recall all the details right now, I will look at this when I have more time this evening. I wanted to give you a quick idea of why you are getting 0 for the size.
This is primarily because the layout system in WPF occurs in two passes, the measure and the arrange pass. First the container control (in your case the Panel) asks it's children for their size once this pass is completed, the container will arrange it children using the sizes they calculated in the measure pass.
I would recommend reading the this MSDN article focusing on the Measuring and Arranging Children section. http://msdn.microsoft.com/en-us/library/ms745058.aspx
Let me know if this does not help, and I will spend some more time to refresh my memory on all the details.
Based on your edit you may want to check out this post describing how to create objects that are connected with lines. http://denisvuyka.wordpress.com/2007/10/21/wpf-diagramming-drawing-a-connection-line-between-two-elements-with-mouse/
I think this is more directed at your exact scenario.
Related
I'm trying to change the behaviour when there's on-screen keyboard presence similar to what is described on https://msdn.microsoft.com/en-gb/windows/uwp/input-and-devices/respond-to-the-presence-of-the-touch-keyboard?f=255&MSPPError=-2147217396 but not actually clarified as to how to achieve:
In some cases, there are UI elements that should stay on the screen
the entire time. Design the UI so that the form controls are contained
in a panning region and the important UI elements are static.
This is my page's basic xaml layout:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="titlebar" Grid.Row="0" />
<RichEditBox x:Name="content" Grid.Row="1" />
</Grid>
What I want is for the titlebar element to still be visible on-screen when the touch-screen keyboard is opened. At the moment, what's happening is when the on-screen keyboard is called, the page is automatically scrolled down so that the RichEditBox appears at the very top of my view (requiring me to scroll up in order to get the titlebar back into view).
Any guidance on how to achieve the behaviour I'm after will be much appreciated.
Put both header TextBlock and RichTextBox in a Grid and then use translateY on the Grid's transform when RichTextBox receive focus.
Maybe something like this https://social.msdn.microsoft.com/Forums/windowsapps/en-US/99652e87-113c-47fa-a8e7-60f11fc9f160/virtual-keyboard-covering-textbox
http://blog.jerrynixon.com/2013/08/windows-8-xaml-manipulation-using.html?m=1
According to some folks, the actual width is obtained using ActualWidth attribute as shown in the example below. It makes sense but I seem to experience contradicting behavior.
<Canvas Width="{Binding ActualWidth,ElementName=Expy}">
<Expander x:Name="Expy"
HorizontalAlignment="Left"
Margin="0,0,0,0"
VerticalAlignment="Top" ...>
...
</Expander>
</Canvas>
In the setup above, the behavior is consistent with the expectations and, although tightly squeezed together, the next element in the panel containing the canvas is not overlapped by it's predecessor.
However, if I change the margins to a bit wider, I can clearly see that the canvas intrude on the next element, estimatingly by the same number of pixies that I requested in the margin attribute. So it'd appear that the ActualWidth isn't the actual width but the width without the margin.
Am I confusing something here and if so, what?
How to obtain and bind to the actaully actual, rendered width?
The linked answer says:
ActualWidth accounts for padding and margins ...
This is incorrect. The ActualWidth includes only the padding, not the margin (same with ActualHeight).
A comment that has been left on that answer by somebody else provides the appropriate correction.
This XAML code illustrates the issue:
<Window x:Class="..."
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<TextBlock x:Name="First" Text="Some text" Padding="10" Margin="0,0"
HorizontalAlignment="Left" Background="Yellow" />
<TextBlock Text="{Binding ActualWidth, ElementName=First}" />
<TextBlock x:Name="Second" Text="Some text" Padding="10" Margin="10,0"
HorizontalAlignment="Left" Background="LimeGreen" />
<TextBlock Text="{Binding ActualWidth, ElementName=Second}" />
</StackPanel>
</Window>
If you run this you will see that both of the "Some text" text blocks have the same ActualWidth value despite the second one having horizontal margins applied to it.
You asked how you could take this into account. There is no way of doing this through binding because the ActualWidth property doesn't include the margin as already stated. What you can do is apply the margin to the parent element (the canvas) instead of applying it to the expander.
In other words, instead of doing this:
<Canvas Width="{Binding ActualWidth,ElementName=Expy}">
<Expander x:Name="Expy" ... Margin="10" ... >
...
</Expander>
</Canvas>
do this:
<Canvas Width="{Binding ActualWidth,ElementName=Expy}" Margin="10">
<Expander x:Name="Expy" ... >
...
</Expander>
</Canvas>
Yes Konrad. You are confusing.
Whenever we mean Actual(Height/Width), it is the rendered one. You were correct in that. However, Actual(Height/Width) values gets initialized after the WPF Layout process which includes Measure and Arrange stages and that is something you need to understand first to get to the real cause of the problem.
At first, Binding anything with Actual values will never give you desired results because by doing this you are violating WPF Layout chain. As per WPF Layout stages, in Measure stage WPF gets the specified size (for e.g. values specified in height and width) for each control in the layout and then in the Arrange stage it actually allocates controls to the layout in the best possible way. The size specified is subject to vary after the Arrange stage.
Also, it should be noted that Actual parameters include rendered size plus padding value (but not margin). In your example, I guess the other panel next to the Expander control is the reason behind the problem you reported. I can confirm only when I see the entire layout.
But as a precautionary measure, you can always stop using Actual parameters for bindings. You can definitely get it worked out using Width and Height values for binding.
You cannot include the margin to your ActualWidth. A solution for this would be to use DesiredSize.Width or DesiredSize.Height. This will take into account the Margin. But it's a UIElement.
I am using the Ribbon control in WPF and I noticed there are 2 different versions.
using Microsoft.Windows.Controls.Ribbon;
If I use this one in my xaml and class, my whole window will be in a very old windows style.
using System.Windows.Controls.Ribbon;
If I use this one in my xaml and class, my Ribbontabs suddenly won't fill correctly anymore.
When I use both of them. With this:
<ribbon:RibbonWindow x:Class="WPSDashboard.Views.ShellWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
xmlns:r="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"
Title="WPSDashboard"
x:Name="RibbonWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Ribbon Region -->
<r:Ribbon x:Name="Ribbon" prism:RegionManager.RegionName="RibbonRegion">
<r:Ribbon.ApplicationMenu>
<r:RibbonApplicationMenu SmallImageSource="Images\SmallIcon.png">
<r:RibbonApplicationMenuItem Header="Exit"
x:Name="MenuItemExit"
ImageSource="Images\Exit.png"
Command="{Binding ExitCommand}"/>
</r:RibbonApplicationMenu>
</r:Ribbon.ApplicationMenu>
</r:Ribbon>
<Grid x:Name="ClientArea" Grid.Row="1">
<!-- Workspace Region-->
<GridSplitter HorizontalAlignment="Left" Width="2" Grid.Column="1"/>
<ContentControl x:Name="WorkspaceRegion" Grid.Column="1" prism:RegionManager.RegionName="WorkspaceRegion" />
</Grid>
</Grid>
</ribbon:RibbonWindow>
My Ribbontabs will load but the window now looks like this:
I can't click on close and minimize and maximize. <---
How can I get the border to be normal instead of small?
I can't close my windows this way.
I found the best way to make it look and work good!
Instead of the tags <ribbon:RibbonWindow on the beginning of the xaml,
Make it <Window .
Also add this part:
xmlns:r="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
Then in your class delete your : RibbonWindow (If it's there)
If that doesn't work and you don't need the quick access toolbar, this may help:
Go back to your XAML, and change the Ribbon margin to -22 :
<r:Ribbon x:Name="Ribbon" prism:RegionManager.RegionName="RibbonRegion" Margin="0,-22,0,0" >
Now my application looks like this(with the -22 margin) :
Now it looks like a normal application without an ugly windows 98 or 2000 style and the close button, minizime button and maximize button are back!
I personally would, either play on margins, or better than that, investigate the style of that ribbon and change it the way it helps my needs
I have the problem, that my Grid is not filling the space as I want it.
Here some code:
<HubSection>
<Grid Width="850">
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
<RowDefinition Height="310"/>
</Grid.RowDefinitions>
<Input:RadDatePicker Grid.Row="0" Value="{Binding CurrentDate, Mode=TwoWay}" />
<ListView
Grid.Row="1">...
</ListView>
<Grid Height="310"
Grid.Row="2">...
</Grid>
...
I want that the middle row is filling the space up of the hubsection. Instead it now just fills up when the listview contains enough items.
Any idea?
Now the filled ListView:
I would try setting the VerticalContentAlignment of the HubSection to Stretch as well as setting the VCA of the outer grid to that option. I'm suspecting the default might be Center or Top and so the minimizing vertical alignment control from the parent control and the expanding star-sized row setting of the inner grid come in a little bit of a conflict that some layout prioritizing rules probably resolve in getting the VCA rule to win.
For similar layout issues it is usually best to analyze with a visual tree debugger such as the XAML Spy or WinRT XAML Toolkit. You can also try tracing these various properties by walking the visual tree with the VisualTreeHelper class yourself.
I hope you can help me with my problem. It's about a custom designer for a WF 4.0 activity, but the problem is essentially in the WPF of the designer.
Some background
I've created a custom WorkFlow activity to send e-mails. For the custom designer for the activity, I've previously been using regular Textboxes for the "Subject" and "Body" of the e-mail, but I'd like to use the ExpressionTextBox to easily bind it to the InArguments of the activity. The ExpressionTextBoxes are in a grid, and this grid is on a StackPanel.
I've set the the MinWidth, MaxWidth and Margin of the ExpressionTextBoxes to fit with the other controls, and in the Visual Studio Designer (viewing the custom activity designer, not the actual WorkFlow) everything looks as it should.
<sapv:ExpressionTextBox Grid.Column="1" Grid.Row="2" Height="Auto" HorizontalAlignment="Right" Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}" OwnerActivity="{Binding Path=ModelItem}" VerticalAlignment="Center" MaxWidth="176" MinWidth="175" />
The problem
When used, initially it also looks as it should, but when the ExpressionTextBoxes are edited, they shrink into being really small. When text is entered, the control expands to fit the text, until it reaches its MaxWidth. When the editing ends, it goes back to it's MaxWidth. I'd prefer if it stayed the same size, regardless of being in edit-mode or not.
If you can't see it, open the image here
What I've tried
I've mostly been doing WinForms, and I'm pretty inexperienced with WPF, so I don't know if there are some funky properties or other settings that I've missed. I've tried setting width-properties of the parent controls (StackPanel and Grid), I've tried setting just the width (no min/max), but it seems to shrink regardless of what I set.
If you would like more information or code, please don't hesitate to ask.
Update
As you can see in the comments to Maurices answer, I figured out how to avoid the problem by removing the horizontalAlignment property, and then using margins to align it to the right. But I'm not going to mark an answer, until there's an explanation of why this behaviour happened in the first place. My XAML was almost identical to what Maurice posted, so there must be something wrong elsewhere.
The XAML for the ExpressionTextBox looks fine to me and when I try the following designer it works just fine.
<sap:ActivityDesigner x:Class="WorkflowConsoleApplication2.MyActivityDesigner"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"
xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation">
<sap:ActivityDesigner.Resources>
<sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
</sap:ActivityDesigner.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Label Content="Subject"
Grid.Row="2"
Grid.Column="0"/>
<sapv:ExpressionTextBox Grid.Column="1"
Grid.Row="2"
Height="Auto"
HorizontalAlignment="Right"
Margin="4, 4, 4, 4"
Expression="{Binding Path=ModelItem.Subject, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In}"
ExpressionType="{x:Type TypeName=sys:String}"
OwnerActivity="{Binding Path=ModelItem}"
VerticalAlignment="Center"
MaxWidth="176"
MinWidth="175" />
</Grid>
</sap:ActivityDesigner>
So I suspect the problem is possibly in your grid definition.