How To improve wpf user control performance? - wpf

I have a usercontrol, and when I have lots of that in a window, it takes long time to get loaded.
Will it get better if I change it to a customcontrol or maybe a DataTemplate with a class and attached properties?
any ideas would be greatly appreciated.
Edited:
this is my control:
<UserControl
x:Class="Pouyansoft.WPF.MVVM.Control.Common.View.DataGridSelectorControl"
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"
x:Name="dataGridSelector"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d" >
<UserControl.Resources>
<CollectionViewSource Source="{Binding DataCollection.Source}" x:Key="theSource"/>
<Style x:Key="DataGridColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid VerticalAlignment="Center" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{TemplateBinding Content}"
HorizontalAlignment="Center" />
<TextBox x:Name="txtSearch" Grid.Row="1" HorizontalAlignment="Stretch"
BorderThickness="1" TextChanged="TextBox_TextChanged" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<DataGrid x:Name="grd"
ItemsSource="{Binding Source={StaticResource theSource}}"
AutoGenerateColumns="False"
ColumnHeaderStyle="{DynamicResource DataGridColumnHeaderStyle1}"
PreviewKeyDown="grd_PreviewKeyDown"
SelectedIndex="{Binding SelectedIndex}"
behavior:MouseDoubleClick.Command="{Binding MouseDoubleClickCommand}"
PreviewMouseLeftButtonUp="grid1_PreviewMouseLeftButtonUp"
GridLinesVisibility="Vertical">
</DataGrid>
</Grid>
and some code in the code behind.(and actually all the other control has the same behavior)

First thing, don't use DynamicResource use StaticResource -
use
ColumnHeaderStyle="{StaticResource DataGridColumnHeaderStyle1}"
in place of
ColumnHeaderStyle="{DynamicResource DataGridColumnHeaderStyle1}"
Second thing is to check for binding errors in your Output window, try and fix as many as you can.
Also, I don't see any benefit of using CollectionViewSource (as you are not doing any Sorting, Filtering, Grouping); If it's not necessary to use CollectionViewSource, you can directly bind the DataGrid's ItemSource to your DataCollection.Source.

Related

How could providing Parent Window as Pattern - WPF

Consider I have 4 Window on my project and I try to provide specific Closing button and one Title
How could I make a object of window and all of window use it as Pattern.
Here is Example of what we have for pattern window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStyle="None" AllowsTransparency="True" >
<Grid>
<Button Content="Close" Height="40" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<TextBlock VerticalAlignment="Top" HorizontalAlignment="Center" X:Name="WindowTitle/>
</Grid>
</Window>
How could I use for all of my Window as pattern. Thanks
Actually, there is no need to write a parent window. You can use Style and Template instead. It's more convenient and is recommended by Microsoft WPF Team.
Write the code below into your App.xaml and you'll get the picture above:
<Application x:Class="Walterlv.Demo.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
.........>
<Application.Resources>
<Style x:Key="Style.Window.Default" TargetType="Window">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Close" Height="40" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<TextBlock Grid.Row="0" VerticalAlignment="Top" HorizontalAlignment="Center"
Text="{TemplateBinding Title}"/>
<Border Grid.Row="1" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<!-- This is the container to host your Window.Content -->
<ContentPresenter/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>
And you can use only one property Style to share such a "pattern":
<Window x:Class="Walterlv.Demo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Style="{StaticResource Style.Window.Default}">
</Window>
You can define different kinds of styles in the App.xaml file and select anyone in your XxxWindow.xaml you need.

WPF ViewBox inside of a StackPanel

