WPF Expander expand behind the grid row - wpf

I have expander control in grid row. And I change the expander size on the expander button click to maximize the expander size. And on the collapse status I minimize the expander size. The problem is the expander expands under the grid row.
Is there is any way to make the expander expand on top of any control?
<Grid AllowDrop="False">
<Grid.RowDefinitions>
<RowDefinition Height="199*" />
<RowDefinition Height="175*" />
</Grid.RowDefinitions>
<Grid Height="60" HorizontalAlignment="Left" Margin="21,26,0,0" Name="grid1" VerticalAlignment="Top" Width="550" Background="#FFE59E9E">
<Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="62,113,0,0" Name="label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="130,115,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Background="#FF2B1313" />
</Grid>
<Expander Name="exp" Expanded="exp_Expanded" Background="#FF3383A7" BorderThickness="4" BorderBrush="{x:Null}" FlowDirection="LeftToRight" Collapsed="exp_Collapsed" ExpandDirection="Left" Height="49" VerticalAlignment="Top" HorizontalAlignment="Right" Width="602" Margin="0,139,237,0">
<DataGrid AutoGenerateColumns="False" Height="105" Name="dataGrid1" Width="200" HorizontalContentAlignment="Center" VerticalAlignment="Center" />
</Expander>
</Grid>
private void exp_Expanded(object sender, RoutedEventArgs e)
{
var exp = (Expander) sender;
//grid1.Width = 550;
// grid1.Height = 40;
exp.Width = 602;
exp.Height = 300;
}
private void exp_Collapsed(object sender, RoutedEventArgs e)
{
var exp = (Expander)sender;
// grid1.Height = 500;
exp.Width = 602;
exp.Height = 49;
}

This is because you have set Grid.RowDefinition for you Grid control and didnt set the Grid.Row property for child controls
if not required remove the below code in you xaml
<Grid.RowDefinitions>
<RowDefinition Height="199*" />
<RowDefinition Height="175*" />
</Grid.RowDefinitions>
or
Add Grid.RowSpan property for your expander
<Expander Grid.RowSpan="2" Name="exp" Expanded="exp_Expanded"...
You can check WPF Tutorial for Grid Panel for more details on how to rows and columns for Grid Panel

Related

Expand/Collapse grid column on WPF expander click event

I have a MVVM application. In main window I have put below grid with 2 columns. In column 2 I have placed an WPF expander and I set it as collapsed by default (IsExpanded="False"). When application executes I would like grid column 1 to fill the entire width of the grid and grid column 2 with width 0 (collapsed). So when I click in the expander I want grid column 2 to expand to take 0.47* of width. Then if I click the expander again, I would like grid column 1 to fill the entire width of the grid and grid column 2 to be collapsed (width=0). How can I do this? Below code is not working.
<Grid x:Name="Grid">
<Grid.RowDefinitions>
<RowDefinition Height="47.5*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="0.47*" />
</Grid.ColumnDefinitions>
<controls:UCIndicationsOfUse Grid.Row="0" Grid.Column="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="auto"
Height="auto"
DataContext="{Binding}" />
<controls:UCPData Grid.Row="1" Grid.Column="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="auto"
Height="auto"
DataContext="{Binding}" />
<Expander Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Width="25"
ExpandDirection="Left"
IsExpanded="False"
HorizontalAlignment="Right">
<Expander.Header>
<TextBlock Text="Settings">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-90"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Expander.Header>
</Expander>
Finally I have added Collapsed and Expanded events to the expander:
<Expander Grid.Row="0"
Grid.RowSpan="2"
Grid.Column="1"
Width="25"
Collapsed="Expander_Collapsed"
Expanded="Expander_Expanded"
ExpandDirection="Left"
IsExpanded="False"
HorizontalAlignment="Right">
<Expander.Header>
<TextBlock Text="Settings">
<TextBlock.LayoutTransform>
<RotateTransform Angle="-90"/>
</TextBlock.LayoutTransform>
</TextBlock>
</Expander.Header>
</Expander>
And then from view code-behind:
private void Expander_Collapsed(object sender, RoutedEventArgs e)
{
ColumnDefinition c = this.Grid.ColumnDefinitions[1];
c.Width = new GridLength(0, GridUnitType.Auto);
this.Grid.ColumnDefinitions.RemoveAt(1);
this.Grid.ColumnDefinitions.Insert(1, c);
}
private void Expander_Expanded(object sender, RoutedEventArgs e)
{
ColumnDefinition c = this.Grid.ColumnDefinitions[1];
c.Width = new GridLength(0.47, GridUnitType.Star);
this.Grid.ColumnDefinitions.RemoveAt(1);
this.Grid.ColumnDefinitions.Insert(1, c);
}
I think this not break MVVM pattern since it is a task for the view.

xaml window doesnt center

