Binding 1000usercontrols to listbox is slow wpf - wpf

I am having a listbox to which i am binding around 1000usercontrols with itemspaneltemplate as grid and i am placing each usercontrol by specifying rows and columns which is working fine.
But problem is it takes too much of time to load i even used backgroundworker process also but also no use.
Please help me what is the solution for the above problem.
<ListBox VerticalAlignment="Top" ItemsSource="{Binding Session.LstPlannedLightChkEntity,ElementName=uc, IsAsync=True}" Grid.Row="0"
VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling"
local:DragDropHelper.IsDragSource="true" local:DragDropHelper.IsDropTarget="true"
local:DragDropHelper.DragDropTemplate="{StaticResource planetTemplateDrag}"
ScrollViewer.VerticalScrollBarVisibility="Hidden" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="True"
>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
<Setter Property="Grid.ColumnSpan" Value="{Binding ColumnSpan}" />
<Style.Resources>
<!-- Background of selected item when focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
<!-- Background of selected item when not focussed -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<local:GridControl x:Name="gcMenuPlanned" VerticalAlignment="Stretch" Margin="-1,-1,0,0"
ShowCustomGridLines="True" GridLineBrush="#FFE4E7EB" GridLineThickness="0.5" SnapsToDevicePixels="True">
<local:GridControl.ContextMenu>
<ContextMenu >
<MenuItem Foreground="Black" Header="Add Task" Click="AddTask_Click" Tag="{Binding CheckType}" />
<MenuItem Foreground="Black" Header="Goto..." Click="miGoto_Click" Tag="{Binding CheckType}" />
</ContextMenu>
</local:GridControl.ContextMenu>
</local:GridControl>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<local:LightFCCheckBlockControl CheckColor="#FFA2CAEB" MouseLeftButtonDown="LightFCCheckBlockControl_MouseLeftButtonDown">
<local:LightFCCheckBlockControl.ContextMenu>
<ContextMenu >
<MenuItem Foreground="Black" Header="Edit" Click="miEdit_Click" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}"/>
<MenuItem Foreground="Black" Style="{StaticResource MenuItemBindingStyle }" Click="miFreeze_Click" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}">
</MenuItem>
<MenuItem Foreground="Black" Click="RemoveChecks_Click" Header="Remove Checks" Tag="{Binding CheckType}"/>
<MenuItem Foreground="Black" Click="DeleteChecks_Click" Header="Delete Checks" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}"/>
<MenuItem Foreground="Black" Header="Goto..." Click="miGoto_Click" Tag="{Binding CheckType}" Visibility="{Binding Path=OpacityForCCheck,Converter={StaticResource opacityToVisibility}}"/>
</ContextMenu>
</local:LightFCCheckBlockControl.ContextMenu>
</local:LightFCCheckBlockControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Thanks
Yogaraj I

Well it sounds a bit odd. First of all, you should answer the question...Is it really necessary to bind 1000 items to a list, which should be shown in UI? The usability would not be the best. Perhaps you could choose an approach with deferred loading.
Second, did you disable the Virtualization in the ListBox? Usually, there are only rendered the visuals for the elements, which are visible. The controls will be reused in case of scrolling.

Related

Horizontal stretch WPF ContextMenu MenuItem in HierarchicalDataTemplate.ItemTemplate

I have a WPF system traybar application. When right clicking traybar icon there is a ContextMenu using a HierarchicalDataTemplate to get a 2 level dynamically populated menu. It works but the "clickable" part of the items on the 2nd level does not properly stretch to the available width of the parent control. Instead See picture:
Now the user has to click the darker section (where the text is) of the MenuItem to perform the Command of this item. I want the whole of the menu row to be able to to trigger the Command.
Here is my XAML:
<CollectionViewSource x:Key="Items" Source="{Binding Path=Items}" />
<ContextMenu x:Shared="false" x:Key="Menu" HorizontalContentAlignment="Stretch">
<ContextMenu.ItemTemplate>
<HierarchicalDataTemplate DataType="SystemTrayItemsViewModel" ItemsSource="{Binding Items}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Converter={StaticResource TabIconConverter}}" />
<TextBlock Text="{Binding Name}" />
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding Text}" ToolTip="{Binding ToolTip}" Command="{Binding ToClipBoardCommand}" HorizontalContentAlignment="Stretch" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</ContextMenu.ItemTemplate>
<ContextMenu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource Items}}">
</CollectionContainer>
<Separator />
<MenuItem Header="Exit" cal:Message.Attach="ExitApplication" />
</CompositeCollection>
</ContextMenu.ItemsSource>
</ContextMenu>
For full source code, check https://github.com/kasperhlund/textgrunt
I just found the answer to this in another SO question.
It seems that the problem is specifying MenuItem within the ItemTemplate. The ContextMenu is apparently wrapping another MenuItem around the ItemTemplate, causing this nesting effect. Istead, you have to do this via the MenuItem's Style:
<ContextMenu>
<ContextMenu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Text}"/>
<Setter Property="ToolTip" Value="{Binding ToolTip}"/>
<Setter Property="Command" Value="{Binding ToClipBoardCommand}"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ContextMenu.Resources>
</ContextMenu>