I am trying to display something like a score board, with team name in top 25% of a square and score taking up lower 75% (with font ratios as appropriate). I also want these controls to grow/shrink as the window gets resized.
To do this I have created a grid and split it into * and 3* rows. I have added one TextBlock to the top row and another TextBlock spanning bottom 4 rows. Then I have wrapped each TextBox in a ViewBox
This causes an application to go into a "break mode".
This shows the issue:
<Window x:Class="WpfRandoms.MainWindow"
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:WpfRandoms"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding Teams}" HorizontalAlignment="Center" Grid.Row="0" BorderBrush="{x:Null}" Background="{x:Null}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Border Margin="10" Padding="10" CornerRadius="5" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0">
<TextBlock Text="{Binding Name}" TextAlignment="Center" />
</Viewbox>
<Viewbox Grid.Row="1">
<TextBlock Text="{Binding Score}" FontSize="40" TextAlignment="Center" />
</Viewbox>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
With code-behind:
using System.Collections.Generic;
using System.Windows;
namespace WpfRandoms
{
public partial class MainWindow : Window
{
public class Team
{
public string Name { get; set; }
public int Score { get; set; }
}
public IList<Team> Teams { get; private set; }
public MainWindow()
{
InitializeComponent();
Teams = new List<Team>();
Teams.Add(new Team() { Name = "Team A", Score = 78 });
Teams.Add(new Team() { Name = "Team B", Score = 1 });
Teams.Add(new Team() { Name = "Team C", Score = 101 });
DataContext = this;
}
}
}
This seems to be caused by the StackPanel used as ItemsPanelTemplate of a ListView (without this StackPanel everything works fine but the layout is not as desired). However, I am not aware of another way of making ListView horizontal, so I am stuck with the StackPanel.
After some experimenting and reading about how ViewBox works, and how StackPanels behave I arrived at some solution (possibly not the best one).
I am wrapping my ListView in a Border, and then binding the height of a Border within the ListView's DataTemplate to the height of that outside Border.
Because of that there is a small limitation - mainly top/bottom margins cause the elements of the ListView to be trimmed. To avoid this trimming I have added padding to the Border within the DataTemplate, and then added a smaller Border within that has a background etc.
I had to also hide the vertical scrollbar of the ListView.
Here is what I have:
<Window x:Class="WpfRandoms.MainWindow"
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"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<Border x:Name="MyBorder" Margin="10" Grid.Row="0">
<ListView ItemsSource="{Binding Teams}" HorizontalAlignment="Center" VerticalAlignment="Stretch" BorderBrush="{x:Null}" Background="{x:Null}" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Border Margin="10, 0" Padding="10" Height="{Binding ActualHeight, ElementName=MyBorder}" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}">
<Border Background="AliceBlue" CornerRadius="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0">
<TextBlock Text="{Binding Name}" TextAlignment="Center"/>
</Viewbox>
<Viewbox Grid.Row="1">
<TextBlock Text="{Binding Score}" FontSize="40" TextAlignment="Center"/>
</Viewbox>
</Grid>
</Border>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
</Grid>
</Window>
If there is a better solution, I would greatly appreciate it :)
I'm not sure if I understand your problem exactly. If you are looking to keep the ratios between the name and score the same, you can use the "*" for the name (25%) and "3*" for the score (75%). You can also put each TextBlock in a Viewbox rather than the entire thing. To keep it simple, I replaced the converter and bindings with hard coded strings.
<Window x:Class="WpfApplication1.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>
<Border Margin="10" Padding="10" CornerRadius="5" Background="Coral">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Viewbox Grid.Row="0">
<TextBlock Text="Home" TextAlignment="Center" />
</Viewbox>
<Viewbox Grid.Row="1" >
<TextBlock Grid.Row="1" Text="25" TextAlignment="Center" />
</Viewbox>
</Grid>
</Border>
</Grid>
I think you may have a problem with the converter you are referencing on the boarder control.
I tested your XAML without the bindings and the view box works as expected.
<Border Margin="10" Padding="10" CornerRadius="5" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}">
<Viewbox>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="Team Name" TextAlignment="Center" Grid.Row="0" />
<TextBlock Text="100" FontSize="100" TextAlignment="Center" Grid.Row="1" Grid.RowSpan="3"/>
</Grid>
</Viewbox>
</Border>
Hopefully this helps!

Overriding Style of WPF TreeView Items

I am using the awesome MahAppsMetro WPF control suite. I have a tree view that loads the file system. I also want to display images in the TreeViewItems so I have overridden the metro tree style as follows
<UserControl x:Class="GDE.Tree.TreeView"
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:Caliburn="http://www.caliburnproject.org"
xmlns:Metro="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="300">
<UserControl.Resources>
<HierarchicalDataTemplate x:Key="TreeTemplate" ItemsSource="{Binding Path=Children}"/>
</UserControl.Resources>
<!--TreeView-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0"
Margin="5"
IsReadOnly="True"
Text="{Binding SelectedPath, Mode=TwoWay}"/>
<TreeView Grid.Row="1"
Margin="5"
ItemsSource="{Binding RootChildren}"
ItemTemplate="{StaticResource TreeTemplate}">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}"
BasedOn="{StaticResource MetroTreeViewItem}">
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Name="img"
Width="16"
Height="16"
Stretch="Fill"
Source="{Binding Path=Icon, Mode=OneTime}"
VerticalAlignment="Center"
HorizontalAlignment="Center"/>
<TextBlock Text="{Binding DisplayName, Mode=OneTime}"
Margin="5,0,0,0"
VerticalAlignment="Center"
HorizontalAlignment="Left"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.Resources>
</TreeView>
</Grid>
</UserControl>
But this does not seem to work as intended and I can't figure out why. From this XAML, I get no binding errors and the visuals look like:
I have gone more extensive with the XAML mark up but I am getting the exact same visuals. How can I change the above XAML to give me the Image/TextBlocks as well as the MahApps look and feel?
Thanks for your time.
To sum up comments instead of changing Style you need to move StackPanel from DataTemplate directly into HierarchicalDataTemplate as at the moment used template has no content:
<HierarchicalDataTemplate x:Key="TreeTemplate" ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<Image Name="img" ... />
<TextBlock Text="{Binding DisplayName, Mode=OneTime}" ... />
</StackPanel>
</HierarchicalDataTemplate>

