XAML Custom control - mathematical fraction - c#

I'm completely new to XAML but not to C# and .NET in general. I'm creating a Windows 8.1 App and I want to create and implement a mathematical fraction control which would represent a structure with numerator and denominator (the first above the second) with horizontal line between them. I'll present here what I already achieved but I know it's very poor and probably the way of my thinking itself is not XAML-like.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestWindowsApplication"
xmlns:local2="using:TestWindowsApplication.CustomControls">
<Style TargetType="local2:MathStructure" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local2:MathStructure">
<StackPanel>
<Border>
<Grid>
<Canvas>
<TextBlock>
1
</TextBlock>
</Canvas>
</Grid>
</Border>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local2:FractionControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local2:FractionControl">
<Border BorderThickness="2" BorderBrush="Green">
<Grid Height="200" Width="120">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Border Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="4" BorderThickness="0,0,0,2" BorderBrush="Red"/>
<Border BorderThickness="1" BorderBrush="White" Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="2">
<Grid>
</Grid>
</Border>
<Border BorderThickness="1" BorderBrush="White" Grid.Row="6" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="2">
<Grid>
</Grid>
</Border>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I'd like this control to be reusable - I'm going to implement many more of such structures (like integrals, derivatives, sums etc.) so the goal of all of these controls is to enable putting one inside another (e.g. fraction with another fraction as its numerator and an integral as its denominator).
I'm not expecting a working example (although one full example would be great for me to learn), I'll appreciate every tip, hint, code I get here.

I would start off by adding a new UserControl item to your project.
Then, using the standard set of controls (textboxes/blocks, comboboxes, ect)arrange them how you wish to get the desired result you're after.
You can then add styles to those controls - as well as possibly adding in any "background computation" for your fraction-control; such as
1/4 == (value/4)
3/8 == (value/8)*3
If nobody beats me too it, I will attempt to provide you with some code... but I recommend having a quick go yourself :D

Related

WPF: How do I get a text box to fill all available horizontal space?

I'm creating a form in WPF. The form has TextBoxes with TextBlocks to their left. A screenshot with GridLines is below:
I want it to look like this (forgive the MS Paint style):
The problem is: the text boxes are really small unless I set the HorizontalAlignment to Stretch, but if I do that, I can't align them to the left. How do I get the Grid containing TextBlock/TextBox to align to the left and make the TextBox fill all available space?
It's trivially easy if I hardcode widths, but that obviously won't work with resizing. I've tried playing with Stack and Dock Panels to hold the Grids with no luck.
I can't use HorizontalAlignment=Stretch, MaxWidth, and Left aligned at the same time? because there is no other control that is the width of the space I am trying to fill.
I also can't use How to get controls in WPF to fill available space? because nothing in my xaml has HorizontalContentAllignment. I tried wrapping stuff in ContentControls and using an ItemsControl to force it with no luck.
The xaml for the form is below. Note, this xaml is for the control that is under the 'Create' header and to the right of the 3 buttons.
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--Left hand side content goes here-->
<DockPanel Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"
Margin="20,0,0,0">
<Grid ShowGridLines="True" DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TextBlockColumn"/>
<ColumnDefinition SharedSizeGroup="TextBoxColumn"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="Input Name:"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch" VerticalAlignment="Center"
Style="{StaticResource FormTextBox}"
Margin="5,0,5,0"/>
</Grid>
<Grid ShowGridLines="True" DockPanel.Dock="Top" HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TextBlockColumn"/>
<ColumnDefinition SharedSizeGroup="TextBoxColumn"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="Input Name:"
HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Grid.Column="1"
HorizontalAlignment="Stretch" VerticalAlignment="Center"
Style="{StaticResource FormTextBox}"
Margin="5,0,5,0"/>
</Grid>
</DockPanel>
</Grid>
The FormTextBox style is:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="TextBox"
x:Key="FormTextBox">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border CornerRadius="10"
Background="{StaticResource InputBrush}">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
Text="{Binding RelativeSource={RelativeSource TemplatedParent},
Path=Text,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
BorderThickness="0"
Background="Transparent"
VerticalContentAlignment="Center"
Padding="5"
Foreground="{StaticResource TextBrush}"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It rounds the corners, changes the background color, and removes the dotted line that shows up if it was selected before you alt-tabbed out and back into the application.
You indicate that this is the desired layout:
There are a few problems with your current code. First, using a DockPanel to host the TextBlock/TextBox pairs, and second, no control has Grid.IsSharedSizeScope=true set on it. You also have defined a shared size for the text box column when in reality you just want it to take up all the available space.
Here is some code that achieves the desired layout:
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--Left hand side content goes here-->
<StackPanel Orientation="Vertical" Grid.Column="1"
Grid.RowSpan="2"
Margin="20,0,0,0"
Grid.IsSharedSizeScope="True" >
<StackPanel.Resources>
<Style TargetType="TextBlock">
<Setter Property="Grid.Column" Value="0"/>
<Setter Property="Text" Value="Input Name:"/>
<Setter Property="VerticalAlignment" Value="Center"/>
</Style>
</StackPanel.Resources>
<Border BorderBrush="Blue" BorderThickness="5">
<Grid ShowGridLines="True" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TextBlockColumn"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock/>
<TextBox Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource FormTextBox}"
Margin="5,0,5,0"/>
</Grid>
</Border>
<Border BorderBrush="Red" BorderThickness="5">
<Grid ShowGridLines="True" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="TextBlockColumn"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock/>
<TextBox Grid.Column="1"
VerticalAlignment="Center"
Style="{StaticResource FormTextBox}"
Margin="5,0,5,0"/>
</Grid>
</Border>
</StackPanel>
</Grid>
This code produces:
In reality though, if you're going for maximum usability, you'll want to create your own control for the TextBlock/TextBox, and then you could just put it in an ItemsControl of some kind for dynamic content.

