Complex controls in a Popup - wpf

I am building a control allowing to manage some items and select one.
It comprises a TextBox and a Button allowing to open a Popup where it all happens.
I would like to have a list of items with details in a System.Windows.Controls.Primitives.Popup class. I am using a Grid with 2 columns, the first one contains the list of items, the second one its details.
Now I want to use a System.Windows.Controls.GridSplitter control to allow the user to resize the area of details.
The problem is that this works everywhere except of inside a Popup control.
My question is, should I use some other control simulating Popup's behavior (Window..) or is there any other way to achieve this.
EDITED:
If I set Width Property of the Popup it works, because the Popup is not trying to adapt to its content. But I want to preserve this behaviour..
What I'm planning is to add complex animations to the controls in the Popup as well.
CODE:
...
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBox Grid.Column="0" Grid.Row="0" Text="Selected Item" />
<ToggleButton Grid.Row="0" Grid.Column="1" Focusable="False">
<Grid>
<TextBlock Text="Select" />
<Popup StaysOpen="False" Width="700" VerticalAlignment="Bottom" IsOpen="{Binding Path=IsChecked,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton, AncestorLevel=1},
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" PlacementTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ToggleButton, AncestorLevel=1}}">
<local:MyManagementControl />
</Popup>
</Grid>
</ToggleButton>
</Grid>
...
MyManagementControl contains:
...
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ListView Grid.Row="0" Grid.Column="0">
...
</ListView>
<GridSplitter Grid.Column="0" Width="10" HorizontalAlignment="Right" VerticalAlignment="Stretch" />
<Grid Grid.Row="0" Grid.Column="1">
...Details...
</Grid>
</Grid>
...

Related

Grid rows aren't the (relative) height I set them to

I was working on a UserControl in a View, when I came across this problem:
I set my content grids row heights to be 2*, 1* and 1* with the lines in between set to auto.
Now. The uppermost row has a grid nested in with a TextBlock and a TextBox. The height of the cell is in no way 2*. It looks like it would look if I had set it to auto. I'm pretty sure the other 2 content rows (containing buttons) are the right height either.
Now I hope you guys can help me fix this. I've googled around a bit and I can't seem to find a fitting solution.
Here's the code:
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="TBCustomerTitle" Margin="0,0,8,0" FontWeight="Bold"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}">Customer:</TextBlock>
<TextBox Name="TBCustomerData" Grid.Column="1"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding DisplayedCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
<Line Grid.Row="1" Style="{StaticResource horizontalLineStyle}" />
<StackPanel Grid.Row="2" Orientation="Vertical">
<Button Command="{Binding AddCommand}">Add a new customer</Button>
<Button Command="{Binding UpdateCommand}">Update the selected customer</Button>
<Button Command="{Binding DeleteCommand}">Delete the selected customer</Button>
</StackPanel>
<Line Grid.Row="3" Style="{StaticResource horizontalLineStyle}" />
<StackPanel Grid.Row="4" Orientation="Vertical">
<Button Command="{Binding RefreshCommand}">Refresh the list</Button>
<Button Command="{Binding ClearSelectionCommand}">Clear selection</Button>
</StackPanel>
</Grid>
EDIT: Now with screenshot, as requested. It's the right column I'm talking about (So yes, this UserControl is in itself another nested Grid)
EDIT 2: Here's the containing code. My page consist of three classess.
The 1st (ApplicationView.xaml) is a Window. It has the navigation buttons in the left column, a nice line, and one column containing the view of that specific object. It has no rows.
ApplicationView.xaml
<Grid>
<Grid.Resources>
<ResourceDictionary Source="StylesRD.xaml" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="6*" />
</Grid.ColumnDefinitions>
<!-- A DockPanel for the Navigation Buttons-->
<DockPanel Grid.Column="0" Margin="0,20" VerticalAlignment="Top" HorizontalAlignment="Center">
<ItemsControl ItemsSource="{Binding PageViewModels}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding }"
Margin="2,5"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DockPanel>
<Line Grid.Column="1" Style="{StaticResource verticalLineStyle}" />
<ContentControl Grid.Column="2" Content="{Binding CurrentPageViewModel}" />
</Grid>
The view (CustomerView.xaml) is the 2nd file. It is a User control and it also has 3 columns, one with the list of Customers in this case, one for the beautiful seperating line (it is beautiful, right? /sarcasm) and the one I'm struggling with right now with the details and the buttons to do stuff.
Here also no rows.
CustomerView.xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<!-- Customer list -->
<view:CustomerListView Grid.Column="0" VerticalAlignment="Top"/>
<Line Grid.Column="1" Style="{StaticResource verticalLineStyle}" />
<!-- Details -->
<view:CustomerDetailsView Grid.Column="2" VerticalAlignment="Top"/>
</Grid>
Your inner Grid has two RowDefinitions without a height setting. Therefore the default Height="*" will be used for both rows. Your inner grid doesn't need two RowDefinitions, so removing them should fix your issue. So your inner grid definition should look like this:
<Grid>
<!--
remove these row definitions
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="TBCustomerTitle" Margin="0,0,8,0" FontWeight="Bold"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}">Customer:</TextBlock>
<TextBox Name="TBCustomerData" Grid.Column="1"
Visibility="{Binding SetVisibility, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding DisplayedCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
Edit:
It works for me as expected. The TextBox and TextBlock get stretched to 2* height, and the two StackPanels have a height of 1* each. Please provide the XAML where you use your user control. Seems like there lies the problem.
Edit 2:
Ah, now I see it. The VerticalAlignment="Top" setting in your CustomerView.xaml pushes your CustomerDetailsView to the top. Either remove this attribute or set the VerticalAlignment to Stretch.
The xaml you provided is working fine, the problem is in the containing xaml. Look at this example xaml.
<StackPanel Orientation="Horizontal">
<Border Background="Yellow">
<local:MyUserControl/>
</Border>
<StackPanel Background="Green">
<local:MyUserControl/>
</StackPanel>
</StackPanel>
And the usercontrol (stripped away bindings and styles)
<UserControl x:Class="WpfApplication3.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:local="clr-namespace:WpfApplication3"
mc:Ignorable="d">
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="TBCustomerTitle" Margin="0,0,8,0" FontWeight="Bold" >Customer:</TextBlock>
<TextBox Name="TBCustomerData" Grid.Column="1" Text="{Binding DisplayedCustomer.Name, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</Grid>
<Line Grid.Row="1" Height="5"/>
<StackPanel Grid.Row="2" Orientation="Vertical">
<Button Command="{Binding AddCommand}">Add a new customer</Button>
<Button Command="{Binding UpdateCommand}">Update the selected customer</Button>
<Button Command="{Binding DeleteCommand}">Delete the selected customer</Button>
</StackPanel>
<Line Grid.Row="3" Height="5"/>
<StackPanel Grid.Row="4" Orientation="Vertical">
<Button Command="{Binding RefreshCommand}">Refresh the list</Button>
<Button Command="{Binding ClearSelectionCommand}">Clear selection</Button>
</StackPanel>
</Grid>
</UserControl>
As you can see the usercontrol located in the stackpanel is not stretching because stackpanel does not stretch it's contents.

