Problem with ContentControl resizing - silverlight

I've been hitting my head against a wall with this one for a while now.
I've got a custom control that derives from ContentControl - it's working perfectly EXCEPT that it won't resize to fit its parent, either declaratively OR programatically.
The custom control is parented within (ultimately) a content presenter, and that's correctly sized, but my control just will NOT size itself out to fit.
(sample.MyControl) - 400x267
- (System.Windows.Controls.ContentPresenter) - 979x569
Even when I explicitly set the width and height (at the right moment), the size doesn't "stick"
Debug.WriteLine(string.Format("MyControl {0}: Size is {1}x{2} ({3}/{4})",
GetHashCode(), this.ActualWidth, this.ActualHeight,
this.HorizontalAlignment, this.VerticalAlignment));
Debug.WriteLine(string.Format("Parent is {0}x{1} ({2}/{3})",
parent.ActualWidth, parent.ActualHeight,
parent.HorizontalAlignment, parent.VerticalAlignment));
this.Width = parent.ActualWidth;
this.Height = parent.ActualHeight;
Debug.WriteLine(string.Format("MyControl {0}: New size is {1}x{2}",
GetHashCode(), this.ActualWidth, this.ActualHeight));
The above code gives:
MyControl 36022757: Size is 400x267 (Stretch/Stretch)
Parent is 979x569 (Stretch/Stretch)
MyControl 36022757: New size is 400x267
Why! Oh Gods Why!
Anyone got any ideas?

You need just to add HorizontalContentAlignment="Stretch" and VerticalContentAlignment="Stretch" to your control:
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
...
</ContentControl>
In such cases Silverlight Spy tool can be helpful for debugging layout in runtime.
Try to run your application in this tool and you will be able to view all xaml elements and even change some properties in runtime.

Related

WPF automatic resize font until it fits within parent control

I have a user control who's root element is a Grid.
I also have have a ContentControl that serves as a placeholder for some text that is filled when data is loaded. This control can be moved around within the user control and so it's position can be anywhere.
If the text is too long to fit within the root Grid of the user control, I want to reduce the font size of the ContentControl until the text fits.
My problem is that I can't seem to find an event that I can handle to do this process.
I tried using the ContentControl.LayoutUpdated event;however, the sender parameter for this always appears to be nothing...which is really not helpful!
I am really looking forward to any advise on how to achieve this.
Thank you
-Frinny
Wrapping your ContentControl in a Viewbox set to only scale down will do this for you:
<Viewbox StretchDirection="DownOnly" Stretch="Uniform">
<ContentControl Content="Some Text"/>
</Viewbox>

Resizing a Panels based on the size of user control

I'm trying to find a way to resize a LayoutPanel (DevExpress) based on the size of the user control that it contains. The user control is exposed using a ContentControl. Here's the relevant Code
This is the Layout panel and the coresponding view:
<dxd:LayoutPanel Caption="Search Criteria" CaptionImage="Images/Icons/DetailView.png">
<ContentControl Name="myContentControl" Content="{Binding Path=ProjectsSearchVM}"/>
</dxd:LayoutPanel>
The ProjectSearchVM is a property of the MainWindowViewModel, which is the DataContext for the code above. This property returns an object of type ProjectsSearchViewModel that is replaced by its corresponding View (containing a userControl) using a Resource File:
<DataTemplate DataType="{x:Type vm:ProjectSearchViewModel}">
<vw:ProjectSearchView />
</DataTemplate>
The problem is that my view is higher than the original size of the Layout Pannel. I'd like to bind the panel's MinSize to the size of my view (or the ContentControl containing it).
I tried this, but it doesn't work:
<dxd:LayoutPanel Caption="Search Criteria" CaptionImage="Images/Icons/DetailView.png">
<dxd:LayoutPanel.MinSize>
<Binding ElementName="myContentControl" Path="Size"/>
</dxd:LayoutPanel.MinSize>
<ContentControl Name="myContentControl" Content="{Binding Path=ProjectsSearchVM}" />
</dxd:LayoutPanel>
I'm still very new to WPF, so I'm sure the solution is simple.
Can anyone enlighten me?
The question was answered on the DevExpress site at this link:
http://www.devexpress.com/Support/Center/Question/Details/Q448884
For flyout, it involves overriding the control in the container, for example, if it's in a Border, something like this:
public class AutoSizeContainer : Border {
protected override void OnInitialized(EventArgs e) {
base.OnInitialized(e);
BaseLayoutItem item = DockLayoutManager.GetLayoutItem(this);
Child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
AutoHideGroup.SetAutoHideSize(item, new Size(Child.DesiredSize.Width + 6, Child.DesiredSize.Height + 6));
}
}
Making such an object the root object of the LayoutPanel in an AutoHide group, makes the flyout sizing correct.
I'm not familiar with DevExpress's LayoutPanel, but most standard WPF panels (Grid, StackPanel) "auto size" to contain their children. Are you setting hard Height and Width properties for the LayoutPanel (or does it only contain a Size property and not Height and Width like standard WPF controls)?
If you are forced to use hard Height/Width values, a common way to bind them would be like this:
<dxd:LayoutPanel ... Height="{Binding Height, ElementName=myContentControl}" Width="{Binding Width, ElementName=myContentControl}">
<ContentControl x:Name=myContentControl ... />
</dxd:LayoutPanel>
Normally, if you bind Heights and Widths you bind to ActualHeight or ActualWidth, but those properties do not exist on ContentControl. (Height and Width are only suggested values, so you may find that if the above binding is needed and works for you, you may need to tweak the values slightly with a value converter to account for margins or padding).

WPF: Making child elements' MinWidth/MinHeight constrain the Window

