Stick to bottom of grid in an inner ContentControl - c#

I have a main view with a secondary child view ChildViewModel inside it:
<Window {...}>
<Window.Resources> {...} </Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0"> {...} </Grid>
<StackPanel Grid.Row="1"> {...} </StackPanel>
<ContentControl Grid.Row="2"
Content="{Binding ChildViewModel}"/>
</Grid>
</Window>
The ChildViewModel contains another grid of elements, with a Stack Panel of two buttons at the bottom. I would like these two buttons to be stuck to the bottom of the whole window.
I have tried this method, however it doesn't quite work as either the whole content control is at the bottom (with a large white gap at the top), or the buttons are at the bottom of the content control, but the content control itself is not at the bottom.
The following image should explain visually what I mean. The buttons are the two small rectangles that I would like at the bottom.
EDIT: Code of the Content Control:
<UserControl {..}>
<UserControl.DataContext>
<viewModels:ChildViewModel />
</UserControl.DataContext>
<Grid FocusVisualStyle="{x:Null}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.Resources>
{..}
</Grid.Resources>
<ScrollViewer Grid.Row="0" VerticalScrollBarVisibility="Auto" FocusVisualStyle="{x:Null}">
{..}
</ScrollViewer>
<customViews:SwirlyThingy Grid.Row="1" {..}/>
<TextBlock Grid.Row="2" {..}/>
<TextBlock Grid.Row="3" {..}/>
<TextBlock Grid.Row="4" {..}}"/>
<!--The buttons I'd like at the bottom-->
<StackPanel Grid.Row=5"
VerticalAlignment="Bottom"
Orientation="Horizontal"
misc:MarginSetter.Margin="6">
<Button Command="{Binding PrepareForMigrationCommand}"
IsEnabled="{Binding CanMigrate,
UpdateSourceTrigger=PropertyChanged}">
<Button.Style>
<Style BasedOn="{StaticResource MajorControlButton}" TargetType="Button">
<Setter Property="Content" Value="Migrate" />
<Style.Triggers>
<DataTrigger Binding="{Binding PrepareForMigrationCommand.Execution.IsNotCompleted}"
Value="True">
<Setter Property="Content" Value="Migrating..." />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
<Button Command="{Binding PrepareForMultiMigrationCommand}"
Visibility="{Binding IsMultiMigration,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource BooleanToVisibilityConverter}}">
<Button.Style>
<Style BasedOn="{StaticResource MajorControlButton}" TargetType="Button">
<Setter Property="Content" Value="Run All" />
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>
</UserControl>

You want to take up all available space for the last item. In order to do this you would star size your last row of your top level grid.
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <!-- Star size this one -->
</Grid.RowDefinitions>
In your control you could simply have two rows, one for all of your content which would be contained in a stackpanel (instead of multiple rows). And one row for your buttons. Your button panel would be aligned to the bottom.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Rectangle Height="20" Fill="Red"/>
</Grid>
<StackPanel Grid.Row="1">
<Rectangle Height="20" Fill="Orange"/>
<Rectangle Height="20" Fill="Yellow"/>
<Rectangle Height="20" Fill="Green"/>
</StackPanel>
<Grid Grid.Row="2"> <!-- simulating your custom control -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<!-- A bunch of content here
</StackPanel>
<StackPanel Grid.Row="1"
Orientation="Horizontal"
VerticalAlignment="Bottom">
<Button Content="Click Me!"/>
<Button Content="No, Me!"/>
</StackPanel>
</Grid>
</Grid>

Related

WPF button is disabled by default and I can't enable it again