Buttons custom content is not rendering at runtime

I have a UserControl hosted in a Windows Forms form. In this UserControl I have a ToolBar where I have various buttons:
<ToolBar>
<Button Content="{StaticResource AllGreenIcon}"/>
<Button Content="{StaticResource AllRedIcon}"/>
<Button Content="{StaticResource RedRectangle}"/>
<Button Content="{StaticResource GreenRectangle}"/>
</ToolBar>
It looks like this in the desinger:
The problem is with the buttons where the icon is made of 4 rectangles. The contents are not rendering for these two buttons at runtime.
It looks like this at runtime:
The code for the AllGreenIcon:
<UserControl.Resources>
<Grid x:Key="AllGreenIcon" Height="16" Width="16" Effect="{StaticResource IconDropShadowEffect}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl Content="{StaticResource GreenRectangle}" Margin="0,0,1,1" Grid.Row="0" Grid.Column="0"/>
<ContentControl Content="{StaticResource GreenRectangle}" Margin="1,0,0,1" Grid.Row="0" Grid.Column="1"/>
<ContentControl Content="{StaticResource GreenRectangle}" Margin="0,1,1,0" Grid.Row="1" Grid.Column="0"/>
<ContentControl Content="{StaticResource GreenRectangle}" Margin="1,1,0,0" Grid.Row="1" Grid.Column="1"/>
</Grid>
</UserControl.Resources>
Does anyone have some ideas how could I fix this?
Thanks in advance!
This common issue is due to WPF (logical) requirement of each UIElement to have a single parent. In your case you are adding to the resources an element - GreenRectangleand then you are using this element as the Content for multiple ContentControls in your AllGreenIcon resource. Each time an element is being connected to the visual tree it will change its parent reference, this guaranties that an element is present only once in the visual tree.
All your green buttons for example will use the same instance of GreenRectangle element. Since each time the GreenRectangle is connected to the visual tree its parent is changed only the last item using the GreenRectange resource will actually display the element.
In conclusion avoid declaring and using UIElements in resources. You should use Styles and Controltemplates.
Note: in your solution the AllGreenIcon grid declared in the resources will have the same problem - cannot be used in two different places in UI at the same time. Use a ContentTemplate instead.
Ex:
<Button ContentTemplate="{StaticResource AllGreenIconTemplate}"/>
I've managed to find a sollution by trial and error. Basicly what I did was I've replaced the ContentControls with Rectangles and made a style for the Rectangles.
<LinearGradientBrush x:Key="GreenLinearGradientBrush" EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="#FF00BD22" Offset="1"/>
<GradientStop Color="#FF218934"/>
</LinearGradientBrush>
<Style x:Key="GreenRectangleStyle" TargetType="{x:Type Rectangle}">
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Fill" Value="{StaticResource GreenLinearGradientBrush}"/>
<Setter Property="Effect" Value="{StaticResource IconDropShadowEffect}"/>
</Style>
<Grid x:Key="AllGreenIcon" Height="16" Width="16" Effect="{StaticResource IconDropShadowEffect}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Margin="0,0,1,1" Grid.Row="0" Grid.Column="0" Style="{StaticResource GreenRectangleStyle}"/>
<Rectangle Margin="1,0,0,1" Grid.Row="0" Grid.Column="1" Style="{StaticResource GreenRectangleStyle}"/>
<Rectangle Margin="0,1,1,0" Grid.Row="1" Grid.Column="0" Style="{StaticResource GreenRectangleStyle}"/>
<Rectangle Margin="1,1,0,0" Grid.Row="1" Grid.Column="1" Style="{StaticResource GreenRectangleStyle}"/>
</Grid>
Does anyone have a better solution?
edit:
#Novitchi S had a better solution, based on his answer here is the final version:
<Style x:Key="GreenRectangleStyle" TargetType="{x:Type Rectangle}">
<Setter Property="Width" Value="16"/>
<Setter Property="Height" Value="16"/>
<Setter Property="Fill" Value="{StaticResource GreenLinearGradientBrush}"/>
<Setter Property="Effect" Value="{StaticResource IconDropShadowEffect}"/>
</Style>
<DataTemplate x:Key="GreenRectangle">
<Rectangle Style="{StaticResource GreenRectangleStyle}"/>
</DataTemplate>
<DataTemplate x:Key="AllGreenIcon">
<Grid Height="16" Width="16" Effect="{StaticResource IconDropShadowEffect}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ContentControl ContentTemplate="{StaticResource GreenRectangle}" Margin="0,0,1,1" Grid.Row="0" Grid.Column="0"/>
<ContentControl ContentTemplate="{StaticResource GreenRectangle}" Margin="1,0,0,1" Grid.Row="0" Grid.Column="1"/>
<ContentControl ContentTemplate="{StaticResource GreenRectangle}" Margin="0,1,1,0" Grid.Row="1" Grid.Column="0"/>
<ContentControl ContentTemplate="{StaticResource GreenRectangle}" Margin="1,1,0,0" Grid.Row="1" Grid.Column="1"/>
</Grid>
</DataTemplate>
.
.
.
<ToolBar>
<Button ContentTemplate="{StaticResource AllGreenIcon}"/>
<Button ContentTemplate="{StaticResource AllRedIcon}"/>
<Button ContentTemplate="{StaticResource RedRectangle}"/>
<Button ContentTemplate="{StaticResource GreenRectangle}"/>
</ToolBar>