Odd WPF Grid Behavior Affected by TextBox Text

I can't figure out why the contents of my TextBox is affecting my grid column widths. I have setup a grid with 3 columns with widths defined as 50, *, 50, as shown below
Now, when in use, the center column will grow/shrink as the text in the TextBox changes, see the 2 examples below. The actual TextBox is not changing size, so I can't understand why in the world the grid is changing. The Grid is inside of a Border inside a UserControl. The UserControl is used as a DataTemplate in a ListBox.
Edit: I've discovered that this issue is related to the UserControl being in a ListBox, see example image below (UserControl in ListBox (circled in red) vs. UserControl Placed on Form (circed in blue). The grid behaves as expected when the UserControl is placed directly on the form. Code for the form is given below.
UserControl XAML:
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="Name:" Margin="2" />
<TextBox Grid.Column="1" Margin="2" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Grid.ColumnSpan="2" />
<TextBlock Text="Shift:" Grid.Row="1" Margin="2" />
<TextBox Grid.Column="1" Grid.Row="1" Margin="2" Text="{Binding TimeShift, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, FallbackValue=0}" HorizontalContentAlignment="Right" />
<TextBlock Text="s" Grid.Row="1" Grid.Column="2" Margin="2" />
</Grid>
Window/Form XAML:
<Window x:Class="CrashSimOffice.FileImport"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CrashSimOffice"
Title="File Import" Height="350" Width="450" Background="White" Icon="/CrashSimOffice;component/Images/16/page-white-save.png">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Content="Add" Margin="2" Command="{Binding AddFileCommand}" />
<Button Content="Remove" Grid.Column="1" Margin="2" Command="{Binding RemoveFileCommand}" />
<ListBox HorizontalContentAlignment="Stretch" Grid.ColumnSpan="4" Margin="2" Grid.Row="1" ItemsSource="{Binding Files}" SelectedItem="{Binding CurrentFile}" ScrollViewer.CanContentScroll="False" Background="WhiteSmoke">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type local:FileViewModel}">
<local:FileView DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Done" Grid.Column="3" Margin="2" Grid.Row="2" Click="Button_Click" />
<local:FileView Grid.Row="3" Grid.ColumnSpan="4" />
</Grid>
OK, I figured it out, Bruno V you got me thinking it must have something to do with the ListBox. I needed to add this to my ListBox:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Not sure why that works, but it does.

How do I retrieve column width in a WPF Grid using a GridSplitter?