Since some people can't be bothered to click on a link, here's all ~80 lines of XAML code for the window...
<Window x:Class="TollLicenser.Views.LicenseView"
x:Name="wdw"
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:TollLicenser.Views"
mc:Ignorable="d"
Title="License View" Height="300" Width="300"
xmlns:vm="clr-namespace:TollLicenser.ViewModels"
d:DataContext="{d:DesignInstance vm:LicenseViewModel}"
SizeToContent="WidthAndHeight"
Margin="8">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Button.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Shadows.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ToggleButton.xaml" />
</ResourceDictionary.MergedDictionaries>
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource MaterialDesignTextBox}">
<Setter Property="Margin" Value="0 8 8 8" />
</Style>
<Style TargetType="{x:Type DatePicker}">
<Setter Property="Margin" Value="0 8 8 8" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Margin" Value="0 8 8 8" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="8" />
</Style>
</ResourceDictionary>
</Window.Resources>
<Grid FocusManager.FocusedElement="{Binding ElementName=CountryCode}">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="5"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"
Style="{StaticResource MaterialDesignHeadlineTextBlock}">
Managing a License
</TextBlock>
<Label Grid.Row="1" Grid.Column="0">Country Code</Label>
<TextBox Grid.Row="1" Grid.Column="1" Name="CountryCode" Text="{Binding CountryCode}"/>
<Label Grid.Row="2" Grid.Column="0">Plaza Name</Label>
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding TollPlazaName}"/>
<Label Grid.Row="3" Grid.Column="0">Start Date</Label>
<DatePicker Grid.Row="3" Grid.Column="1" SelectedDate="{Binding StartDate}"/>
<Label Grid.Row="4" Grid.Column="0">End Date</Label>
<DatePicker Grid.Row="4" Grid.Column="1" SelectedDate="{Binding EndDate}"/>
<Label Grid.Row="5" Grid.Column="0">Max Users</Label>
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding MaxUsers}"/>
<GridSplitter Grid.Row="6" Height="5" />
<Button Grid.Row="7" Grid.Column="0" Content="Save" Margin="8" IsEnabled="True" IsDefault="True"
Command="{Binding SaveLicenseCommand}" CommandParameter="{Binding ElementName=wdw}" />
</Grid>
</Window>
Basically the problem is that the damn button (seen below) is disabled even from the time the window opens...
This seems to bind correctly to the ViewModel.
Only things in the viewmodel that have anything really to do with the button is the command and the method it executes as below:
public ICommand SaveLicenseCommand => new AwaitableDelegateCommand<Window>(SaveLicense);
private async Task SaveLicense(Window wdw)
{
_model.Id = Id;
_model.CountryCode = Encryption.Encrypt(CountryCode);
_model.EndDate = Encryption.Encrypt(EndDate.ToString());
_model.MaxUsers = Encryption.Encrypt(MaxUsers.ToString());
_model.StartDate = Encryption.Encrypt(StartDate.ToString());
_model.TollPlazaName = Encryption.Encrypt(TollPlazaName);
// LYTODO Post the model to the web service.
if (_model.Id != 0)
{
// Editing a license.
await _apiHelper.PutLicenseAsync(_model);
await _licenses.Load(); // Reload licenses with the updated item.
}
else
{
// Adding a license.
await _apiHelper.PostLicenseAsync(_model);
}
wdw.Close();
}
I don't have the faintest idea why the button is disabled or what other information to provide so please comment if there's more that you need and I will include it.
Why is the window opening with the button disabled?

ScrollViewer not scrolling ItemsControl changes

I am having a problem with a ScrollViewer in a modal dialog not changing scroll behavior when the ItemsSource of a ItemsControl inside the ScrollViewer changes.
When first creating the dialog the ScrollViewer's scrollbar behaves as expected with the size of the contents. When adding items to an ObservableCollection the ItemsControl is bound to the content changes but the ScrollViewer does not react to the change and activates the scrollbar.
Few items in ObservableCollection:
More items added to ObservableCollection :
After application restart:
<Grid x:Name ="Maingrid">
<Grid.Resources>
<ResourceDictionary>
<!--Style for RadButtons-->
<Style TargetType="telerik:RadButton" x:Key="RadButtonStyle">
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="95"/>
<Setter Property="Height" Value="Auto"/>
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
<!--end of Style for RadButtons-->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/PS.Common.Presentation;Component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="200" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>
<!--List-->
<ScrollViewer x:Name="LeftScrollViewer" Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding BaysAndSystems, NotifyOnSourceUpdated=True}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" IsChecked="{Binding Selected}" Content="{Binding Item.NameAndReference}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<!--Buttons-->
<StackPanel Grid.Row="2" Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Center">
<telerik:RadButton Content="{x:Static resx:Resources.Copy}" Command="{Binding CopyCommand}"
CommandParameter="{Binding}" Style="{StaticResource RadButtonStyle}" />
<telerik:RadButton Content="{x:Static resx:Resources.Cancel}" Command="{Binding CopyCancledCommand}"
CommandParameter="{Binding}" Style="{StaticResource RadButtonStyle}" />
</StackPanel>
</Grid>
What can I do to get the ScrollViewer to react to the changed content?
Your ScrollViewer is in Grid.Row="1" which has a fixed height. Changed this grid's row height to *. It should work. Also you can try different values for VerticalScrollBarVisibility.
Your problem is that your row that holds your scrollviewer increases its height despite your definition of 200 px. Set it to "*" and set property MaxHeight="200" on your Row - it is going to be OK.
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" MaxHeight="200" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>