How to modify Avalon 2.0 startup layout WPF

I have downloaded the avalon 2.0 and on load the tool panel starts on the right and the files panel starts on the left.
I am trying to get the tool panel to dock on the left on load even when I have deleted everything that is related to FileViewModel which loads on the left a blank panel stays on the left.
This image below shows how the window currently loads:
I want to have the tool panel loads on the left like this:(I achieved this by dragging the tool pane on run time.
In my WPF I can only see one LayoutAnchorablePane so I can't see why the screen is split into two?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="3"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Menu Grid.Row="0">
<MenuItem Header="File">
<MenuItem Header="New" Command="{Binding NewCommand}"/>
<MenuItem Header="Open" Command="{Binding OpenCommand}"/>
<Separator/>
<MenuItem Header="Save" Command="{Binding ActiveDocument.SaveCommand}"/>
<MenuItem Header="Save As..." Command="{Binding ActiveDocument.SaveAsCommand}"/>
<Separator/>
<MenuItem Header="Close" Command="{Binding ActiveDocument.CloseCommand}"/>
</MenuItem>
<MenuItem Header="Tools">
<MenuItem Header="{Binding FileStats.Title, Mode=TwoWay}" IsChecked="{Binding FileStats.IsVisible, Mode=TwoWay}" IsCheckable="True"/>
<MenuItem Header="{Binding Exported.Title, Mode=TwoWay}" IsChecked="{Binding Exported.IsVisible, Mode=TwoWay}" IsCheckable="True"/>
<MenuItem Header="{Binding ExportedResult.Title, Mode=TwoWay}" IsChecked="{Binding ExportedResult.IsVisible, Mode=TwoWay}" IsCheckable="True"/>
<MenuItem Header="{Binding Manifest.Title, Mode=TwoWay}" IsChecked="{Binding Manifest.IsVisible, Mode=TwoWay}" IsCheckable="True"/>
</MenuItem>
<MenuItem Header="Layout">
<MenuItem Header="Load" Command="{Binding LoadLayoutCommand, ElementName=mainWindow}"/>
<MenuItem Header="Save" Command="{Binding SaveLayoutCommand, ElementName=mainWindow}"/>
<MenuItem Header="Dump to Console" Click="OnDumpToConsole"/>
</MenuItem>
</Menu><!--AnchorablesSource="{Binding Tools}" DocumentsSource="{Binding Files}"-->
<avalonDock:DockingManager x:Name="dockManager"
AnchorablesSource="{Binding Tools}"
DocumentsSource="{Binding Files}"
ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}"
Grid.Row="1" >
<avalonDock:DockingManager.LayoutItemTemplateSelector>
<local:PanesTemplateSelector>
<local:PanesTemplateSelector.FileStatsViewTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding FileSize}"/>
<TextBlock Text="{Binding LastModified}"/>
<TextBox Text="test"/>
</StackPanel>
</DataTemplate>
</local:PanesTemplateSelector.FileStatsViewTemplate>
</local:PanesTemplateSelector>
</avalonDock:DockingManager.LayoutItemTemplateSelector>
<avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<local:PanesStyleSelector>
<local:PanesStyleSelector.ToolStyle>
<Style TargetType="{x:Type avalonDock:LayoutAnchorableItem}">
<Setter Property="Title" Value="{Binding Model.Title}"/>
<Setter Property="IconSource" Value="{Binding Model.IconSource}"/>
<Setter Property="Visibility" Value="{Binding Model.IsVisible, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter={x:Static Visibility.Hidden}}"/>
<Setter Property="ContentId" Value="{Binding Model.ContentId}"/>
<Setter Property="IsSelected" Value="{Binding Model.IsSelected, Mode=TwoWay}"/>
<Setter Property="IsActive" Value="{Binding Model.IsActive, Mode=TwoWay}"/>
</Style>
</local:PanesStyleSelector.ToolStyle>
</local:PanesStyleSelector>
</avalonDock:DockingManager.LayoutItemContainerStyleSelector>
<avalonDock:DockingManager.LayoutUpdateStrategy>
<local:LayoutInitializer/>
</avalonDock:DockingManager.LayoutUpdateStrategy>
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal" >
<avalonDock:LayoutAnchorablePane Name="ToolsPane" DockHeight="150" >
</avalonDock:LayoutAnchorablePane>
<avalonDock:LayoutDocumentPane />
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
</Grid>
this seems to work, but take care that the sample is saving the state
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal">
<avalonDock:LayoutAnchorablePane Name="ToolsPane" DockWidth="100">
<avalonDock:LayoutAnchorable>
<TextBlock>tototo</TextBlock>
</avalonDock:LayoutAnchorable>
</avalonDock:LayoutAnchorablePane>
<avalonDock:LayoutDocumentPane/>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>

