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);
Related
I'm currently developing a plugin for Revit (BIM software) and I'm, trying to use WPF and Caliburn.Micro to show a window/dialog when I press a button of the plugin.
So like in the documentation, I have a bootstrapper:
public class Bootstrapper : BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<LocationPopupViewModel>();
}
}
}
A simple testing ViewModel:
namespace ExternalForms.ViewModels
{
public class LocationPopupViewModel : Screen
{
private int _horizontalLength;
private int _verticalLength;
public int HorizontalLength
{
get
{
return _horizontalLength;
}
set
{
_horizontalLength = value;
NotifyOfPropertyChange(() => HorizontalLength);
}
}
public int VerticalLength
{
get
{
return _verticalLength;
}
set
{
_verticalLength = value;
NotifyOfPropertyChange(() => VerticalLength);
}
}
}
}
And of course the window that I want to show:
<Window x:Class="ExternalForms.Views.LocationPopupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExternalForms.Views"
mc:Ignorable="d" WindowStartupLocation="CenterScreen"
ResizeMode="CanResizeWithGrip"
Title="gebied" Height="300" Width="410"
FontSize="16">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<!--Row 1-->
<TextBlock Text="Stel xxx in" FontWeight="DemiBold" Grid.Column="1" Grid.Row="1" FontSize="18"/>
<!--Row 2-->
<StackPanel Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Width="360" Margin="0, 0, 0, 20">
<TextBlock TextWrapping="Wrap">
Let op dat het gebied een maximale horizontale en verticale lengte mag hebben van 1 kilometer.
</TextBlock>
</StackPanel>
<!--Row 3-->
<TextBlock Text="Horizontaal" Grid.Column="1" Grid.Row="3"/>
<!--Row 4-->
<TextBox x:Name="HorizontalLength" Grid.Row="4" Grid.Column="1" MinWidth="100"/>
<!--Row 5-->
<TextBlock Text="Verticaal" Grid.Column="1" Grid.Row="5"/>
<!--Row 6-->
<TextBox x:Name="VerticalLength" Grid.Row="6" Grid.Column="1" MinWidth="100"/>
<!--Row 7-->
<StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="1" Margin="0, 20, 0, 0" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<Button x:Name="SubmitDimensions" IsDefault="True" Width="100" Height="30">OK</Button>
<Button IsCancel="True" IsDefault="True" Width="100" Height="30">Cancel</Button>
</StackPanel>
</Grid>
The function that is trying to show the window:
private void SetBoundingBox()
{
IWindowManager windowManager = new WindowManager();
LocationPopupView locationPopup = new LocationPopupView();
windowManager.ShowWindow(locationPopup, null, null);
}
But when I try to open the dialog in Revit, a window with an error pops up:
UPDATE:
My current project structure looks like this:
Assembly "UI" takes care of all the internal UI elements in Revit (so the buttons in Revit, even though there is currently only one).
The current button in Revit calls the "Get3DBAG" assembly, who does some tasks and eventually calls the "Location" assembly, which calls the Windowmanager.showwindow() method for the WPF views, which are in the "ExternalForms" assembly.
You problem lies in the following line.
LocationPopupView locationPopup = new LocationPopupView();
You are attemping to initialize an instance of View, instead of ViewModel. You should replace this with following.
LocationPopupViewModel locationPopup = new LocationPopupViewModel();
Caliburn Micro would resolve the corresponding View by itself using the naming convention.
Update : Based on Comment
From your comment, it looks like your View/ViewModels are in a different assembly. In that scenario, you need to ensure the assembly is included while Caliburn Micro searches for Views. You can do so by overriding SelectAssemblies method in Bootstrapper.
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
Assembly.GetExecutingAssembly()
// Ensure your external assembly is included.
};
}
You would be also interested to read more Custom Conventions using Caliburn Micro
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}");
}
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 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.
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.