Hide and auto resize columns with GridSplitter

I've a project with 1 header row and 1 content row. The content row is divided into 3 columns (groupboxes). These 3 columns are realized with GridSplitter.
Source Code:
<Window
x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewMenu="clr-namespace:Cons.ViewMenu"
Title="Test Gridsplitter"
Height="700"
Width="1000">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Row 0 -->
<GroupBox Name="Menu" Grid.Row="0">
<ViewMenu:LockedToolBar>
<ToggleButton x:Name="HideColumn0Button" IsChecked="True" Width="80" Height="40">Hide C0</ToggleButton>
<ToggleButton x:Name="HideColumn1Button" IsChecked="True" Width="80" Height="40">Hide C1</ToggleButton>
<ToggleButton x:Name="HideColumn2Button" IsChecked="True" Width="80" Height="40">Hide C2</ToggleButton>
</ViewMenu:LockedToolBar>
</GroupBox>
<!-- Row 1 -->
<GroupBox Name="Body" Grid.Row="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*" MinWidth="80" />
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*" MinWidth="80" />
</Grid.ColumnDefinitions>
<!-- Column 0 -->
<GroupBox Header="Column 0"
Name="ds"
Grid.Row="0"
Grid.Column="0"
Visibility="{Binding Path=IsChecked, ElementName=HideColumn0Button, Converter={StaticResource BoolToVisConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ViewMenu:LockedToolBar Grid.Row="0">
</ViewMenu:LockedToolBar>
</Grid>
</GroupBox>
<!-- Column 1 -->
<GroupBox Header="Column 1"
Grid.Row="0"
Grid.Column="2"
Visibility="{Binding Path=IsChecked, ElementName=HideColumn1Button, Converter={StaticResource BoolToVisConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ViewMenu:LockedToolBar Grid.Row="0">
</ViewMenu:LockedToolBar>
</Grid>
</GroupBox>
<!-- Column 2 -->
<GroupBox Header="Column 2"
Grid.Row="0"
Grid.Column="4"
Visibility="{Binding Path=IsChecked, ElementName=HideColumn2Button, Converter={StaticResource BoolToVisConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ViewMenu:LockedToolBar Grid.Row="0">
</ViewMenu:LockedToolBar>
</Grid>
</GroupBox>
<GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="5"/>
<GridSplitter Grid.Column="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="5"/>
</Grid>
</GroupBox>
</Grid>
</Window>
I click on HideColumn1Button, column 1 is hidden, but the other two columns have the same width as before. But I want, that column 0 and 2 are auto resized to the complete width.
Does anyone of you know, how to do that?
If you wish to bind it using a checkbox then you can try the following code, just build a library out of it and make use of extended column definition. Courtesy(immortalus)
http://www.codeproject.com/Articles/437237/WPF-Grid-Column-and-Row-Hiding
Alternatively, on the button_click or checkbox_checked you can write code(I have named the grid as testgrid), remember to add the reverse code as well:
testgrid.ColumnDefinitions[0].Width = new GridLength(0);
testgrid.ColumnDefinitions[0].MinWidth = 0;
An even more extended version is to write your own Storyboard, but the above two should help.
Regards
Kajal
Your BooleanToVisibilityConverter needs to return Visibility.Collapsed, not Visibility.Hidden. That would be the visual equivalent to setting the width to 0.
Edit
Find your definition of BooleanToVisibilityConverter somewhere in your code.
You should only have 3 columns. Put the GridSplitters in Columns 1 and 2, HorizontalAlignment="Left". For each GroupBox set Margin="5,0,0,0".
Please try to verify that BooleanToVisibilityConverter needs to return Visibility.Collapsed, not Visibility.Hidden.
BooleanToVisibilityConverter.cs source code in C# .NET
You should only have 3 columns with Auto width for column 0. Put the GridSplitters in Columns 1 and 2.
Here is the code i tried :
<Window
x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ViewMenu="clr-namespace:Cons.ViewMenu"
Title="Test Gridsplitter"
Height="700"
Width="1000">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Row 0 -->
<GroupBox Name="Menu" Grid.Row="0">
<StackPanel>
<ToggleButton x:Name="HideColumn0Button" IsChecked="True" Width="80" Height="40">Hide C0</ToggleButton>
<ToggleButton x:Name="HideColumn1Button" IsChecked="True" Width="80" Height="40">Hide C1</ToggleButton>
<ToggleButton x:Name="HideColumn2Button" IsChecked="True" Width="80" Height="40">Hide C2</ToggleButton>
</StackPanel>
</GroupBox>
<!-- Row 1 -->
<GroupBox Name="Body" Grid.Row="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" MinWidth="150"/>
<ColumnDefinition Width="*" MinWidth="150"/>
</Grid.ColumnDefinitions>
<!-- Column 0 -->
<GroupBox Header="Column 0"
Name="ds"
Margin="5,0,0,0"
Grid.Row="0"
Width="150"
Grid.Column="0"
Visibility="{Binding Path=IsChecked, ElementName=HideColumn0Button, Converter={StaticResource BoolToVisConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
</StackPanel>
</Grid>
</GroupBox>
<!-- Column 1 -->
<GroupBox Header="Column 1"
Grid.Row="0"
Grid.Column="1"
Margin="5,0,0,0"
Visibility="{Binding Path=IsChecked, ElementName=HideColumn1Button, Converter={StaticResource BoolToVisConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
</StackPanel>
</Grid>
</GroupBox>
<!-- Column 2 -->
<GroupBox Header="Column 2"
Grid.Row="0"
Margin="5,0,0,0"
Grid.Column="2"
Visibility="{Binding Path=IsChecked, ElementName=HideColumn2Button, Converter={StaticResource BoolToVisConverter}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
</StackPanel>
</Grid>
</GroupBox>
//Put the GridSplitters in Columns 1 and 2, HorizontalAlignment="Left".
<GridSplitter Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="5"/>
<GridSplitter Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Stretch" Width="5"/>
</Grid>
</GroupBox>
</Grid>
</Window>
Before hide
After Hide
How to create a GridSplitter that occupies a column
To specify a GridSplitter that occupies a column in a Grid, set the Column attached property to one of the columns that you want to resize. If your Grid has more than one row, set the RowSpan attached property to the number of rows. Then set the HorizontalAlignment to Center, set the VerticalAlignment property to Stretch, and set the Width of the column that contains the GridSplitter to Auto.
The following example shows how to define a vertical GridSplitter that occupies a column and resizes the columns on either side of it.
Credit : http://msdn.microsoft.com/en-us/library/ms745672(v=vs.110).aspx
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
..
<GridSplitter Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
Background="Black"
ShowsPreview="True"
Width="5"
/>