Issue templating RadioButton in Silverlight 5

I try to apply a really simple ControlTemplate to a RadioButton. But that cause in a weird behavior.
As Long as I´m just clicking the Label everything works fine, but when I click the button control itself it never changes again. Here the complete code of the control:
<UserControl x:Class="RadioButtonDemo.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<ControlTemplate TargetType="RadioButton" x:Key="RadioButtonTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{TemplateBinding Content}"/>
<RadioButton IsChecked="{TemplateBinding IsChecked}" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
<Style TargetType="RadioButton" x:Key="RadioButtonStyle">
<Setter Property="Template" Value="{StaticResource RadioButtonTemplate}"/>
</Style>
</UserControl.Resources>
<StackPanel>
<RadioButton Content="Textbox diabled" GroupName="Group1" Style="{StaticResource RadioButtonStyle}"/>
<RadioButton x:Name="EnabledButton" Content="Textbox enabled" GroupName="Group1" Style="{StaticResource RadioButtonStyle}"/>
<TextBox IsEnabled="{Binding IsChecked, ElementName=EnabledButton}"/>
</StackPanel>
Can someone help?
Please get default style from following link,
http://msdn.microsoft.com/en-us/library/cc296247(v=vs.95).aspx
Use the template by just swapping content and button(:-( code is bulk).

Binding to the UserControl Inside HierarchicalDataTemplate in Silverlight

I have customized TreeView in usercontrol.
In the HierarchicalDataTemplate I have an image with direction (arrow for the example).
When the application\UserControl flow direction change I need to flip the image.
So i tried binding the Image.FlowDirection (Which is flipping the image automatic when RightToLeft) to the UserControl.FlowDirection
<Image FlowDirection="{Binding Path=FlowDirection,
ElementName=MyUserControl}" ... />
But it is not working. I guess because he can't find the UserControl from inside the template.
I've tried this binding outside the template - and it's working fine.
Any solution ?
How can I get my UserControl from inside the template ?
--UPDATE--
There are two places of binding in this xaml. The first is in the style of the button, and it is working, and the second in the template of the TreeViewItem - and there it's not working.
<UserControl x:Class="MyTree"
...
d:DesignHeight="218" d:DesignWidth="284" x:Name="MyLayerListControl">
<UserControl.Resources>
<Style x:Key="CloseButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<VisualStateManager.VisualStateGroups>
...
</VisualStateManager.VisualStateGroups>
<Border x:Name="CloseButtonBorder" BorderThickness="0" Margin="3" CornerRadius="0" Background="Gray" >
<!-- THIS BINDING IS WORKING -->
<Image Source="{StaticResource back}" Margin="2"
FlowDirection="{Binding Path=FlowDirection, ElementName=MyLayerListControl}"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Transparent">
<Button Style="{StaticResource CloseButtonStyle}" />
<Grid>
<Grid.ColumnDefinitions></Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.Resources>
<sdk:HierarchicalDataTemplate x:Key="LayerListTemplate" ItemsSource="{Binding Path=Childrens}" >
<Grid>
<Border CornerRadius="2" BorderBrush="#FF6DBDD1" BorderThickness="1" Background="#FFBADDE9" Opacity="0.5" />
<StackPanel Orientation="Vertical">
<!-- The Item -->
<StackPanel Orientation="Horizontal" Margin="3">
<!-- THIS BINDING IS NOT WORKING -->
<Image x:Name="ArrowImage" Width="16" Height="16" Source="{StaticResource arrow}"
FlowDirection="{Binding Path=FlowDirection, ElementName=MyLayerListControl}"/>
</StackPanel>
</StackPanel>
</Grid>
</sdk:HierarchicalDataTemplate>
</Grid.Resources>
<sdk:TreeView ItemsSource="{Binding}" ItemTemplate="{StaticResource LayerListTemplate}" x:Name="MyTreeView" Grid.Row="1" />
</Grid>
</Grid>
</UserControl>
As #Chris says, add "DataContext" in front of you binding path, as you are binding to the Control itself, so if FlowDirection is a property of the DataContext, you need to have that.
Also, make sure you have Mode=TwoWay in your binding.
As an alternative, you can you use RelativeSource so you don't have to hard code an ElementName.
Check out: http://tonychampion.net/blog/index.php/2011/12/7th-day-of-silverlight-ancestor-relative-source-binding/

Resources