Wpf ComboBox with Checkbox Performance Problems - c#

I've got a WPF Combobox with about 1000 rows.
Each Row has a checkbox to allow selecting mulltiple rows.
If nothing has been selected it opens just fine. Howeve if I've already selected something and now want to change my selection it takes about 30s for the ComboBox to open and it has for some reason scrolled to the bottom.
I'm using VirtualizingStackPanel but it doesn't seem to fix the problem.
<ComboBox
x:Name="cbStockCat"
Grid.Column="1"
Margin="2,0,2,0"
Padding="2,10,0,4"
materialDesign:HintAssist.Hint="Stock Category"
materialDesign:HintAssist.IsFloating="True"
StaysOpenOnEdit="True"
customProperties:EnterKeyTraversalExtension.IsEnabled="True"
AllowDrop="True"
IsEditable="True"
ToolTip="{Binding StockCategoryCollection.ToolTipText}"
TabIndex="{Binding StockCatTabIndex, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Text="{Binding StockCategoryCollection.Text, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding StockCategoryCollection}"
Cursor="Hand">
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
<ComboBox.ItemTemplate>
<DataTemplate >
<CheckBox
IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Content="{Binding}"
Background="{StaticResource BrushPrimaryLighter}"
CommandParameter="{Binding}" >
</CheckBox>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Any ideas?

Related

WPF command parameter for MiddleClick on CheckBox in ItemsControl

I want to trigger a command when I use a MiddleClick on a Checkbox in an ItemsControl. I need to return the item source as a command parameter. I have tried two methods in XAML.
Method 1:
<ItemsControl x:Name="CheckBoxItems" ItemsSource="{Binding Curves}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</ItemsControl.InputBindings>
</ItemsControl>
This method returns the UserControl to the command instead of the item source.
Method 2:
<ItemsControl x:Name="CheckBoxItems" ItemsSource="{Binding Curves}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0">
<CheckBox.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding Path=SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</CheckBox.InputBindings>
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This method does not trigger the SelectOnlyCommand. Thanks for your help.
(Edited)
if you want to pass the single item, it works like this:
<ItemsControl x:Name="CheckBoxItems" ItemsSource="{Binding Curves}" Grid.Row="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0">
<CheckBox.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding ElementName=CheckBoxItems, Path=DataContext.SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</CheckBox.InputBindings>
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can achieve that with way 2 , but problem is you not able to bind Command. You will have to bind it by ElementName.
<CheckBox Content="{Binding Name}" IsChecked="{Binding IsChecked}" Margin="0,0,5,0">
<CheckBox.InputBindings>
<MouseBinding Gesture="MiddleClick" Command="{Binding ElementName=CheckBoxItems, Path = DataContext.SelectOnlyCommand}"
CommandParameter="{Binding }"/>
</CheckBox.InputBindings>
</CheckBox>

Access current ItemsControl index via binding