Changing mouseover effect on Mahapps Tile

So recently I've started using MahApps.Metro for an application.
It's been going great, but one problem I cannot solve is MouseOver effect on a Tile.
I have a Grid, in which there's an Expander that hosts all the Tiles each of which represent a connection to the specific database. They are bound to an ObservableCollection which I populate from another database.
<Grid>
<Expander Margin="5" Header="Server Connections">
<ListBox ItemsSource="{Binding OmsConnections}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<controls:Tile
Title="{Binding Name}"
controls:ControlsHelper.MouseOverBorderBrush="{DynamicResource BlackBrush}"
Background="{DynamicResource GrayBrush2}"
Command="{Binding DataContext.TileClickCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}"
HorizontalTitleAlignment="Left"
Style="{StaticResource LargeTileStyle}"
TiltFactor="2">
<Image
Width="60"
Height="60"
Source="{Binding OmsConnectionTypeId, Converter={StaticResource ConnectionTypeToIconConverter}}" />
</controls:Tile>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</Grid>
This is the style applied via Style
<Style x:Key="LargeTileStyle" TargetType="controls:Tile">
<Setter Property="Height" Value="125" />
<Setter Property="TitleFontSize" Value="14" />
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="TextOptions.TextRenderingMode" Value="ClearType" />
<Setter Property="Width" Value="210" />
</Style>
So Whenever I mouseover an item I get the black border as specified, and this Orange Background Color (Which, if I'm not mistaken, is AccentColorBrush3) and I have no idea how to change it.
Here's the Image, since my rep is low and i cannot embed it.
Also, I'm really, really bad with Templates and Styles, so this is pretty much what i scrapped from the internet. ANY Feedback would be much appreciated for both the way I Bound to a collection and how to change the MouseOver color.
You could "override" the AccentColorBrush3 resource by adding a SolidColorBrush resource to the ListBox:
<ListBox ItemsSource="{Binding OmsConnections}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<!-- Specify the highlight brush here: -->
<ListBox.Resources>
<SolidColorBrush x:Key="AccentColorBrush3" Color="Yellow" />
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<controls:Tile
Title="{Binding Name}"
controls:ControlsHelper.MouseOverBorderBrush="{DynamicResource BlackBrush}"
Background="{DynamicResource GrayBrush2}"
Command="{Binding DataContext.TileClickCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}"
HorizontalTitleAlignment="Left"
Style="{StaticResource LargeTileStyle}"
TiltFactor="2">
<Image Width="60"
Height="60"
Source="{Binding OmsConnectionTypeId, Converter={StaticResource ConnectionTypeToIconConverter}}" />
</controls:Tile>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

How to hide context menu from DataGrid header?

I'm using a ContextMenu on the right click on a DataGrid. I don't want to show the ContextMenu on the DataGrid header.
<dgWPFCtrl:SelfBindingDataGrid Grid.Row="1" Margin="0,5,0,0" Name="_cycleList"
ItemsSource="{Binding Path=CurrentElementsList, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
IsReadOnly="False"
SelectedItem="{Binding Path=CurrentItem}">
<dgWPFCtrl:SelfBindingDataGrid.ContextMenu>
<ContextMenu>
<MenuItem Command="{Binding OpenCycleCommand}" Header="CYCLE" CommandParameter="CYCLE"/>
<MenuItem Command="{Binding OpenCycleCommand}" Header="H1" CommandParameter="H1"/>
<MenuItem Command="{Binding OpenCycleCommand}" Header="PDF" CommandParameter="PDF"/>
</ContextMenu>
</dgWPFCtrl:SelfBindingDataGrid.ContextMenu>
How can I solve this?
You can change ContextMenu just for the header with ColumnHeaderStyle:
<dgWPFCtrl:SelfBindingDataGrid>
<dgWPFCtrl:SelfBindingDataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContextMenu">
<Setter.Value>
<ContextMenu Visibility="Collapsed" />
</Setter.Value>
</Setter>
</Style>
</dgWPFCtrl:SelfBindingDataGrid.ColumnHeaderStyle>

Binding a command defined in a datatemplate

I know there are few answers on this topic. But none of them was working in my case.
I have a ListView with a style and an ItemContainerStyle. In the ItemContainer Style, I define some triggers in order to use a different DataTemplate depending if the item in the list is selected or not. Then, finally in the Datatemplate I have a context menu with a command. The problem is how to bind the command to the viewmodel.
This is the ListView:
<ListView
x:Name="lstPersons"
Grid.Row="1"
Style="{StaticResource ListViewStyle}"
ItemContainerStyle="{StaticResource ItemContainerStyle}"
DataContext="{Binding}"
ItemsSource="{Binding Path=Persons}"
Tag="{Binding}"
SelectedItem="{Binding Path=SelectedPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
</ListView>
and these are the styles, datatemplates and contextmenu (defined in a resource dictionary).
The commands in the context menu do not work....:
<ContextMenu x:Key="SelectedItemContextMenu">
<MenuItem
Header="Do Something"
Command="{Binding Path=DataContext.DoSomethingCmd, ElementName=LayoutRoot}">
</MenuItem>
<MenuItem
Header="Do Something"
Command="{Binding PlacementTarget.Tag.DoSomethingCmd, RelativeSource={RelativeSource AncestorType=ContextMenu}}">
</MenuItem>
</ContextMenu>
<DataTemplate
x:Key="ItemTemplate">
<Canvas
Margin="4"
Width="60"
Height="60"
Background="LightGray">
<TextBlock
Foreground="Black"
Margin="2 0 0 0"
Opacity="0.5"
FontFamily="Segoe UI"
Text="{Binding Path=FirstName}" />
</Canvas>
</DataTemplate>
<DataTemplate
x:Key="ItemSelectedTemplate">
<Grid>
<Border
BorderBrush="Black"
BorderThickness="1"
Margin="3"
ContextMenu="{DynamicResource SelectedItemContextMenu}">
<Canvas
Width="60"
Height="60"
Background="LightBlue">
<TextBlock
Foreground="Black"
Margin="2 0 0 0"
Opacity="0.5"
FontFamily="Segoe UI"
Text="{Binding Path=FirstName}" />
</Canvas>
</Border>
</Grid>
</DataTemplate>
<!--style of the listviewitem-->
<Style
TargetType="{x:Type ListViewItem}"
x:Key="ItemContainerStyle">
<Setter
Property="ContentTemplate"
Value="{StaticResource ItemTemplate}" />
<Style.Triggers>
<Trigger
Property="IsSelected"
Value="True">
<Setter
Property="ContentTemplate"
Value="{StaticResource ItemSelectedTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
<!--style of the listview-->
<Style
TargetType="{x:Type ListBox}"
x:Key="ListViewStyle">
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type ListBox}">
<Grid>
<Border>
<ScrollViewer
Focusable="false">
<WrapPanel
IsItemsHost="True"
Orientation="Horizontal"
Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/>
</ScrollViewer>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Your ContextMenu is used inside a data template. I will be put in a different name scope of "LayoutRoot" and ElementName binding won't work. Also, the PlacementTarget of your context menu is the Border, and you've not setup any Tag on it. So the second command won't work either.
It looks like you are implement the commands on the ListBox level (or LayoutRoot?). It might be easier to put your context menu on the ListBox, and use ListBox.SelectedItem to find the current selection and apply your logic on it.
You can use RelativeSource:
<ContextMenu x:Key="SelectedItemContextMenu">
<MenuItem
Header="Do Something"
Command="{Binding Path=DataContext.DoSomethingCmd, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}">
</MenuItem>
</ContextMenu>
You should probably be using RoutedCommands instead of VM commands in this case. You would bind the RoutedCommand to the ContextMenu, and since you only need static object references for that, finding them shouldn't be a problem. Then you'd set up appropriate CommandBindings on the controls that should handle the commands (either ListView or ListViewItem, depending on whether you want the List-ViewModel or the Item-ViewModel to handle the command). These controls will know their ViewModels, so binding to them will not be a problem there. Through the process of Command Routing, which is built-in in WPF, the context menu will find the proper target for its command automatically.
For guidance on how to set up CommandBindings in a MVVM-friendly way, you might want to refer to http://wpfglue.wordpress.com/2012/05/07/commanding-binding-controls-to-methods/

Resources