Opening new UserControl in MainWindow erases all empty rows - wpf

Once I run the program, it opens a UserControl in my MainWindow. The UserControl is a Menu consisting of 3 buttons.
Image of the UserControl:
Menu
The code behind Main Window:
<Window
...
Title="MainWindow" Height="350" Width="525" SizeToContent="WidthAndHeight" >
<Window.DataContext>
<ViewModels:MainWindowViewModel />
</Window.DataContext>
<ContentControl Content="{Binding CurrentViewModel}"/> //Inserts a UserControl
The code behind Menu UserControl:
<UserControl
...
d:DesignHeight="90" d:DesignWidth="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100*"/> //Problem
<RowDefinition Height="100*"/>
<RowDefinition Height="100*"/> //Problem
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Margin="30,0" Content="First" Command="{Binding DataContext.SwitchToNextUserControl,
RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}, Mode=OneWay}" />
<Button Grid.Row="1" Grid.Column="1" Margin="30,0" Content="Second"/>
<Button Grid.Row="1" Grid.Column="2" Margin="30,0" Content="Third"/>
</Grid>
THE PROBLEM:
Once the menu is opened, the empty rows (those without buttons, first and third) get collapsed (or just height to 0?), as shown: Running program
I can get over it with setting MinHeight for every row, but it works only on pixels. I'd like them to work in the method of stars ("*"). I guess I could set their height from code behind (using stars), but just the thought of it makes me feel like I rub my right ear with left hand.
Also, once I click on the "First" button, some other UserControl is opened in the window, instead of the "Menu" one, and its rows are also collapsed. Just mentioning it.
So the question is, what should I do to make my UserControls appear just as they look in designer?

You should remove to SizeToContent="WidthAndHeight" from your window XAML.
This causes the height of the window to shrink to fit the size of the UserControl (and effectively the height of the middle Button).

Related

How can we show UWP user control on vertical-top edge of the parent window?

Following XAML in this Microsoft tutorial is showing too much gap between the top edge of the parent window and the UWP user control. Question: How can we make the user control align to the top edge of parent window? Remark: The VerticalAlignment="Top" in the StackPanel below does not help. This question is something similar to this post but in a different context.
<UserControl
x:Class="ClassLibUWP_inside_WPF.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:ClassLibUWP_inside_WPF"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:winui="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d"
d:DesignWidth="400" Height="329">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="211*"/>
<ColumnDefinition Width="189*"/>
</Grid.ColumnDefinitions>
<StackPanel Background="LightCoral" Grid.ColumnSpan="2">
<TextBlock>This is a simple custom UWP control</TextBlock>
<Rectangle Fill="Blue" Height="93" Width="100"/>
<TextBlock Text="{x:Bind XamlIslandMessage}" FontSize="50"></TextBlock>
<winui:RatingControl Height="32" />
</StackPanel>
</Grid>
</UserControl>
When you run the app built in the above tutorial, you get the following screen showing the above UWP user control:
I would instead like to display it as follows [notice about no gap between window title and the red stack panel]:
The UserControl has a fixed height that is smaller than the height of the window and thus is vertically centered in the window. Setting VerticalAlignment="Top" on the WindowsXamlHost should give what you want.

Caliburn Micro Message.attach does not consider changes of datacontext