Custom panoramic control with edge snaping

I am trying to create a 'PanoramaControl' like control for Windows Phone 8, in terms that it displays a slideshow of scenes, each of them having the size of the ScreenWidth. I have tried using Microsoft's panorama control but I have abandoned this approach for several reasons:
the amount of scenes is around 10-20, and it might be too much for PanoramaControl to handle, especially because there will be animation inside.
I don't want the control to loop continuously, and PanoramaControl does.
After some research I decided to implement the control on my own, using a ScrollViewer and a ListBox, and the result is here: https://www.youtube.com/watch?v=2RcqDMKn0EY (the movement is very smooth on both device and emulator, but is a bit choppy in the link due to screen capture)
What I am missing however, is the scene by scene snap-to-edge elastic functionality.
I have tried playing with manipulation events, but I fail to get that smooth elastic inertial movement and I thought of asking for a suggestion towards an elegant implementation before getting the frustration up or worse.. hacking and compromising..
Therefore help or suggestions (even towards different approaches) will be greatly appreciated! :)
<Grid x:Name="layoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="8*"/>
<RowDefinition Height="10*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="14*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Row="0" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="3" Name="scrollViewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
<ListBox Name="listBoxScenes" ItemsSource="{Binding Scenes}" ScrollViewer.VerticalScrollBarVisibility ="Disabled" SelectedItem="{Binding SelectedScene, Mode=TwoWay}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="0">
<Grid Width="{Binding SceneWidth}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--Contains the item name and the date-->
<StackPanel Grid.Row="0">
<TextBlock Text="{Binding ItemName, FallbackValue=Item1}" Margin="9,30,0,0" Style="{StaticResource PhoneTextTitle1Style}" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding CurrentTime, StringFormat=D, FallbackValue='Sunday, May 11, 2014'}" Style="{StaticResource PhoneTextNormalStyle}" HorizontalAlignment="Right"/>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
</Grid>

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