I need to display to the user two listboxes - one on either side of the window - and allow the user to choose how much screen space is devoted to each. I have achieved that much with the following code:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding FirstColumnWidth}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListBox Name="FirstColumn" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="0" />
<GridSplitter Name="gridSplitter1" Width="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="1" />
<ListBox Name="SecondColumn" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="2" />
</Grid>
However, whilst the binding will retrieve an initial width for the first column and size them both accordingly, using the GridSplitter to resize them simply replaces the binding with the new value. How can I retrieve the new value so that I can persist it?
Ideally, the solution needs to play nicely with MVVM - I'm using Caliburn and trying to keep the code as clean as possible (my view model contains the FirstColumnWidth property that is currently being bound).
There are two solutions that I can think of.
1. Use the different binding modes available and the Width and ActualWidth properties.
Example
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=FirstColumnWidth, Mode=OneTime}" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="{Binding Path=SecondColumnWidth, Mode=OneTime}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Column="0" ActualWidth="{Binding Path=FirstColumnWidth, Mode=OneWayToSource}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
<GridSplitter Grid.Column="1" Width="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.Column="2" ActualWidth="{Binding Path=SecondColumnWidth, Mode=OneWayToSource}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</Grid>
or
2. Override the current/default behaviour of the grid splitter using the attached behaviour pattern (tutorial on CodeProject). I will post of code sample for this tomorrow when I'm at my desk.

Control as background of Grid

I have a grid, and I need to have a control as background of this grid. This control will be a progressbar, but it's my problem how to create it.
I can't find how can I set a control as background of grid.
Have you got any experience with this kind of problem?
<DataTemplate x:Key="TodoItemWeeklyTemplate">
<Grid MinWidth="800" Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Source="{Binding Occurrence.Appointment.Icon, Converter={StaticResource imgConverter}}" Width="16" Height="16" Stretch="Fill" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" MaxWidth="130" Text="{Binding Occurrence.Appointment.Subject}" />
</Grid>
</DataTemplate>
Here is how I would do it:-
<Grid MinWidth="800">
<Rectangle x:Name="Background" Fill="Green" Width="{Binding PercentDone, Converter={StaticConverter WidthConv}, ConverterParameter=800}" HorizontalAlignment="Left" />
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Top" Source="{Binding Occurrence.Appointment.Icon, Converter={StaticResource imgConverter}}" Width="16" Height="16" Stretch="Fill" />
<TextBlock Grid.Column="1" HorizontalAlignment="Left" MaxWidth="130" Text="{Binding Occurrence.Appointment.Subject}" />
</Grid>
</Grid>
Where WidthConv is an instance of a class added to the usercontrol resources that implements IValueConverter. The Convert method would take the input percentage value and apply it to the parameter to return the width the rectangle needs to be to represents that percentage value.
The important point here is that Grid naturaly overlays elements on each other when the occupy the same area.
You cannot set a control as a background as it is of Brush Type.
But if you want to emulate that you can put your Grid in another one like that :
<Grid>
<Grid>
<!-- put your Content here -->
</Grid>
<ProgressBar />
</Grid>

WPF: Problem with overlapping controls and grid column widths

I have a problem regarding a parent grid with a control in it that overlaps a tabcontrol.
I need the child grid (in the tab control) to resize its columns according to the overlapping control.
Specifically, when the overlapping control is resized (due to resize of the window for example) the child grid inside the tabcontrol needs to resize its columns so that the child controls inside the tabcontrol grid isn't overlapped by the control that overlaps the tabcontrol.
I sincerely hope someone here knows a solution for this problem, I've been fighting with it for days :)
Thanks in advance!
Best regards,
Req
edit: In response to the comments below:
Absolutely - I figured I should have, but seeing that I was/am at work I didn't have the code handy. But I can write up a similar example of the XAML.
<Grid Name="parentGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TabControl Name="tabCtrl" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="2">
<TabItem Name="tabItem1">
<Grid Name="tabCtrlGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <!-- This is the column I want to resize according to the overlapping image control below -->
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button Name="someChildControl" Grid.Column="1" Grid.Row="0" />
</Grid>
</TabItem>
</TabControl>
<Image Name="overlappingImg" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="2" /> <!-- whenever the screen/window is resized, the parentGrid resizes, and thus resizing this overlapping image. -->
</Grid>
What needs to happen is that column 0 in the tabCtrlGrid needs to resize its width to fit the width of the overlapping area of the image. That way someChildControl is never overlapped by the image, regardless of how it's resized.
Hopefully that makes it a little more clear :)
How does this look?
<Grid Name="parentGrid" Background="LightGray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Aqua"/>
<TextBlock Text="Tab controller" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/>
<Rectangle Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Aqua"/>
<TextBlock Text="Up down nav" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle HorizontalAlignment="Left" VerticalAlignment="Top" Width="130" Height="160" Fill="BlanchedAlmond"/>
<TextBlock Text="CoverArt" HorizontalAlignment="Left" VerticalAlignment="Top" Width="130" Height="160"/>
<Rectangle Grid.Column="1" Fill="LightGray" />
<TextBlock Text="Tab content" Grid.Column="1" />
</Grid>
</Grid>

Resources