This is a simplified example. I have a usercontrol that contains a "browse to folder" functionality, using a textbox and a button. Clicking the button would open up the browse-dialog, and would essentially fill in the textbox.
<UserControl x:Class="MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<!-- Folder -->
<TextBlock>Path</TextBlock>
<DockPanel LastChildFill="True" Grid.Column="1">
<Button DockPanel.Dock="Right" cal:Message.Attach="[Event Click] = [Action BrowseHotFolder()]" Content="..." HorizontalAlignment="Left" Width="25" Height="25" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Margin="0,0,5,0"/>
<TextBox Text="{Binding HotFolderPath, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}" />
</DockPanel>
</Grid>
I have a listbox that contains a number of objects. The selected object will be fed into this usercontrol as datacontext.
<Window>
...
<Listbox ItemsSource="{Binding Items, Mode=OneWay}" SelectedItem="{Binding SelectedItem}">
...
<view:MyUserControl DataContext="{Binding SelectedItem}" />
</Window>
Now, let's say I have two items in my listbox and I have the first one selected. I fill in "foo" in the textbox of MyUserControl. Then I select the second item, and fill in "bar". The databinding works fine, and both items have the correct values set. If I then click the browse button on the first one and select a folder, it will change the textbox of the first item to the selected path. However, if I select the second item, and browse to a folder it will ALSO change the first item's textbox.
My guess is that the message attach syntax does not call the browse action on the correct Item. It disregards the datacontext (currently selected item) and just uses the first one.
What can I do about this?
I think your guess is correct; the target used for the Message.Attach is the first data context bound, and does not update when the context is changed after the user selection.
We saw a similar problem with user controls switched in a content control - the fix was to specify cal:Action.TargetWithoutContext="{Binding}" on the button.
The issue is mentioned here by Rob Eisenberg:
https://caliburnmicro.codeplex.com/discussions/257005
I have made a workaround by changing
cal:Message.Attach="[Event Click] = [Action BrowseHotFolder()]"
to
cal:Message.Attach="[Event Click] = [Action BrowseHotFolder($datacontext)]"
Now, the BrowseHotFolder-method still is called on the wrong ItemViewModel, but weirdly $datacontext passes the correct ItemViewModel. In the method itself I now do:
public void BrowsePath(ItemViewModel context)
{
context.Path = _folderBrowsingService.Browse();
}
This is a workaround, but solves the problem.

WPF XAML ListView with ScrollBars

I have a ListView which is showing both scroll bars. To achieve that, I places my ListView within a Border located in a Grid like below:
<Window ...
MinWidth="600" MinHeight="500" Width="800" Height="500"
Topmost="True"
WindowStartupLocation="CenterScreen"
SizeToContent="Height" WindowStyle="None">
<Window.Resources>
<ResourceDictionary>
...
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" MinHeight="60"/>
<RowDefinition Height="48"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition Height="370"/> <-- THIS IS HARDCODED TO 370 BUT I NEED IT TO BE RESIZABLE
</Grid.RowDefinitions>
<Grid Margin="5,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="346*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MyName}" Grid.Column="1"
Style="{StaticResource MyNameStyle}" Margin="0,5,0,5" />
</Grid>
<Border BorderBrush="{StaticResource MyBrush}" Grid.Row="1" Grid.Column="0" >
<ListView
x:Name="lstMyListView"
Margin="0,0,0,0"
BorderBrush="Transparent"
ItemsSource="{Binding MyItems}"
SelectedIndex="0"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto">
...
...
</ListView>
...
...
</Border>
...
...
</Grid>
</Grid>
</Window>
This is all in a form that is resizable. Therefore, the ListView should also resize but it should do that only when user resizes the form. The problem with my hard coded value above is obvious, the ListView will not resize but stay at constant height=370.
I know I can set this to 370* but in that case, my List will resize to fit all items. I want to limit this so that resizing only occurs when user resizes the form. So, ListView should show scroll bars if there are more items and as the user resizes form, that scroll bar should go away if form is resized to height that can accommodate all items in ListView.
UPDATE:
Instead of hard coding the height to 370 above, I have tried setting the height to , Auto, and 370. All of these would expand the ListView (and therefore form, too) to accommodate all items in the ListView.
UPDATE 2:
Updated XAML to show whole tree structure.
UPDATE 3:
As per Rachel's suggestion, set hardcoded 370 to "*" in commented line above in XAML and that produces form resized so that the ListView fits all items in it. I added screenshot showing the form as it opens and a screenshot showing how it should look like when it opens. As you can see, it resizes hightwise to accomodate all itesm.
What I need is that form and ListView stay in their set size and resize only if user resizes the form.
If I understand your question correctly, you are saying the form loads as too large of a size because the ListView is growing to it's full height. If that's the case, remove the SizeToContent="Height" from the <Window> tag since it is making the window's initial height be equal to whatever height the content is, which includes the fully sized ListView.
By setting ScrollViewer.VerticalScrollBarVisibility="Visible" & MaxHeight="700"
scroll bar will be visible
MaxHeight to any value
Hi I think i have understand you. So, i am trying:
So, you want to have your ListView at least a height of 370 and then only resizes if the window resizes (increment and decrement of window size).
Setting MinHeight of 2nd RowDefinition could help
<Grid Grid.Row="1">
<Grid.RowDefinitions>
<RowDefinition Height="32"/>
<RowDefinition MinHeight="370"/> <!-- THIS IS HARDCODED....-->
</Grid.RowDefinitions>
.....
</Grid>
Thank you.

