Image in one column is expanding to the second column - c#

I have defined a grid with some rows and two columns
In [0,0] I have placed an image with main attributes as below:
HorizontalAlignment="Left" VerticalAlignment="Center"
Stretch="None" Margin="10 0 0 0" Width="260"
And in [0,1] I have placed a label with some text in it with some main attributes like this:
HorizontalContentAlignment="Left" HorizontalAlignment="Left" Width="36" FontSize="16"
My question is why if I remove the width = 260 from image field then suddenly also the label in next column is disappearing? I think the image expands and covers it. But why? Shouldn't it be limited to its own [0,0] cell?

Your columns are autosizing to the size of their contents, so I would guess that your image in (0,0) isn't actually spreading into column 1 it is just that column 0 is growing so large that you can't see column 1 anymore.
If you make the column size * you will constrain it to the available space. As someone else said, you can use ShowGridLines to help debug what is going on with your columns, especially if you add a second row just to see where the division between your columns is.

Related

Xamarin.Forms FlexLayout resize to a max value

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.

Why Border disappear when setting big Width?

I resize the border according to timeline. Why when the Width becomes very big the Border disappear. For example for Width=100000 the Border is visible but for Width=200000 the Border disappears.
<StackPanel>
<Border BorderThickness="0,0,0,1" BorderBrush="Black" Height="100" Width="1000000">
</Border>
</StackPanel>
It turns out, that there are some limitations on the Border setting BorderThickness property.
Unfortunately, I can not say exactly how they look, I tried to find them using ILSpy (you can try to look for them am).
One limitation I can say: if the value of one coordinate over 125,000 the line of Border disappears. Here is my list of examples:
Thickness Width
--------- ---------
0,0,0,1 125 001
0,0,0,2 251 000
0,0,0,3 375 001
0,0,0,4 501 000
In all these cases, the line is not drawn.
As an alternative, you can increase the value for Thickness each time (not varinat), or using a Line / Separator, for them, there should be no restrictions. You need to change the value of Margin, depending on conditions or setting the Visibility for him.
Example with Separator:
<Separator Name="HighSignal"
Width="1000000"
Background="Black"
Height="2"
Visibility="Collapsed"
Margin="0,100,0,0" />
<Separator Name="LowSignal"
Width="1000000"
Background="Black"
Height="2"
Visibility="Visible"
Margin="0,0,0,0" />
Note: For Separator you may create a Style, because for him base type a Control (for Line -Shape).

the display word gets cut off 1 position

In the following code, there is a column that gets displayed called
'All day event' for some reason here the 't' is getting cut off. can you point me if there is any value here too large that would cause this?
<dxe:CheckEdit x:Name="chkAllDay" Margin="0,6,202,4" Grid.Column="2"
Content="{Binding Source={StaticResource SchedulerControlStringIdConverter},
ConverterParameter=Form_AllDayEvent,
Converter={StaticResource SchedulerControlStringIdConverter}}"
EditValue="{Binding Controller.AllDay}" IsReadOnly="{Binding ReadOnly}"
IsEnabled="True" HorizontalAlignment="Right" Width="81" />
Your CheckEdit has its Width fixed to 81 pixels and also fixed Margins*. From your code snippet I cannot guess how the whole layout looks, but be sure to re-calculate those values. Maybe you've just accidentally got 5px off and the remaining area is too small for the text?
*) I said about Margin, but I've mistaken them with Padding. Margin is not relevant here, they it's the outer spacing' and does not count to the Width. OTOH, the Padding would. I think here's one good explanation

How to implement youtube sparkbars like control in WPF

Youtube has a nice control for votes like below screenshots,
Is there anything similar in WPF already or if I need to do it by myself, how to do it? I'm new to WPF, XAML and all, so I have this question.
I am not familiar that anything exactly like this already exists, there are Sparkline controls in some of the proprietary controls such as Telerik RadControls, but nothing exactly the same to the YouTube votes.
But it should be easy enough to create your own control using XAML.
Let's take a look, the control exists from 3 labels, a line that shows progress and two icons. To position this elements in a WPF user control, you can use a grid with three rows and two columns.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid>
</Grid>
The labels are then placed into first and last rows using the XAML attributes Grid.Row and Grid.Column. The icons in last row can be placed using a StackPanel or just creating more columns, do as you wish. Everything here is easy.
The problem is the spark line, which I suggest you create two rectangles placed on top of one another. Both should go into second row, and span through all columns, you can achieve this using Grid.ColumnSpan attribute. First rectangle represents the background, so choose a light color for it. The second one represents the actual vote counter and should be colored red or green, depending on the votes.
Give all elements a name and you are finished with XAML (except minor corrections such as Margins and Horizontal or Vertical Alignments).
In code, create three properties for user control, all of type Integer (int). One for view count and two for up and down votes. Those properties can either be bound to labels in XAML, or you can update the values manually. Read more about Data binding here: http://wpftutorial.net/DataBindingOverview.html
To correctly place the rectangle that displays vote counter, you should just calculate the percentage of upvotes based on the properties, use the following code for help:
double percentage = UpvoteCount / (double)(UpvoteCount + DownvoteCount);
Note that I cast the sum to double, to keep percentage a floating point number (or you would always get a zero). From here all you need to do is to rescale the width of the rectangle to the appropriate percentage, considering that the background rectangle spans 100%. You can do this with the following code:
voteProgress.Width = percentage * voteBackground.ActualWidth;
In this case voteProgress and voteBackground are the names of your rectangles. Youtube also uses different colors, which you can change based on your calculated percentage:
if (percentage > 0.5)
voteProgress.Fill = new SolidColorBrush(Colors.Green);
else
voteProgress.Fill = new SolidColorBrush(Colors.Red);
The percentage MUST be calculated each time the size of the control changes (or number of votes), so look into SizeChanged event.
For more information and details, please read WPF tutorial, courtesy of Christian Moser.
http://wpftutorial.net

How to resize WPF DataGrid to fit its content?

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"

Categories