I have an ElementHost which contains an WPF user control.
For some reason that I don't know, the ElementHost is not being resized to the user control when it changes its height.
My ElementHost has the property AutoSize set to True and the Dock property set to DockStyle.Fill.
Also my WPF user control that I bound to the ElementHost.Child has also the Autosize property set to True.
When my WPF changes its height dynamically, the ElementHost does not resize accordingly to have the same height as the WPF user control.
I have been searching a lot in google and I got with this interesting post and also with this one.
There is discussed about do the following:
Override the MeasureOverride method
After the measurement is calculated, use
PresentationSource.From(visual).CompositionTarget.TransformToDevice.Transform(point)
to get the device coordinates
Update ElementHost.Size.
So in one of the answers of that post I found the method that calculates the size which is this. Here it is:
public System.Windows.Size GetElementPixelSize(UIElement element)
{
Matrix transformToDevice;
var source = PresentationSource.FromVisual(element);
if (source != null)
transformToDevice = source.CompositionTarget.TransformToDevice;
else
using (var Hwndsource = new HwndSource(new HwndSourceParameters()))
transformToDevice = Hwndsource.CompositionTarget.TransformToDevice;
if (element.DesiredSize == new System.Windows.Size())
element.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
return (System.Windows.Size)transformToDevice.Transform((Vector)element.DesiredSize);
}
Now I am trying to follow the 3 steps above indicated, in order to update the ElementHost size. So first, I override the MeasureOverride method in my xaml.cs wpf user control, convert the size from WPF coordinates to device coordinates and finally I am trying to update the ElementHost.Size:
protected override Size MeasureOverride(Size constraint)
{
// within my wpf control I have a reference to ElementHost so I can do below
// myDlgHost is the name that my wpf user control has - I have set it through x:Name -
ElementHost.Size = this.GetElementPixelSize(this.myDlgHost);
return base.MeasureOverride(constraint);
}
But a compilation error appears when trying to update the ElementHost.Size, it says:
Cannot implicitly convert type 'System.Windows.Size' to 'System.Drawing.Size'
So anyone can indicate me how can I convert the size from WPF coordinates to device coordinates and update the elementhost size?
Related
I am using report viewer inside a windows form and I am trying to adjust the height of the ToolStrip of the ReportViewer.
I tried to adjust the AutoSize property to false then adjust the Height but the height didn’t change:
var toolStrip = (ToolStrip)reportViewer1.Controls.Find("toolStrip1", true).First();
toolStrip.AutoSize = false;
toolStrip.Height = 100;
How can I adjust the height of Report viewer toolbar in windows form? Any suggestions would be much appreciated.
The ToolStrip of the report viewer has Dock = Fill inside a custom control (report toolbar). The report toolbar has overridden is size-related methods and properties and looks into the PreferredSize of the ToolStrip to set the bounds.
Properties like Padding, ImageScalingSize, MinimumSize, Font contribute to determining the preferred size of toolstrip; so you can set either of mentioned properties.
The most effective property is MinimumSize:
var toolStrip = (ToolStrip)reportViewer1.Controls.Find("toolStrip1", true).First();
toolStrip.MinimumSize = new Size(0, 100);
toolStrip.Parent.Height = 0; // No effect, just to force recalculation of height.
I’m programmatically inserting grids into grids, for the first nested, it will work perfect. But then from the second it stops resizing to fit for the content.
The only defaults I override are the MinWidth and the MinHeight.
EDIT:
Each time I'm creating a grid, I add a stackpanel (with lable inside) to each cell. Then I Insert a nested grid to that stack panel.
As seen above, the grid that's being marked with the green thing, dose not affect the mainGrid size.
Thanks
Apparently the grid restricts it's maximum size, I don't know for what purpose.
Hopefully that won't back fire at me later. but for now, all I had to do was create and use a custom grid with unlimited 'resize room'.
public class CustomGrid : Grid
{
protected override Size MeasureOverride(Size availableSize)
{
availableSize = new Size(availableSize.Width + double.MaxValue, availableSize.Height + double.MaxValue);
return base.MeasureOverride(availableSize);
}
}
There are probably more legitimate solutions to this problem, but for the moment that's all I need.
I currently create a class which inherits from a Popup.
Finally it will be used to show the user a popup with validation rules when editing e.g a TextBox.
Therefore I created ValidationPopup with this constructor so far:
public ValidationPopup(UIElement parent, double width) : base()
{
this.parent = parent;
this.width = width;
InitControl();
}
I would like to set the size of the popup equal to the size of the PlacementTarget parent.
In order to allow many different controls to be able to have one of these ValidationPopups I pass an UIElement as parent instead of TextBox etc.
My problem is that I have to pass the width and height values of this control when building an instance of ValidationPopup in order to size it properly.
Is it possible to get these values from UIElement?
I saw RenderSize on MSDN but it only gives me 0.0 values for width and height.
This is where I setup one instance of ValidationPopup:
txtOperator = new TextBox();
layoutGrid.Children.Add(txtOperator);
operatorVPU = new ValidationPopup(txtOperator, txtOperator.Width);
I tried to use RenderSize but this doesn't work until the whole UI is completly finished.
Is there a way to get Height and Width values of an UIElement at this point?
Are there maybe other even better ways to achieve the same result?
Sounds like you need to use the ActualWidth/Height properties. If they are still 0 or NaN, you can try executing this code on a later part of the view creation.
I am trying to create a custom user control in WPF. I want to be able to set the size manually when I later use the control within another window.
As a short test I have just made a control comprising a canvas within a grid, which totally fills the control. When initialised it draws a rectangle within itself showing its size. I then position this on a window, making it whatever size I want.
However I now have problems, as if I make the height of the rectangle I draw
this.ActualHeight
then when the control initialises this value is still 0, and so I get nothing. If instead I use
this.Height
then I get the height that I made it during design time, and not the size I have subsequently made it within the window.
The height and width seem to be set within the XAML designer, so I don't know what to do.
Is there an easy way around this?
I think what you're experiencing is how WPF performs layout and specifically how Canvas does not participate in Layout.
In your specific case you are setting the width of the Rectangle to Canvas.ActualWidth? Unless the width / height of the canvas have been explictly set then the ActualWidth/Actualheight will be zero, hence you can't get a point of reference within which to position children of Canvas. What I would do is bind the canvas width and height to its parent container (or set in code) to get the ActualWidth / ActualHeight correctly propagated.
As a point of interest try this example to understand how the WPF Layout engine works. The following code can force a height on a FrameworkElement to set the Width, Height as normal, then force a layout (measure, arrange pass) on the element in question. This causes the WPF layout engine to measure/arrange the element and propagate the Width, Height to ActualWidth, ActualHeight.
For example:
// Set the width, height you want
element.Width = 123;
element.Height = 456;
// Force measure/arrange
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
element.Arrange(new Rect(0, 0, element.DesiredWidth, element.DesiredHeight));
// Subject to sufficient space, the actual width, height will have
// the values propagated from width/height after a measure and arrange call
double width = element.ActualWidth;
double height = element.ActualHeight;
Also see this related question for clarity. I have used the above method occasionally to measure the text in a textblock so as to position correctly on a canvas.
.NET Framework / C# / Windows Forms
I'd like the FlowLayoutPanel to automatically adjust its width or height depending on number of controls inside of it. It also should change the number of columns/rows if there is not enough space (wrap its content). The problem is that if I set autosize then the flowlayoutpanel doesn't wrap controls I insert. Which solution is the best?
Thanks!
Set the FlowLayoutPanel's MaximumSize to the width you want it to wrap at. Set WrapContents = true.
Have you tried using the TableLayoutPanel? It's very useful for placing controls within cells.
There is no such thing like impossible in software development. Impossible just takes longer.
I've investigated the problem. If there is really need for Flow Layout, it can be done with a bit of work. Since FlowLayoutPanel lays out the controls without particularly thinking about the number of rows/columns, but rather on cumulative width/height, you may need to keep track of how many controls you've already added. First of all, set the autosize to false, then hook your own size management logic to the ControlAdded/ControlRemoved events. The idea is to set the width and height of the panel in such a way, that you'll get your desired number of 'columns' there
Dirty proof of concept:
private void flowLayoutPanel1_ControlAdded(object sender, ControlEventArgs e)
{
int count = this.flowLayoutPanel1.Controls.Count;
if (count % 4 == 0)
{
this.flowLayoutPanel1.Height = this.flowLayoutPanel1.Height + 70;
}
}
if the panel has initially width for 4 controls, it will generate row for new ones. ControlRemoved handler should check the same and decrease the panel height, or get all contained controls and place them again. You should think about it, it may not be the kind of thing you want. It depends on the usage scenarios. Will all the controls be of the same size? If not, you'd need more complicated logic.
But really, think about table layout - you can wrap it in a helper class or derive new control from it, where you'd resolve all the control placing logic. FlowLayout makes it easy to add and remove controls, but then the size management code goes in. TableLayout gives you a good mechanism for rows and columns, managing width and height is easier, but you'd need more code to change the placement of all controls if you want to remove one from the form dynamically.
If possible, I suggest you re-size the FlowLayoutPanel so that it makes use of all the width that is available and then anchor it at Top, Left and Right. This should make it grow in height as needed while still wrapping the controls.
I know this is an old thread but if anyone else wonders on here then here's the solution I produced - set autosize to true on the panel and call this extension method from the flow panel's Resize event:
public static void ReOrganise(this FlowLayoutPanel panel)
{
var width = 0;
Control prevChildCtrl = null;
panel.SuspendLayout();
//Clear flow breaks
foreach (Control childCtrl in panel.Controls)
{
panel.SetFlowBreak(childCtrl, false);
}
foreach (Control childCtrl in panel.Controls)
{
width = width + childCtrl.Width;
if(width > panel.Width && prevChildCtrl != null)
{
panel.SetFlowBreak(prevChildCtrl, true);
width = childCtrl.Width;
}
prevChildCtrl = childCtrl;
}
panel.ResumeLayout();
}
Are you adding the controls dynamically basing on the user's actions? I'm afraid you'd need to change the FlowLayout properties on the fly in code, when adding new controls to it, then refreshing the form would do the trick.