Wpf application with a fixed panel

I need to create a Wpf application with this type of navigation:
A main screen with a fixed top panel, and the rest of the window that acts as a container for other views. The container can be populated with 0 or 1 views - there's never a situation when 2 or more windows should be seen at the time in this container.
I've added this very childish drawing I made:
The top green panel is the navigation panel, and when pressing "A" button, I need viewA to be opened in the red part of the window.
Similarly, when pressing "B" button, I need viewB to be opened in the red part of the window instead of viewA.
My questions:
What objects should I use to represent viewA, viewB and the containing window? Are these Windows? Pages?
What is the best way of switching between viewA and viewB? I prefer avoiding loading both viewA and viewB (and any other view I'll have) into memory and just hide\show them..
Thanks.
You could put all the "Green" stuff in directly in your window and "Red" stuff (UserControl likely) inside a ContentControl and then bind the Content property of that to the red's stuff. So it'd be like this:
<Window x:Class="garbage.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--Green stuff-->
<Button Content="A" />
<Button Content="B" Grid.Column="1"/>
<ContentControl Grid.Row="1" Grid.ColumnSpan="2" Content="{Binding RedStuff}">
</ContentControl>
</Grid>

How to add a buttom that is always visible after a scrollviewer?

I have a ScrollViewer which includes a lot of content (datagrids, stackpanels, textboxes, labels, etc...), and outside of it I want to add a button (PRINT), and it is important that the button is not part of the ScrollViewer. My goal is that the top 90% of my screen is the scrollviewer and the bottom 10% is a "frozen panel" that always shows the PRINT button, and this should remain true when maximized and minimized.
After having a lo of problems with 'the property content is set more then once' I realized I need to add both my ScrollViewer and the Button inside another container, so far the only one that seems to work is GRID - but honestly after you read this if you have anything else to recommend I am open to suggestions, I only used GRID because it seemed to almost give me what I wanted.
This is my code right now:
[Code]
<Window DataContext="{Binding PrintView, Source={StaticResource Locator}}" Width="900">
<Grid Height="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollViewer Name="PrintView" Grid.Row="0" Height="Auto">
<StackPanel>
... a LOT of stuff ...
</StackPanel>
</ScrollViewer>
<Button Content="Print"
Margin="0,20,0,20"
Height="50"
Width="150"
FontSize="24"
FontWeight="Bold"
Grid.Row="1"
/>
</Grid>
</Window>
[Code]
When done like this my ScrollViewer doesn't have a Scrollbar so I see the first page but I cannot scroll down, also there is no PRINT button seen
One interesting test was to change the following:
<ScrollViewer Name="Apercu" Grid.Row="0" Height="600">
Now I see my scrollbar again (and I can scroll) and my PRINT button is beneth it and always visible (this is almost perfect) but when I maximumize my window the ScrollViewer stays 600 of height and as such well it doesn't acctually maximize (everything below the PRINT button is just white).
Any ideas? Is there another way I could specify my HEIGHTS or is there a different control I should be using (not GRID)?
Thanks,
Found it ...
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
And remove height from ScollViewer

Resources