I have a xaml (window) control which contains a grid and inside that grid, two stackpanel. The second stackpanel is set to "collapsed" per visibility. When the form loads and the button on the form is clicked, the xaml window shows up centered by setting WindowStartupLocation="CenterScreen". But when the button on the xaml is clicked to set the second stackpanel's visibility to visible, it doesn't center no more. Can anyone help resolve this issue or tell me on how to fix this?
Update: After looking closely at this, I think it may be because the visibility is set to collapsed? I've tried instead of collapsed, hidden, and it centered it but with the column being shown empty as it's used by the stackpanel.
Here are the codes:
Form1.cs
public Form1()
{
InitializeComponent();
this.StartPosition = FormStartPosition.CenterScreen;
}
private void button_Click(object sender, EventArgs e)
{
MainWindow childWindow = new MainWindow();
childWindow.Show();
}
MainWindw.xaml
<Window x:Class="ChildProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:ChildProject"
Title="MainWindow"
Width="Auto"
Height="Auto"
SizeToContent="WidthAndHeight"
AllowsTransparency="False"
ResizeMode="NoResize"
WindowStyle="None"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<StackPanel x:Name="stkpnlMain"
Grid.Column="0"
Grid.Row="0"
Orientation="Vertical">
<Label Content="This is suppose to display message on right ..."
FontStyle="Italic"
FontWeight="Bold"/>
<Button Content="Click Me"
Width="75"
Margin="5" Click="Button_Click" />
</StackPanel>
<StackPanel x:Name="stkpnlDisplay"
Grid.Column="1"
Grid.Row="0"
Margin="5,0,0,0"
Orientation="Vertical"
Background="YellowGreen" Visibility="Collapsed" >
<Label Content="... First now shows ..."
BorderBrush="Black"
BorderThickness="1"
Background="Yellow" />
<Label Content="Hopefully this will work"
BorderBrush="Red"
BorderThickness="3"
Margin="0,5"
Background="White" />
</StackPanel>
</Grid>
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
stkpnlDisplay.Visibility = Visibility.Visible;
}

WPF: Layout dynamic content so that there's only a scrollbar if necessary, otherwise content expands to fill space

I'm trying to layout a set of TextBoxes, vertically, one on top of the other. If there are so many TextBoxes that they cannot fit within the Window height then I want a ScrollBar to become available on the Window. The number of input TextBoxes is variable. There is always a last TextBox with the name output.
If all the TextBoxes can appear within the Window height then I want the last TextBox to stretch to the bottom and fill all the remaining space. In addition, if the output TextBox has a lot of Text then I want this TextBox to make a ScrollBar available.
Here's some pseudo XAML of what I have:
<ScrollViewer>
<Grid>
<TextBox Name="input1" Margin="12, 12, 12, 12" VerticalAlignment="Top" HorizontalAlignment="Left" />
<TextBox Name="input2" Margin="12, 60, 12, 12" VerticalAlignment="Top" HorizontalAlignment="Left" />
<TextBox Name="input3" Margin="12, 108, 12, 12" VerticalAlignment="Top" HorizontalAlignment="Left" />
...
<TextBox Name="inputN" Margin="12, ((N - 1) * 48 + 12), 12, 12" VerticalAlignment="Top" HorizontalAlignment="Left" />
<TextBox Name="ouput" Margin="12, (N * 48 + 12), 12, 12" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</Grid>
</ScrollViewer>
The problem I have right now is that if the output TextBox has a lot of content then it increases in height and has the Window present a ScrollBar. Instead I want the output TextBox to get the ScrollBar.
I can fix that problem by removing the ScrollViewer that is holding the Grid. However if I do that I get another problem. Because the number of input TextBoxes is variable, if there are so many that not all the TextBoxes can show in the Window, the Window doesn't get a ScrollBar, which I need.
I have tried playing around with putting a MaxHeight on the output TextBox, but if there are few input TextBoxes and a tall Window then I'm apt to not fill all of the remaining vertical space.
It sounds like you need to wrap your Output TextBox in a ScrollViewer and also assure it does stay in the bottom (defining some rows in the Grid or docking it to the bottom of a DockPanel.
EDIT: Do you need something like this?
<Grid x:Name="grd01">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="1">
<TextBox HorizontalAlignment="Stretch" TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
SECOND EDIT:
<Grid x:Name="grd01">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<ScrollViewer Grid.Row="0">
<StackPanel>
<TextBox x:Name="input"
HorizontalAlignment="Stretch"
TextWrapping="Wrap" />
</StackPanel>
</ScrollViewer>
<ScrollViewer Grid.Row="1">
<TextBox x:Name="output"
HorizontalAlignment="Stretch"
TextWrapping="Wrap" />
</ScrollViewer>
</Grid>
you can use this tweak on the window loaded event with this code:
EDIT:
i modified it so it's even correct if resizing now
private void Window_Loaded(object sender, RoutedEventArgs e)
{
output.MaxHeight = output.ActualHeight;
output.VerticalAlignment = VerticalAlignment.Top;
output.Height = output.MaxHeight;
}
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
output.MaxHeight = output.MinHeight = output.Height = outGrid.ActualHeight;
}
-
<ScrollViewer Height="Auto">
<DockPanel>
<StackPanel DockPanel.Dock="Top" >
<TextBox VerticalAlignment="Top" HorizontalAlignment="Stretch" />
<TextBox VerticalAlignment="Top" HorizontalAlignment="Stretch" />
<TextBox VerticalAlignment="Top" HorizontalAlignment="Stretch" />
<TextBox VerticalAlignment="Top" HorizontalAlignment="Stretch" />
<TextBox VerticalAlignment="Top" HorizontalAlignment="Stretch" />
<TextBox VerticalAlignment="Top" HorizontalAlignment="Stretch" />
</StackPanel>
<Grid DockPanel.Dock="Bottom" Name="outGrid">
<TextBox Name="output" TextWrapping="Wrap" AcceptsReturn="True" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" VerticalAlignment="Stretch" />
</Grid>
</DockPanel>
</ScrollViewer>

