I've got a FlexLayout inside my Xamarin.Forms Application which displays some Frames. The problem is, that if i set FlexLayout.Grow="1", the last frames not completly filling a column will grow to the size where they fill it. But if I set FlexLayout.Grow="0" there will be some empty space at the end of each colum.
As you can see under Allergens there is a little space at the end of each column which will grow when resizing the Window until a fifth item will fit into the column (when FlexLayout.Grow="0" set). But if I set FlexLayout.Grow="1" will resize to fil the entire column space until a fifth item will fit into the column. Then all items will resize to their minimum. This is what it should be, BUT I don't want the last items to grow infinitly. See this image:
Here is the code for the FlexLayout:
<StackLayout Grid.Row="11">
<flexLayouts:ExtendedFlexLayout Margin="5,0,5,0"
Direction="Row"
Wrap="Wrap"
VerticalOptions="Start"
AlignItems="Start"
JustifyContent="Start"
ItemsSource="{Binding Allergens}">
<flexLayouts:ExtendedFlexLayout.ItemTemplate>
<DataTemplate>
<details:BeverageDetailsView FlexLayout.Grow="1" />
</DataTemplate>
</flexLayouts:ExtendedFlexLayout.ItemTemplate>
</flexLayouts:ExtendedFlexLayout>
</StackLayout>
Is there a way to stop the remaining items from resizing to that big ones?
Thanks for any help
Solution:
I think the length of right empty space depending on your widthRequest of item.And the widthRequest will be calculated by the screen width and margin of boxView.
For example, if you want put 4 items in a row and the boxMargin here is 10.
You should first get screen width, you can refer to http://stackoverflow.com/a/26504582/283974
And then, you can calculate the widthRequest of items.
Because there are 4 items in a row, each item has a left and right margin,so there is 8 margins in a row. So the screenWidth should minus itemsInRow *2 * margin.
float screenWidth = 375;//375 is an example ,you should use screen width in your code
float margin = 10;
float itemsInRow = 4;
float widthRequest = (screenWidth - itemsInRow *2 * margin)/4;
Set the widthRequest to the item in Xaml, then the length of left space and right space will become same.
I add a image here to make it clear:
I solved this by using a template selector and adding a couple null items to the end of the collection. The template selector selects the regular template for the display items, and a template with an empty grid for null items. I created the collection in my view model by wrapping the observable collection and having my view model collection always present N more items as null values.
Related
There are too many items in the menu strip item.
Like this:
It looks very long and bad. I want to add a scroll bar to menu strip items.
I want to see 3 of these items with the help of the scroll bar.
How can I do it?
You can set the maximum height of a MenuItem's DropDown using the ToolStripMenuItem.DropDown MaximumSize property.
You can determine the height of the DropDown based on the maximum number of Items you want to show. Or any other measure that makes sense in your scenario (maybe a measure that fits the current ClientSize.Height of a Form).
To specify a height relative to a maximum number of sub items (here, maxSubMenuItems), sum the Height of the first maxSubMenuItems sub items and use this measure to set the MaximumSize property.
The standard (top and bottom) scroll buttons will appear.
Here, I'm using a maxHeight + (maxHeight / maxSubMenuItems) value, to add some space, at the top and bottom of the dropdown, otherwise a menu may not fit in and it also looks better :)
Insert this code in the Form's Constructor (after InitializeComponent()) or in Form.Load:
int maxSubMenuItems = 6;
if (toolStripMenuItem1.DropDownItems.Count > maxSubMenuItems) {
int maxHeight = toolStripMenuItem1.DropDownItems
.OfType<ToolStripMenuItem>()
.Take(maxSubMenuItems)
.Sum(itm => itm.Height);
toolStripMenuItem1.DropDown.MaximumSize =
new Size(toolStripMenuItem1.DropDown.Width, maxHeight + (maxHeight / maxSubMenuItems));
}
► This can come in handy when you have to show a list of sub-items that represent Fonts, for example. So you may want to show a string drawn using the Font name in the list. Or similar situations, when you have to present a single, potentially long, dropdown.
In other cases, try to limit the number of items per ToolStripMenuItem using sub menus.
I have a vertical WarpPanel that is populated with controls at runtime. The types and number of controls is determined at runtime. It works good with controls that have a fixed height, but controls that expand according to their contents (e.g. Listbox) often create a new column. I somehow need to force the panel to place the controls in the last column as the other, fixed height controls UNLESS the space available in the column is less than MinHeight of the control we are trying to place. Setting Height or MaxHeight for the controls is not an option.
The image below demonstrates the problem. The two listboxes' widths are the same, but instead of putting them in the same column, one of them ends up half-invisible.
Instead of that I would expect to get this:
Is there any way to implement this without making/using a custom panel?
Code:
**Panel:**
<WrapPanel x:Name="wp" Orientation="Vertical">
**Adding controls:**
private void AddControl(bool isListBox)
{
if (isListBox)
{
var lb = new ListBox();
lb.MinHeight = 310;
lb.Width = 310;
lb.MaxWidth = 310;
lb.MinWidth = 310;
wp.Children.Add(lb);
}
else
{
var cb = new ComboBox();
cb.Width = 310;
cb.MaxWidth = 310;
wp.Children.Add(cb);
}
}
The problem here is that the WrapPanel is always going to give the ListBox as much space as it wants, up to the available height in the WrapPanel. What you want to have happen is something more like a UniformGrid effect, but only for expanding Height elements in the column and only as long as the MinHeight constraint isn't violated. This gets a bit tricky, especially if you have other fixed height elements in-between the ListBox elements or other elements with different MinHeight constraints.
It's possible to do the computation, but I think you'll need to create a custom Panel to get this behavior. Basically, it would work like the WrapPanel code, but when you have variable height elements (elements whose Measure returns unbounded size in the wrap dimension), it needs to look at their MinHeight and accumulate these with the fixed Height elements in the same column, ultimately dividing the remaining non-fixed Height by the number of variable elements, to produce the height(s) that will be provided in the Arrange pass.
I am creating a custom control in C#, and want to have a grid cell that contains a ListBox, which can be hidden or shown as desired. Hiding it is easy, I just set the Width to zero, however when I want to show it, I need to know the width that the ListBox would like to use.
I thought that DesiredSize.Width would give me this vale, but it's always zero, even after calling Measure(). Here is the code I'm using to show the ListBox...
_lb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
_lb.Width = _lb.DesiredSize.Width;
Any ideas how I find the desired width?
If your ListBox is in the cell of a grid, give that grid column a name. Then in code, you can access the .ActualWidth property of that grid column and use that value to set the width of your ListBox.
That assumes of course that the width of your grid column is not set to Auto, because that would still give you a 0 value.
_lb.Width = myGridColumn.ActualWidth
You might need to subtract a little bit from the column width to make your control fit nicely.
EDIT
One thing that I've found is that the ListBox must have items added to it before it will return anything other than 0 when it is measured.
string myItem = "Don't ask for a bath in Athabaska";
_lb.Items.Add(myItem);
_lb.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
double width = _lb.DesiredSize.Width;
As long as the ListBox has already been added to the window/usercontrol/grid, the above code returns a value of 227.53 for the width variable; using my defaults for font family and size.
If the ListBox has not been added to the window, or it doesn't have any items in it, it will return 0 for the .DesiredSize.Width property.
Also, if the .Visibility property is set to Collapsed instead of Hidden, the width will be 0.
Don't set the width to 0 when starting. Leave the width alone initially, set the .Visibility to Hidden. It will render to the needed width, but won't be shown. Then you can measure it and start playing around with the width.
The aim
I would like to set such size for the DataGrid (standard, from WPF) so all cells (text) would be fully visible. I have window with DockPanel, with DataGrid in it, so when I resize the window, all nested widgets (DockPanel and DataGrid) are resized accordingly.
Example (edit-1)
Let's say you have window, 100 pixels wide and you have DataGrid with one column, which cell is "the quick brown fox..." (400 pixels wide). Thus the DataGrid should be resized to 400 pixels (probably more, because of padding) and the Window should be resized to 400 pixels too (also more, because of padding).
I didn't find any standard method to do it (AFAIK WPF provides way to clip the content to desired width, my problem is exactly opposite), so I come up with such ugly workaround, which does not work too well.
The workaround
iterate over DataGrid headers (assuming they are just strings) and compute width required for the text
iterate over DataGrid rows per each column (assuming they are TextBlock or TextBox) and compute the maximum width required for the text -- add horizontal paddings for TextBlock/TextBox and horizontal margins for DataGrid cell
sum all differences between DataGrid ActualWidth for columns and the maximum width computed in (2)
increase the window width by the difference computed in (3)
THE PROBLEM
I did several tests, and in some cases the computed width is too big (this is minor problem), for some cases is too small. The problem starts at its core procedure -- computing the required width for TextBox/TextBlock, computed width is always 1 unit less than it should be (if I set the width to computed one, 1 pixel from text is always clipped).
So which factor I am ignoring here? Or maybe better -- is there already some method to resize DataGrid to fit its content?
The code
Computing width required for text (here for TextBlock):
public static double TextWidth(this TextBlock widget, string text)
{
var formattedText = new FormattedText(text, // can use arbitrary text
System.Globalization.CultureInfo.CurrentCulture,
widget.FlowDirection,
widget.FontFamily.GetTypefaces().FirstOrDefault(),
widget.FontSize,
widget.Foreground);
return formattedText.Width+widget.Padding.Left+widget.Padding.Right;
}
Adjusting the Window size to fit DataGrid content (ugly_factor is ugly workaround ;-) since I didn't figure out how to fix it properly I set it to 1.3 and this way my window is "never" too small):
public static void AdjustWidthToDataGrid(this Window window, DataGrid dataGrid, double ugly_factor)
{
var max_widths = dataGrid.Columns.Select(it => window.TextWidth(it.Header as string)
* ugly_factor).ToArray();
foreach (var row in Enumerable.Range(0, dataGrid.Items.Count))
foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))
{
var cell = dataGrid.GetCell(row, col);
double width = 0;
if (cell.Content is TextBlock)
width = (cell.Content as TextBlock).TextWidth();
else if (cell.Content is TextBox)
width = (cell.Content as TextBox).TextWidth();
if (cell.Content is FrameworkElement)
{
var widget = cell.Content as FrameworkElement;
width = width + widget.Margin.Left + widget.Margin.Right;
}
max_widths[col] = Math.Max(max_widths[col],
width*ugly_factor+cell.Padding.Left+cell.Padding.Right);
}
double width_diff = 0;
foreach (var col in Enumerable.Range(0, dataGrid.Columns.Count))
width_diff += Math.Max(0,max_widths[col] - dataGrid.Columns[col].ActualWidth);
if (width_diff > 0)
window.Width = window.ActualWidth+ width_diff;
}
I just came out of the same problem where I had to give options in a data grid's column to fit its width as per the content of both header and cell. I used the following code:
private void FitToContent()
{
// where dg is my data grid's name...
foreach (DataGridColumn column in dg.Columns)
{
//if you want to size your column as per the cell content
column.Width = new DataGridLength(1.0, DataGridLengthUnitType.SizeToCells);
//if you want to size your column as per the column header
column.Width = new DataGridLength(1.0, DataGridLengthUnitType.SizeToHeader);
//if you want to size your column as per both header and cell content
column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Auto);
}
}
Also I provided an option on columns to fit as per the display (datagrid's width). for that I used the same code above with the following minor change:
column.Width = new DataGridLength(1.0, DataGridLengthUnitType.Star);
FOR ALL COLUMNS : Make sure you keep HorizontalScrollVisibility to Auto.
If I understood your question right and you want to:
A DataGrid where columns are as wide as it's widest content.
The DataGrid fits to its contents.
This can be achieved with databinding:
<DataGrid AutoGenerateColumns="False"
EnableRowVirtualization="True"
Height="111"
HorizontalAlignment="Left"
ItemsSource="{Binding}"
Margin="72,203,0,0"
Name="dataGrid"
RowDetailsVisibilityMode="VisibleWhenSelected"
VerticalAlignment="Top"
Width="{Binding Path=ActualWidth, ElementName=grid}">
<DataGrid.Columns>
<DataGridTextColumn x:Name="Column1"
Binding="{Binding Path=Something1}"
Header="Column1"
Width="Auto" />
<DataGridTextColumn x:Name="Column2"
Binding="{Binding Path=Something2}"
Header="Column2"
Width="*" />
</DataGrid.Columns>
</DataGrid>
Here the first column is as wide is needed and the second is spreaded space which is left. However the DataGrid's width is the same as Grid's widht that is around it, so the wanted outcome is achieved.
In my case, I found DataGrid use HorizontalAlignment="Stretch" VerticalAlignment="Stretch" in default, So I set it to
<DataGrid ItemsSource="{Binding Source}" Width="Auto" Height="Auto"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
Then works.
Marko's comment is the answer:
I'm at a bit of a loss with your resizing logic. First of all, if you set the window's SizeToContent="WidthAndHeight", then the window is shown to the full size of the datagrid. On the other hand, if you show a window at some predefined size, and you want to resize the window once the window is shown, then at that point resizing to the datagrid's desired with is very counter intuitive. Because the resizing will jump from say 100px to 400px, but what if I want to resize to only 250px... (asuming you resize by dragging the corner of the window)
SizeToCells is what worked for me. I like this because its in XAML and it's concise.
<DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="Name" Width="SizeToCells"/>
AutoGenarateColumns="False"
I have a listview with OwnerDraw = true and Details view mode.
I want when the list contains 3,4 or 5 items the height of each item to be listview.Height/3 ,4 or 5 without scrolling.
I know that the height of item depends on size of the font.
This doesn't work
listView.Font = new Font("Arial", listView.Height / nOfItems);
I draw the text at DrawItem event with constant font size: e.Graphics.DrawString(....).
What I do successfully is to adjust the height of the list view by assigning an image list with a dummy image with the appropriate height I want to have.
So e.g. to have rows with each 40 pixel high, I assign an image with 40 pixel height to the list view inside an image list.
You do not have to actually draw the image, it is sufficient to assign it and do owner drawing then. It looks like e.g. the list in the background of this screenshot (it is a CMS I wrote in .NET).
you r right.
actually when you change the ImageSize property in ImageList, i have seen the ImageList goes empty. so for your problem You have to refill the ImageList with desire ImageSize again. try it it could solve your problem.