I have a WPF Window that contains a UserControl with a MinWidth and MinHeight. How can I prevent the user from resizing the Window down to a point where that UserControl's minimum size is violated?
Here's a simplified version of a Window I'm working on. My real app's UserControl is replaced here by a Border:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal">
<Button Content="OK"/>
<Button Content="Cancel"/>
</StackPanel>
<Border BorderBrush="Green" BorderThickness="10"
MinWidth="200" MinHeight="150"/>
</DockPanel>
</Window>
If I shrink the window small enough, the Border's right and bottom edges are cut off. I want to prevent the window from getting that small -- I want my window's minimum size to be exactly the point at which the Border is at its minimum size. Some frameworks (like the Delphi VCL) automatically aggregate child controls' minimum sizes up to the window; I expected WPF to do the same, but clearly it does not.
I could always explicitly set the Window's MinWidth and MinHeight, but to calculate those correctly, I would have to factor in the Buttons' ActualHeight, which would mean waiting for at least one layout pass (or calling Measure manually). Messy.
Is there any better way to keep the Window from resizing too small for its content?
The simplest way I've found is to tell the Window to size to its content:
<Window ... SizeToContent="WidthAndHeight" ...>
and then, once it's done sizing (which will take the child elements' MinWidth and MinHeight into account), run some code that sets MinWidth and MinHeight to the window's ActualWidth and ActualHeight. It's also a good idea to turn SizeToContent back off at this point, lest the window resize when its content changes.
The next question is, where to put this code? I finally settled on OnSourceInitialized:
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
MinWidth = ActualWidth;
MinHeight = ActualHeight;
ClearValue(SizeToContentProperty);
}
I also tried the Loaded event, but in my case, that was too soon -- Loaded happens before databindings have been evaluated, and I had databindings that affected my layout (a Label with a binding for its Content -- its size changed after the binding took effect). Moving the code into OnSourceInitialized, which fires after databinding, corrected the problem.
(There were also other events that fired after binding, but before the window was shown -- SizeChanged and LayoutUpdated -- but they both fire multiple times as the window is shown, and again later if the user resizes the window; OnSourceInitialized only fires once, which I consider ideal.)
Have you tried using an ElementName style binding from the Window to the UserControl at hand? It seems like it would be feasible to bind the Window's MinWidth/Height to those of the Button. Still not pretty, but it shouldn't require extra passes once the binding is in place and will adapt if you change the values on the Button.

Window size and TabControl with DataBinding (Size of Items)

The following scenario bothers me:
I have a simple WPF Window that has a TabControl as content. The ItemsSource of the TabControl is bound to a list of objects. In order to visualize the objects I defined some DataTemplates. As the list of objects may have different types, the right visualization is chosen by the default template selector. This works fine and does not cause any trouble.
The issue that came up is the size of the window. The DataTemplates have different sizes. And I want the dialog to have a size that the largest DataTemplate fits. When I use SizeToContent in the Window, the Window changes its size everytime I change the tabs.
So, my questions is, how can I achieve to make the window fit the largest TabItem (which size is determined by the DataTemplate)?
thanks,
Florian
The problem you are having, is that because the larger DataTemplate is not shown, it's size is not taken into account when sizing to content.
Your options:
1) Manually set (min)width/height on appropriate controls (tabcontrol, Window, DataTemplate, etc)
2) If you know that a certain tab is always going to be bigger than the rest, you can bind the width/height of the other tabs to the bigger tab:
<TabItem>
<StackPanel Name="stackPanelBiggest" />
</TabItem>
<TabItem>
<StackPanel Width="{Binding ElementName=stackPanelBiggest, Path=ActualWidth}" />
</TabItem>
I think that for the above to work, the biggest tab has to be first one shown. Although the tab control destroys the visual tree of the previous tab when swithching to another tab, this method is still working for me (despite the fact that the ActualWidth should be 0 or NaN, after switching tabs).

ListBox with ItemTemplate (and ScrollBar!)

I have a databound and itemtemplated ListBox:
<ListBox x:Name="lbLista"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Deleteable, Mode=TwoWay}" />
<Label Content="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ites show fine and they come from an ObservableCollection.
The problem is the scrollbar which appears but is not usable - it does not have a handle to grab. I've tried setting some ScrollView attached properties on ListBox, but they do not affect the situation.
I pasted your code into test project, added about 20 items and I get usable scroll bars, no problem, and they work as expected. When I only add a couple items (such that scrolling is unnecessary) I get no usable scrollbar. Could this be the case? that you are not adding enough items?
If you remove the ScrollViewer.VerticalScrollBarVisibility="Visible" then the scroll bars only appear when you have need of them.
ListBox will try to expand in height that is available.. When you set the Height property of ListBox you get a scrollviewer that actually works...
If you wish your ListBox to accodate the height available, you might want to try to regulate the Height from your parent controls.. In a Grid for example, setting the Height to Auto in your RowDefinition might do the trick...
HTH
I have never had any luck with any scrollable content placed inside a stackpanel (anything derived from ScrollableContainer. The stackpanel has an odd layout mechanism that confuses child controls when the measure operation is completed and I found the vertical size ends up infinite, therefore not constrained - so it goes beyond the boundaries of the container and ends up clipped. The scrollbar doesn't show because the control thinks it has all the space in the world when it doesn't.
You should always place scrollable content inside a container that can resolve to a known height during its layout operation at runtime so that the scrollbars size appropriately. The parent container up in the visual tree must be able to resolve to an actual height, and this happens in the grid if you set the height of the RowDefinition o to auto or fixed.
This also happens in Silverlight.
-em-
Thnaks for answer. I tried it myself too to an Empty Project and - lo behold allmighty creator of heaven and seven seas - it worked. I originally had ListBox inside which was inside of root . For some reason ListBox doesn't like being inside of StackPanel, at all! =)
-pom-

Resources