How to Fill Tab Item Area with WPF Grid

How does one get a grid to fill the lower portion of a tab item and make is size correctly? (personally I would call that area the page). As it stands right now I have a grid at my layout root and then a tab control with several tabs on it. I have tried to drag and drop a grid onto the tab control; however, it it's always set to the fixed size that I initially created it for.
<Grid x:Name="LayoutRoot" Margin="0,0,-1,0" Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*"/>
<ColumnDefinition Width="1497*"/>
<ColumnDefinition Width="116*"/>
<ColumnDefinition Width="36*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="101*"/>
<RowDefinition Height="24*"/>
<RowDefinition Height="5*"/>
<RowDefinition Height="27*"/>
<RowDefinition Height="597*"/>
<RowDefinition Height="0*"/>
</Grid.RowDefinitions>
<Rectangle Grid.ColumnSpan="4" Fill="#FF080808" Margin="-1,0,0,0" Stroke="#FF0061FF" Grid.RowSpan="3"/>
<Image Source="LP_Script Logo_black.jpg" Margin="32,18,1206,27" Grid.Column="1" Stretch="Fill" MinWidth="250" MinHeight="56" ScrollViewer.CanContentScroll="True"/>
<TextBox x:Name="ProgramSearchTextBox" TextWrapping="Wrap" Text="" KeyDown="ProgramSearchTextBox_KeyDown" PreviewKeyDown="ProgramSearchTextBox_PreviewKeyDown" Margin="2,1,2,0" HorizontalContentAlignment="Right" Grid.Column="2" Grid.Row="1" />
<TabControl x:Name="mainMenuTabControl" VerticalAlignment="Stretch" Height="Auto" Width="Auto" PreviewKeyDown="mainMenuTabControl_PreviewKeyDown" Grid.ColumnSpan="4" Margin="-1,0,1,0" Grid.Row="3" BorderThickness="1,1,1,0" Grid.RowSpan="3">
<TabItem x:Name="homeTab" Header="Home">
<TabItem.Background>
<LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#FFF3F3F3" Offset="0"/>
<GradientStop Color="#FFEBEBEB" Offset="0.5"/>
<GradientStop Color="#FFC1C0C0" Offset="1"/>
</LinearGradientBrush>
</TabItem.Background>
<DockPanel Height="Auto" Width="Auto" d:IsHidden="True">
<Grid x:Name="dashboard" Background="#FFE5E5E5" RenderTransformOrigin="0.5,0.5" Width="1636">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleY="-1" ScaleX="-1"/>
<SkewTransform/>
<RotateTransform Angle="180"/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
</Grid>
</DockPanel>
</TabItem>
<TabItem x:Name="fileMaintTab" Header="File Maintenance" KeyDown="fileMaintTab_KeyDown">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0*"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0*"/>
<ColumnDefinition/>
<ColumnDefinition Width="336*"/>
<ColumnDefinition Width="1316*"/>
</Grid.ColumnDefinitions>
<TreeView x:Name="FileMaintTreeView" Background="#FF747474" BorderThickness="1,1,5,1" BorderBrush="#FF0090FD" SelectedItemChanged="FileMaintTreeView_SelectedItemChanged" RenderTransformOrigin="0.5,0.5" Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="2" Margin="0,0,1,0">
<TreeView.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</TreeView.RenderTransform>
Here is a small example to demonstrate this for you:
<Grid>
<TabControl>
<TabItem Header="Whole Row Tab">
<Grid Background="Blue">
<TextBlock Text="I'm in the whole of this tab" />
</Grid>
</TabItem>
<TabItem Header="Half Row Tab">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="1" Background="Red">
<TextBlock Text="I'm in the bottom half of this tab" />
</Grid>
</Grid>
</TabItem>
<TabItem Header="Another Half Row Tab">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="1" Background="Red">
<TextBlock Text="I'm in the bottom half of this tab" />
</Grid>
</Grid>
</TabItem>
<TabItem Header="Varied Row Tab">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Green">
<TextBlock Text="I'm in the top quarter of this tab" />
</Grid>
<Grid Grid.Row="3" Background="Green">
<TextBlock Text="I'm in the bottom quarter of this tab" />
</Grid>
</Grid>
</TabItem>
</TabControl>
</Grid>
For the Grid underneath your TabItem, try setting up your definitions, like this:
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
For your TreeView definition, I changed it to the following:
<TreeView x:Name="FileMaintTreeView" Background="#FF747474" BorderBrush="#FF0090FD" SelectedItemChanged="FileMaintTreeView_SelectedItemChanged" Grid.Column="0" Grid.Row="0">
(I removed things like margins and whatnot, you can put them back in if you want...
That will at least get your TreeView to fill up the entire TabItem.
If you wanted the TabItem to have something else on the page... let's say some control next to the TreeView, then you can add another ColumnDefinition. Width="*" means it will fill up the entire remaining space. Width="Auto" means it will only fill the size of the controls nested within that column/row.
For me, finally I found reason from TabControlStyle.xaml(which is a style file), by adding following settings:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="TabControlStyle" TargetType="{x:Type TabControl}">
<Style.Resources>
<Style TargetType="{x:Type TabItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Setter>
</Style>
</Style.Resources>
</Style>
</ResourceDictionary>

Bing Maps needs a lot of performance when using custom pushpins

I have problems with a .NET 4 application using Bing Maps with custom pushpins. The performance is very bad on zooming or moving the map. I'm using a ObservableCollection which has a data-binding to Bing Maps. Everytime the map changes it is being checked which pushpins are in the map section. The collection will be re-filled and finally a NotifyCollectionChangedEvent is being fired which makes the map draw the pushpins.
<bingMap:MapItemsControl ItemsSource="{Binding Locations}">
<bingMap:MapItemsControl.ItemTemplate>
<DataTemplate>
<bingMap:Pushpin Location="{Binding Coordinates}" Height="Auto" Width="Auto" PositionOrigin="BottomCenter"
Template="{StaticResource PushpinControlTemplateLoc}">
</bingMap:Pushpin>
</DataTemplate>
</bingMap:MapItemsControl.ItemTemplate>
</bingMap:MapItemsControl >
I made some researches with a performance profiler: The InitializeComponent() method of my custom pushpin class needs an average time of 25% to 35%!
There are usually between 10 and 25 custom pushpins displayed on the map. If I reduce the amount of data bindings it becomes a little bit faster, but still not fast enough.
I've already tested out to declare all the brushes as freezed static resources but the drawing still runs very slow.
<SolidColorBrush x:Key="SolidColorBrushUnknownMsg" Color="Gray" ice:Freeze="True" xmlns:ice="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" />
I tried to use the Microsoft default pushpins <bingMap:Pushpin Location="{Binding Coordinates}"/> which was much faster. So there must be something wrong in my usage or implementation of my custom pushpin.
Here's the rest of my code:
Custom pushpin class (only auto-generated code):
public partial class MyPushpin: System.Windows.Controls.Grid
{
public MyPushpin()
{
InitializeComponent();
}
}
Custom pushpin XAML code:
<Grid x:Class="Test.MyPushpin"
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"
mc:Ignorable="d">
<Grid.Resources>
<Style BasedOn="{StaticResource DataTextBlock}" x:Key="test1" TargetType="TextBlock">
<Setter Property="Background" Value="{StaticResource SolidColorBrushErrorMsg}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=TextLine1, Mode=OneWay}" Value="0">
<Setter Property="Background" Value="{StaticResource BackgroundImage}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<Border CornerRadius="20" BorderBrush="White" Padding="7" Opacity="0.8" Width="120" Height="100" Background="{StaticResource BackgroundImage}">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="test2" Foreground="Black" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding TextLine2, StringFormat=N1,Mode=OneWay}" Style="{StaticResource DataTextBlock}" />
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding objCurrentPower.sUnit,Mode=OneWay}" Foreground="Black" />
<!--three more lines of textblocks with data bindings -->
</Grid>
</Border>
Why does my custom pushpin need so much performance?
Problem solved: Instead of using a separate class and xaml and referencing to them it's better to use a ControlTemplate for the custom pushpins in the class the actually contains the Bing Map:
<ControlTemplate x:Key="CutomPushpinTemplate" TargetType="bingMap:Pushpin">
<Border CornerRadius="15" BorderBrush="White" Padding="7" Opacity="0.8" Width="120" Height="90" Background="{StaticResource Bgr_enercon}">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="16" />
<RowDefinition Height="16" />
<RowDefinition Height="16" />
<RowDefinition Height="16" />
<RowDefinition Height="16" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="45" />
<ColumnDefinition Width="32" />
<ColumnDefinition Width="23" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="test2" Foreground="Black" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding TextLine2, StringFormat=N1,Mode=OneWay}" Style="{StaticResource DataTextBlock}" />
<TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding objCurrentPower.sUnit,Mode=OneWay}" Foreground="Black" />
<!--three more lines of textblocks with data bindings -->
</Grid>
</Border>
</ControlTemplate>
This template is used for all pushpins of the Bing Map this way:
<bingMap:MapItemsControl ItemsSource="{Binding Locations}">
<bingMap:MapItemsControl.ItemTemplate>
<DataTemplate>
<bingMap:Pushpin Location="{Binding objCoordinates}" Height="Auto" Width="Auto" PositionOrigin="BottomCenter" Template="{StaticResource CutomPushpinTemplate}">
</bingMap:Pushpin>
</DataTemplate>
</bingMap:MapItemsControl.ItemTemplate>
Doing it that way is much faster. The performance profiler shows that the programm now does not spend so much time for instantiating the custom pushpins.
Here is the xaml code which shows how it was implemented before (slow):
<ControlTemplate x:Key="PushpinControlTemplateLoc" TargetType="bingMap:Pushpin" >
<Test.MyPushpin />
</ControlTemplate>

Categories