I have the following piece of code
<ItemsControl x:Name="ItemsControl" ItemsSource="{Binding Offers}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<wpf:Card Padding="32" Margin="5" d:DataContext="{d:DesignData }">
<StackPanel Margin="0,0,0,-30" Height="107">
<TextBlock
Style="{DynamicResource MaterialDesignTitleTextBlock}">
<Run Text="Offer " />
</TextBlock>
<TextBlock Text="{Binding CarDescription}" />
<Separator Height="1" Visibility="Hidden" />
<Button Content="Select"
Width="72"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="0,20,0,0"
Command="{Binding SelectOfferCommand}"/>
</StackPanel>
</wpf:Card>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This produces a bunch of repeated boxes, every has a button. Every time i click the button i want to access current box index (from ItemsControl's ItemsSource) and pass it as a command parameter. Is it possible to do it?
You can pass the current Index of an ItemsControl using the AlterationIndex.
See more info here
Example:
<ItemsControl x:Name="ItemsControl"
ItemsSource="{Binding Offers}"
AlternationCount="1000">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<wpf:Card Padding="32" Margin="5" d:DataContext="{d:DesignData }">
<StackPanel Margin="0,0,0,-30" Height="107">
<TextBlock
Style="{DynamicResource MaterialDesignTitleTextBlock}">
<Run Text="Offer " />
</TextBlock>
<TextBlock Text="{Binding CarDescription}" />
<Separator Height="1" Visibility="Hidden" />
<Button Content="Select"
Width="72"
VerticalAlignment="Bottom"
HorizontalAlignment="Right"
Margin="0,20,0,0"
Command="{Binding SelectOfferCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentPresenter}}, Path=(ItemsControl.AlternationIndex)}"/>
</StackPanel>
</wpf:Card>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
May be it will be suitable for you to add index property to each Offer while creating Offers and send this index OnSelectOfferCommand. It will be much easier
ps I think i must explain my answer: My sugestion is not only easier in realisation, but also it is a good practice to seperate busines logic from UI. In this case if UI will be changed, changes will not effect whole ordering process

DeferRefresh is not allowed during an AddNew or EditItem transaction

I have a Window containing 2 DataGrids. And if I click from one specific column in the first DataGrid into any column of the other DataGrid, then I get the error
DeferRefresh is not allowed during an AddNew or EditItem transaction
What is going wrong here?
The first DataGrid is
<DataGrid x:Name="FirstDataGrid"
ItemsSource="{Binding Parts, Mode=TwoWay}"
SelectedItem="{Binding SelectedPart, Mode=TwoWay}"
CellEditEnding="DataGrid_OnCellEditEnding" >
<i:Interaction.Behaviors>
<views:ScrollIntoViewBehavior />
</i:Interaction.Behaviors>
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Identifications, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Margin="5,0,0,0">
<Hyperlink NavigateUri="{Binding ArticleNumber, Mode=OneWay}"
Command="{Binding ElementName=PartDataGrid, Path=DataContext.OpenIdentificationCommand}" CommandParameter="{Binding}" >
<TextBlock Text="{Binding ArticleNumber, Mode=OneWay}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The second DataGrid does not matter since I can click on any column to produce the error.
Solved it by myself.
The column that causes problems is read-only. So why allow an edit mode anyway? That is obviously wrong. I fixed that by adding
IsReadOnly="True"
to the WPF column definition.

Can i make UpDown Column at DataGrid?

Can i make UpDown Column at DataGrid?
I have simple DataGrid:
<DataGrid Grid.Row="0" Grid.Column="0">
<DataGrid.Columns>
<DataGridTextColumn Header="Name"> </DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
And i want to make UpDown column. Can i do that?
Thank you!
P.S. i mean something like numericUpDown counter. :up: [1], down: [0].
I think you can do something like
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=AttrName}" Height="25" Width="150" HorizontalAlignment="Left" VerticalAlignment="Top" />
<TextBlock Text="{Binding Path=AttrDisplayLabel}" Height="25" Width="Auto" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="10,0,0,0" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Height="25"
ItemsSource="{Binding Source={StaticResource cvsAttributes}}"
SelectedValuePath="AttributeID"
IsSynchronizedWithCurrentItem="False"
SelectionChanged="Selector_OnSelectionChanged"
SelectedValue="{Binding Path=AttributeId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
....
Just replace combo with your updown/spinner control. The celltemplate is your display... the celledittemplate is your edit control...(updown...etc...)
If you mean NumericUpDown column
you can have a template column and add NumericUpDown Control to the template
Look Here for creating custom numeric updown control or simply use one provided with WPFToolkit !!
Find Codeples for Toolkit Here

Binding event from nested control

I'm writing application in windows phone 8 and have problem with bindings.
Here is my xaml code with my page structure
<phone:Pivot Grid.Row="1" SelectedIndex="{Binding SelectedPivotElement, Mode=TwoWay}" x:Name="SymbolsPivot" Title="Symbols" ItemsSource="{Binding CategoriesWithSymbols}">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<ContentControl Content="{Binding Name}"/>
</DataTemplate>
</phone:Pivot.HeaderTemplate>
<phone:Pivot.ItemTemplate>
<DataTemplate>
<telerikData:RadJumpList x:Name="SymbolsControl" ItemsSource="{Binding Path=Symbols}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
<telerikData:RadJumpList.GroupDescriptors>
<data:PropertyGroupDescriptor PropertyName="GroupName"
SortMode="Ascending" />
</telerikData:RadJumpList.GroupDescriptors>
<telerikPrimitives:RadDataBoundListBox.VirtualizationStrategyDefinition>
<telerikPrimitives:WrapVirtualizationStrategyDefinition Orientation="Horizontal"/>
</telerikPrimitives:RadDataBoundListBox.VirtualizationStrategyDefinition>
<telerikData:RadJumpList.GroupHeaderTemplate>
<DataTemplate>
<Grid Margin="0,-8,0,12" Width="480">
<TextBlock FontWeight="Bold" FontSize="{StaticResource PhoneFontSizeMedium}" Text="{Binding}" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</telerikData:RadJumpList.GroupHeaderTemplate>
<telerikData:RadJumpList.ItemTemplate>
<DataTemplate>
<Grid Width="300">
<TextBlock Text="{Binding Symbol}"/>
</Grid>
</DataTemplate>
</telerikData:RadJumpList.ItemTemplate>
</telerikData:RadJumpList>
</DataTemplate>
</phone:Pivot.ItemTemplate>
</phone:Pivot>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ItemTap" SourceName="SymbolsControl" >
<cmd:EventToCommand Command="{Binding TapCommand}"
/>
</i:EventTrigger>
</i:Interaction.Triggers>
So I have pivot control and inside pivot I have a list.
And now the problem is that application binds item tap event to my relay command but this event/command is never called. Everything works if I move list outside pivot. How to fix that problem ?

Categories

Resources