I want to make a storyboard for RowDefinition changing the Height, and I found this to help me. The only problem when I want to create the class GridLengthAnimation, I cannot make it a AnimationTimeline. Is this because windows phone 8 does not support this?
In this case is there another work around for making a storyboard for RowDefinition?
Easiest way may be that you put grids to the rows, and animate their Height-property like this.
Here is the xaml:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Background="AliceBlue"
Grid.Row="0"
Height="100"
Tap="Grid_Tap"
CacheMode="BitmapCache" />
<Grid Background="AntiqueWhite"
Grid.Row="1"
Height="100"
Tap="Grid_Tap"
CacheMode="BitmapCache" />
<Grid Background="Aqua"
Grid.Row="2"
Height="100"
Tap="Grid_Tap"
CacheMode="BitmapCache" />
<Grid Background="Aquamarine"
Grid.Row="3"
Height="100"
Tap="Grid_Tap"
CacheMode="BitmapCache" />
</Grid>
And the cs:
private void AnimateHeight(Grid grid)
{
double newHeight = grid.ActualHeight == 100 ? 300 : 100; //select the height we want to animate
Storyboard story = new Storyboard();
DoubleAnimation animation = new DoubleAnimation();
animation.To = newHeight;
animation.Duration = TimeSpan.FromSeconds(0.5);
Storyboard.SetTarget(animation, grid);
Storyboard.SetTargetProperty(animation, new PropertyPath(Grid.HeightProperty));
story.Children.Add(animation);
story.Begin();
}
private void Grid_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
Grid grid = sender as Grid; //select the grid we tapped
AnimateHeight(grid);
}
Notice that I putted cachemode to bitmapcache all of the grids. That's not necessary, but gives more fluent animation, because static grids won't be redrawed again in each frame.
Related
I'm trying to get the positions of controls (buttons) but it keeps returning {0;0}. I'm sure there's an explanation for this, but I can't figure out why this happens.
I want the position of the control, relative to the window or a certain container. My buttons are arranged in another grid. Taking the margins of these buttons would just give 0,0 since they're all inside grid cells.
What I tried:
- var point = btnTest.TransformToAncestor(mainGrid).Transform(new Point());
- UIElement container = VisualTreeHelper.GetParent(btnTest) as UIElement;
Point relativeLocation = btnTest.TranslatePoint(new Point(0, 0), mainGrid);
I tried this with a grid as a parent and with a canvas. Everything I try gives me {0,0}. When I change the new Point parameters, the position does change. It stays the same as the parameters.
Small part of my XAML:
<Grid x:Name="mainGrid">
<Grid Name="buttonGrid" Margin="105,64,98.4,97.8">
<Grid.RowDefinitions>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button x:Name="btnTest" Grid.Row="0" Grid.Column="0" Content="Button" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="26" Height="29"/>
<Button x:Name="btnTest2" Grid.Row="1" Grid.Column="1" Content="Button" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top" Width="26" Height="29"/>
</Grid>
</Grid>
Your code works perfectly fine, it is the timing that is the issue. The UI elements must be drawn before the position can be retrieved.
The code sample below shows the point extraction running in the constructor with the result 0,0 and then running in the loaded event which returns the desired result 84,78.
<Window x:Class="WpfApp7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Grid x:Name="mainGrid">
<Button x:Name="btnTest" Content="TileButton" HorizontalAlignment="Left" Margin="84,78,0,0" VerticalAlignment="Top" Width="109" Height="103"/>
</Grid>
public MainWindow()
{
InitializeComponent();
GetPoint();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
GetPoint();
}
private void GetPoint()
{
var point = btnTest.TransformToAncestor(mainGrid).Transform(new Point());
UIElement container = VisualTreeHelper.GetParent(btnTest) as UIElement;
Point relativeLocation = btnTest.TranslatePoint(new Point(0, 0), mainGrid);
MessageBox.Show($"X = {relativeLocation.X} Y = {relativeLocation.Y}");
}
I apologize for the length of this post but this one bums me out for two days straight now. Consider the image below. On Mouseclick on one of the tiles 1-4 the tiles resize and a big tile 5 appears in the middle. Another mouseclick reverses the process.
First I tried to bind the width/height property of row- and columndefinitions directly. This didn't work at all. The current solution uses the width and height property of labels to get the resizing done. The code is as follows...
XAML:
....
<Grid Name ="MainGrid" Background="Crimson">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Name="LeftGrid" Grid.Column ="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1"/>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Column ="1" Grid.Row ="0" Background ="Cyan " Width="200" Name="HandleLeftTop" />
<Label Grid.Column ="0" Grid.Row ="1" Background ="Cyan " Width="200" Name="HandleLeftSideTop" />
<Label Grid.Column ="0" Grid.Row ="2" Background ="Cyan " Width="200" Name="HandleLeftSideBottom"/>
<Grid Grid.Column ="1" Grid.Row ="1" Background ="Green" MouseDown="Grid_MouseDown"> </Grid>
<Grid Grid.Column ="1" Grid.Row ="2" Background ="Yellow" MouseDown="Grid_MouseDown_1"></Grid>
</Grid>
<Grid Name="RightGrid" Grid.Column ="2">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1"/>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Column ="0" Grid.Row ="0" Background ="Cyan " Width="200" Name="HandleRightTop"/>
<Label Grid.Column ="1" Grid.Row ="1" Background ="Cyan " Width="200" Name="HandleRightSideTop"/>
<Label Grid.Column ="1" Grid.Row ="2" Background ="Cyan " Width="200" Name="HandleRightSideBottom"/>
<Grid Grid.Column ="0" Grid.Row ="1" Background ="Thistle " MouseDown="Grid_MouseDown_2"></Grid>
<Grid Grid.Column ="0" Grid.Row ="2" Background ="Tan " MouseDown="Grid_MouseDown_3"></Grid>
</Grid>
<Grid Name="MiddleGrid" Grid.Column ="1">
<Grid.RowDefinitions>
<RowDefinition Height="1"/>
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row ="0" Background ="Cyan " Width="200" Name="HandleMiddleTop" />
<Grid Grid.Column ="0" Grid.Row ="1" Background ="Tomato"/>
</Grid>
</Grid>
C#:
public partial class RTGraphControl : UserControl
{
private readonly RTGraphControlViewModel _viewModel;
public RTGraphControl()
{
InitializeComponent();
_viewModel = new RTGraphControlViewModel(this);
DataContext = _viewModel;
//.... Binding row heights etc...
var leftColumnWidthbindingElement = new Binding
{
Source = _viewModel,
Path = new PropertyPath("LeftColumnWidth"),
Mode = BindingMode.OneWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
HandleLeftTop.SetBinding(WidthProperty, leftColumnWidthbindingElement);
// same for right and middle column
_viewModel.Expanded = false;
}
}
public class RTGraphControlViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private readonly RTGraphControl _rt;
private bool _expanded;
private double _rowHeight;
private double _leftcolumnWidth;
private double _middlecolumnWidth;
private double _rightcolumnWidth;
public RTGraphControlViewModel(RTGraphControl rt)
{
_rt = rt;
}
public bool Expanded
{
get { return _expanded; }
set
{
_expanded = value;
double width = _rt.MainGrid.ActualWidth;
if (_expanded)
{
LeftColumnWidth = width*0.2;
RightColumnwidth = width*0.2;
MiddleColumnWidth = width*0.6;
}
else
{
LeftColumnWidth = width * 0.5;
RightColumnwidth = width * 0.5;
MiddleColumnWidth = width * 0;
}
OnPropertyChanged("Expanded");
}
}
public double LeftColumnWidth
{
get { return _leftcolumnWidth; }
set
{
_leftcolumnWidth = value;
OnPropertyChanged("LeftColumnWidth");
}
}
public double MiddleColumnWidth {...}
public double RightColumnwidth {...}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
This kind of works for the left and middle column but funnily enough it doesn't for the right column. The right column doesn't change its width at all. Another problem is that after initialization of the usercontrol actualwidth is set to 0. A workaround with .Measure and .Arrange didn't work.
Thanks in advance
Jon
You could define your XAML like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Column="0" Grid.Row="0" Background="ForestGreen" Margin="2"
MouseDown="OuterContainer_OnMouseDown" />
<Grid Grid.Column="2" Grid.Row="0" Background="LimeGreen" Margin="2"
MouseDown="OuterContainer_OnMouseDown" />
<Grid Grid.Column="0" Grid.Row="1" Background="Firebrick" Margin="2"
MouseDown="OuterContainer_OnMouseDown" />
<Grid Grid.Column="2" Grid.Row="1" Background="OrangeRed" Margin="2"
MouseDown="OuterContainer_OnMouseDown" />
<Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Background="DodgerBlue"
MouseDown="MiddleContainer_OnMouseDown" x:Name="MiddleContainer"
Visibility="Collapsed" Width="300" Margin="2" />
</Grid>
Then a little code-behind to show/hide the middle box:
private void OuterContainer_OnMouseDown(object sender, MouseButtonEventArgs e)
{
MiddleContainer.Visibility = Visibility.Visible;
}
private void MiddleContainer_OnMouseDown(object sender, MouseButtonEventArgs e)
{
MiddleContainer.Visibility = Visibility.Collapsed;
}
Hidden:
Showing:
The only caveat is that the middle box has a preset size (300, but you can change that), instead of 60%. Not sure what you're intending to do with it, so that may or may not be an issue.
Given the following XAML;
<Grid>
<Grid.RowDefinitions>
<RowDefinition MinHeight="100"/>
<RowDefinition Height="2"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Background="LightBlue">
<Button Height="30"
Click="Button_Click">Hide Lower Panel</Button>
</Border>
<GridSplitter Grid.Row="1"
ResizeDirection="Rows"
Width="Auto"
HorizontalAlignment="Stretch"
Margin="0"
x:Name="Splitter"/>
<Border Grid.Row="2"
Background="LightCoral"
x:Name="LowerPanel" MinHeight="25"/>
</Grid>
Where Button_Click is;
this.LowerPanel.Visibility = this.LowerPanel.Visibility == Visibility.Visible
? Visibility.Collapsed
: Visibility.Visible;
This looks like this;
If the button is clicked before doing anything else, then it collapses as expected;
However, if I resize using the grid splitter..
Then when I press the button, the following happens;
Is there any way to make the lower element collapse correctly again after it has been resized?
Note: for the purposes of this question I've just used code-behind event handers and a button to trigger this, but in real-life it's done in the proper MVVM way with the visibility being determined by a bound property on the view model.
AFAIK, when GridSplitter is used, its rewrites the Height or Width properties of the corresponding RowDefinitions and ColumnDefinitions. In order to do what you want, you should to play with RowDefinitions.Height property, like this:
public MainWindow()
{
InitializeComponent();
//gr is the name of the Grid
basepr1 = gr.RowDefinitions[0].Height;
basepr2 = gr.RowDefinitions[2].Height;
}
static GridLength zero = new GridLength(0);
GridLength basepr1;
GridLength basepr2;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (this.LowerPanel.Visibility == Visibility.Visible)
{
this.LowerPanel.Visibility = Visibility.Collapsed;
basepr2 = gr.RowDefinitions[2].Height; // remember previos height
gr.RowDefinitions[2].Height = zero;
}
else
{
this.LowerPanel.Visibility = Visibility.Visible;
gr.RowDefinitions[2].Height = basepr2;
}
}
I think you need to mark one of the row definitions as '*':
<Grid.RowDefinitions>
<RowDefinition MinHeight="100"/>
<RowDefinition Height="2"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
I have this Grid in my WPF application :
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="70" Name="BarRowDef" />
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Name="BarGrid" Grid.Row="0" Height="70" VerticalAlignment="Top" Background="#FF802C2C">
<Button Content="History" Focusable="False" Width="100" Height="60" HorizontalAlignment="Left" VerticalAlignment="Center" Name="HistoryButton" Click="HistoryButton_Click"/>
</Grid>
<Grid Name="MiddleGrid" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<WebBrowser HorizontalAlignment="Stretch" Name="Browser" VerticalAlignment="Stretch" LoadCompleted="Finish_Load" Grid.Column="1"/>
</Grid>
</Grid>
And i want to the browser will have full screen option. So what i done is in the event Of EnterFullscreen is called is :
BarRowDef.Height = new GridLength(0);
And what happen is that the Browser start from the top of the page but in the bottom i have a white space in the size of BarGrid.
Any idea what can be the problem?
Edit
This is the full EnterFullScreenMode method :
public void EnterFullScreenMode()
{
BarRowDef.Height = new GridLength(0);
if (this.WindowState == System.Windows.WindowState.Maximized)
{
this.WindowState = System.Windows.WindowState.Normal;
}
this.WindowStyle = System.Windows.WindowStyle.None;
this.WindowState = System.Windows.WindowState.Maximized;
IsFullScreen = true;
}
I believe setting to Visibility.Hidden can still result in some whitespace being rendered.
You can set the content of the row (BarGrid) to Collapsed, which means: "Do not display the element, and do not reserve space for it in layout".
BarGrid.Visibility = Visibility.Collapsed;
Edit: Additional details from comments
Also ensure the height setting removed from the RowDefinition.
Instead of:
<RowDefinition Height="70" Name="BarRowDef"/>
Use:
<RowDefinition Height="Auto"/>
I am not sure what do you mean, EnterFullscreen event of what?
You can try this:
BarGrid.Visibility = Visibility.Hidden;
instead of:
BarRowDef.Height = new GridLength(0);
I have a XAML with 2 columns in a Grid and I have a button that when I click it, in the code behind, I set the visibility to collapse, and want to resize the other half of the screen to try to take up the whole screen. The collapsing part works, and the RHS then shifts over to the LHS, but it does not take up the entire screen. I tried using both the Auto and Star to resize in HidePlots, but it never takes the full screen. I thought if I collapsed the LHS, and set the column to * for the RHS, it would take up the whole screen. Any thoughts? Thanks.
Here's some code to make it more clear:
<Grid Grid.Row="1" x:Name="ExpandableGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="1.5*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" x:Name="TableGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Grid.Column="0" x:Name="SampleViewGroupBox" Header="SampleView" HorizontalAlignment="Stretch" FontFamily="Arial" FontSize="12" Margin="5,0,5,0" >
<ContentControl Content="{Binding LayoutManager.SampleView}" Height="Auto" Width="Auto"/>
</GroupBox>
<Button x:Name="TableButton" HorizontalAlignment="Right" Content="Button" Width="15" Height="15" VerticalAlignment="Top" Margin="0,0,-2,0" Click="MaxButton_Click" Grid.Column="0" Grid.Row="0"/>
</Grid>
<Grid Grid.Column="1" x:Name="BaseViewGrid">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<GroupBox Grid.RowSpan="2" Grid.Column="1" Name="BaseViewGroupBox" Header="PLOTS" Margin="5,0,5,0" >
<ContentControl Content="{Binding LayoutManager.ConsensusView}" Height="Auto" Width="Auto" />
</GroupBox>
</Grid>
</Grid>
private void MaxButton_Click(object sender, RoutedEventArgs e)
{
UIElement senderElement = (UIElement)sender;
if (_tableMinimized)
{
HideTables(false);
_tableMinimized = false;
((Button)senderElement).Style = (Style)FindResource("DashboardDetailsButton");
}
else
{
HideTables(true);
_tableMinimized = true;
((Button)senderElement).Style = (Style)FindResource("DashboardDetailsButtonReverse");
}
}
private void HideTables(bool hide)
{
if (hide)
{
foreach (UIElement child in TableGrid.Children)
child.Visibility = Visibility.Collapsed;
for (int i = 0; i < ExpandableGrid.ColumnDefinitions.Count; i++)
ExpandableGrid.ColumnDefinitions[i].Width = GridLength.Auto;
ExpandableGrid.ColumnDefinitions[1].MinWidth = 500;
for (int i = 0; i < ExpandableGrid.RowDefinitions.Count; i++)
ExpandableGrid.RowDefinitions[i].Height = GridLength.Auto;
TableButton.Visibility = Visibility.Visible;
}
else
{
foreach (UIElement child in TableGrid.Children)
child.Visibility = Visibility.Visible;
for (int i = 0; i < ExpandableGrid.ColumnDefinitions.Count; i++)
ExpandableGrid.ColumnDefinitions[i].Width = new GridLength(1, GridUnitType.Star);
for (int i = 0; i < ExpandableGrid.RowDefinitions.Count; i++)
ExpandableGrid.RowDefinitions[i].Height = new GridLength(1, GridUnitType.Star);
}
}
Edit: I tried to also change one line to:
ExpandableGrid.ColumnDefinitions[1].MinWidth = System.Windows.SystemParameters.PrimaryScreenWidth-20;
instead of the hard-coded 500 value, it looks correct. However, if I try to click the button again to revert back to normal, the RHS takes up the bulk of the screen without getting back to its original position.
Your current column definition says to make Column B equal to 1.5 times the size of Column A, so even if ColumnB's content is hidden, the column will still take up 3/5 of the screen.
Change it so the column that collapses has a Width="Auto", and set it's Content's Width equal to whatever size it should be when it's expanded. If you want to keep the 1.5* default width, I'd recommend using something like a MathConverter to figure out what size it should be based on the parent Grid's width. I have the code for one posted here
<Grid x:Name="ParentGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid x:Name="RHS" Grid.Column="0" />
<!-- Collapse this Grid -->
<Grid x:Name="LHS" Grid.Column="1"
Width="{Binding ElementName=ParentGrid, Path=ActualWidth,
Converter={StaticResource MathConverter},
ConverterParameter=((#VALUE/5)*3)}" />
</Grid>
You need to set column 0 to be whatever you desire (Auto, 150, etc...) and set column 1 to be *.
It looks like your Grid is also within a Grid, so the parent's behavior also has to be taken into account.