Is there a RowSpan="All" in WPF?

I create a GridSplitter across the 3 rows that I have in my grid like this:
<GridSplitter Grid.Row="0" Grid.Column="1" Background="Yellow"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="Auto" Height="Auto" ResizeDirection="Columns"
Grid.RowSpan="3" ...
However, it's conceivable that I might add another row to my grid at a later stage, and I don't really want to go back and update all of my rowspans.
My first guess was Grid.RowSpan="*", but that doesn't compile.
A simple solution:
<!-- RowSpan == Int32.MaxValue -->
<GridSplitter Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2147483647" />
You can bind to the RowDefinitions.Count but would need to update the binding when adding rows manually.
Edit: Only semi-manually in fact
Xaml:
<StackPanel Orientation="Vertical">
<Grid Name="GridThing">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Children>
<Button Content="TopRight" Grid.Row="0" Grid.Column="1"/>
<Button Content="LowerRight" Grid.Row="1" Grid.Column="1"/>
<Button Content="Span Rows" Name="BSpan" Grid.RowSpan="{Binding RelativeSource={RelativeSource AncestorType=Grid}, Path=RowDefinitions.Count, Mode=OneWay}"/>
</Grid.Children>
</Grid>
<Button Click="Button_Click" Content="Add Row" />
</StackPanel>
Code:
private void Button_Click(object sender, RoutedEventArgs e)
{
GridThing.RowDefinitions.Add(new RowDefinition() { Height = new GridLength(20) });
foreach (FrameworkElement child in GridThing.Children)
{
BindingExpression exp = child.GetBindingExpression(Grid.RowSpanProperty);
if (exp != null)
{
exp.UpdateTarget();
}
}
}
The Grid control provides nothing like this out of the box. It's conceivable that you could implement a MarkupExtension or some other trickery to enable this.

Drag and drop between ListBox items and Grid cells in WPF?

There is a list box with some items in it. Also there is a grid with 3x3 matrix. The user will be dragging an item and dropping on one the cells of grid.
Most of the samples I found are about dragging-dropping from one listbox to another listbox. But I want to drop in one cell of grid. How can I achieve this?
Please advise. thanks
PJ
pls, check if an example below would work for you:
xaml:
<Grid>
<ListBox Height="100" HorizontalAlignment="Left" Margin="56,65,0,0"
Name="listBox1" VerticalAlignment="Top" Width="120"
PreviewMouseLeftButtonDown="listBox1_PreviewMouseLeftButtonDown">
<ListBoxItem Content="one" />
<ListBoxItem Content="two" />
<ListBoxItem Content="three" />
</ListBox>
<Grid Height="100" HorizontalAlignment="Left" Margin="238,65,0,0" Name="grid1"
VerticalAlignment="Top" Width="200" ShowGridLines="True" TextBlock.Drop="grid1_Drop">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" AllowDrop="True"></TextBlock>
<TextBlock Grid.Row="0" Grid.Column="1" AllowDrop="True"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" AllowDrop="True"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="1" AllowDrop="True"></TextBlock>
</Grid>
</Grid>
code:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void listBox1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
object item = listBox1.SelectedItem;
if (item != null)
DragDrop.DoDragDrop(listBox1, item, DragDropEffects.Move);
}
private void grid1_Drop(object sender, RoutedEventArgs e)
{
TextBlock textBlock = e.Source as TextBlock;
Console.WriteLine("drop item into grid column:{0} row:{1}",
Grid.GetColumn(textBlock), Grid.GetRow(textBlock));
DataObject item = (((DragEventArgs)e).Data) as DataObject;
ListBoxItem listItem = item.GetData(typeof(ListBoxItem)) as ListBoxItem;
textBlock.Text = listItem.Content.ToString();
}
}
hope this helps, regards

Resources