Combobox Virtualization issue - c#

I have a strange issue as in combobox style when i made virutalzation true, i have a checked Combobox to check all the checkboxes in the combobox items.
in ItemsPanel property, i've made some custom styling with VirtualizingStackPanel as below
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"
IsVirtualizing="True"
VirtualizationMode="Recycling" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
But before and after scrolling the view, it differs.
For e.g., here i try to get very first item of the combobox after scrolling down the items panel as
ComboBoxItem cmbItem = ComboBox1.ItemContainerGenerator.ContainerFromItem(ComboBox1.Items[0]) as ComboBoxItem;
But, i get nothing but NULL here.
So is there anyway we can achieve this using virutalization? (I know it's already virtualizing!). Or we should get rid virtualization and think of another solution. We saw that without virutalization property the combobox loads very slow.
Any thoughts?
Thanks in advance! :)

The NULL is directly a result of virtualization. It is the ComboBoxItem instances that are virtualized/recycled. Only the visible items from your collection will have a ComboBoxItem assigned, so if you ask for the ComboBoxItem on any item that is not visible, you will get back a NULL.

Related

ListView ignoring drag and drop when setting a ItemTemplate

I have set up a ListView to manage tabs on my app. So users can drag and drop tabs to new instances of the app and reorder tabs. All goes great until I set up a ControlTemplate for the Itens at the ListView.
I used ControlTemplate because when I add a ListView.ItemTemplate directly it won`t work (it does not affect the listview item). So before adding a new item I use this:
tab.Template = (ControlTemplate)this.Resources["listViewItemTemplate"];
So the tabs is looking great, but all the functions that used to work (like drag and drop) isn't working anymore. When I remove the ControlTemplate the ListView show only one little string.
This is what is happening
My ListView Code:
<ListView x:Name="TabsListView"
CanDragItems="True"
AllowDrop="True"
DragEnter="TabsListView_DragEnter"
Drop="TabsListView_Drop"
ScrollViewer.VerticalScrollBarVisibility="Disabled
CanReorderItems="True"
DragItemsStarting="TabsListView_DragItemsStarting"
ItemClick="TabsListView_ItemClick" >
I know for sure that the issue isn't on the drag and drop method.
To create a new item I just use Add. Of course I checked every single item inside ControlTemplate to know that it is not blocking anything.
The control template is:
<ControlTemplate x:Key="listViewItemTemplate" >
<ListViewItem>
<Grid Tapped="Grid_Tapped" Width="180" Margin="-12,-12,-12,0">
<TextBlock Text="{Binding Name}" Margin="5,6,0,0"></TextBlock>
</Grid>
</ListViewItem>
</ControlTemplate>
The reason is that you are using ControlTemplate and embedding a ListViewItem in there. ListViewItems are created automatically by the control to contain the items, and ItemTemplate is a template of the contents of this container. So it should look like this:
<DataTemplate x:Key="listViewItemTemplate" >
<Grid Tapped="Grid_Tapped" Width="180" Margin="-12,-12,-12,0">
<TextBlock Text="{Binding Name}" Margin="5,6,0,0"></TextBlock>
</Grid>
</ControlTemplate>
<ListView ...
ItemTemplate="{ThemeResource listViewItemTemplate}">
...
</ListView>
Furthermore, if you want to style the ListViewItem (the container), you can create a style with TargetType="ListViewItem" and set it as ListView.ItemContainerStyle.
<Style TargetType="ListViewItem" x:Key="TabListViewItemContainerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Grid x:Name="ContentBorder">
... some template with ContentPresenter:
<ContentPresenter x:Name="ContentPresenter" ... />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ListView ...
ItemContainerStyle="{StaticResource TabListViewItemContainerStyle}">
...
</ListView>
You can find the default style in: C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.15063.0\Generic
Update
I have checked the code and found the problem. What you are actually doing is adding ListViewItems directly in code:
ListViewItem tab = new ListViewItem();
DataModel model = new DataModel();
model.Name = $"NewTab {counter}";
tab.DataContext = model;
tab.Content = model.ToString();
TabsListView.Items.Add(tab);
Unfortunately this does not work, because when ListView sees an item that is of type ListViewItem, it just adds it to the list, but ItemTemplate doesn't apply to it, because that is applied only when the items are not UIElement but rather a custom class. If you use DataModel directly, ItemTemplate will be applied as expected:
DataModel model = new DataModel();
model.Name = $"NewTab {counter}";
TabsListView.Items.Add(model);
ListView encounters DataModel, knows that just a class not a UIElement, so it internally creates a ListViewItem, applies ItemContainerStyle to it and then uses the ItemTemplate to create the UI that will be displayed inside the ListViewItem's ContentPresenter. It is better to use this approach as it gives you better decoupling as you don't have to create UI-based classes in the code-behind and you get more control (as you can change both the style of the item as well as the container).

WPF - Focus Control Within DataTemplate applied to FlyoutControl

I have a DataTemplate which contains a TextBox. The DataTemplate is bound to the ContentTemplate property of a Style for the DevExpress FlyoutControl. The Flyout Control itself is within the ControlTemplate of another TextBox.
When the TextBox with the FlyoutControl is focused, I want to redirect focus to the first TextBox in the FlyoutControl's ContentTemplate (from the DataTemplate). Setting FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}} on the TextBox I want focused accomplishes this the first time, but once the Flyout has loaded it no longer works.
I have tried every suggestion I can find and nothing so far has worked. I can get the TextBox I want to reference in code and call Focus(), but it always returns false. At best, when I try to focus it in code, the Flyout is focused instead, but never the TextBox within the Flyout.
Here is what each relevant part looks like (irrelevant code omitted):
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit x:Name="TextThatWantsFocus"
FocusManager.FocusedElement={Binding RelativeSource={RelativeSource Self}}" />
</Grid>
</DataTemplate>
...
<Style x:Key="FlyoutStyle" TargetType="dxe:FlyoutControl">
<Setter Property="ContentTemplate" Value="{StaticResource FlyoutTemplate}"/>
</Style>
...
<dxe:TextEdit>
<dxe:TextEdit.Template>
<ControlTemplate>
<StackPanel>
<dxe:TextEdit x:Name="InnerTextEdit" />
<dxe:FlyoutControl Style="{StaticResource FlyoutStyle}"/>
</StackPanel>
</ControlTemplate>
</dxe:TextEdit.Template>
</dxe:TextEdit>
The flyout is being opened in code. It is here that I also would like to focus the TextBox (TextThatWantsFocus). However, nothing I have tried will give it focus (except for FocusManager handling it the first time), including the typical SO answer involving triggers. Any ideas would be greatly appreciated.
I took DmitryG's advice and submitted a DevExpress support ticket, and they were able to provide a solution.
The issue was resolved by handling the Loaded event of the TextEdit I want focused and using the dispatcher to focus it:
private void TextThatWantsFocus_Loaded(object obj, RoutedEventArgs e)
{
var text = obj as FrameworkElement;
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(delegate()
{ text.Focus(); }));
}
I suggest you using the FocusBehavior from DevExpress MVVM Framework:
<DataTemplate x:Key="FlyoutTemplate">
<Grid>
<dxe:TextEdit>
<dxmvvm:Interaction.Behaviors>
<local:FocusBehavior/>
</dxmvvm:Interaction.Behaviors>
</dxe:TextEdit>
</Grid>
</DataTemplate>

WPF TreeViewItem Toggle Button visibility

I've ran into an issue I'm hoping someone can help me solve. I've run into a case where my nodes contain a set of child nodes with visibility set to false. I'm hoping that I can disable the toggle arrow beside the TreeViewItem if all it's children are invisibile. Is this possible? Here's an example:
<TreeView Margin="10,10,0,13" Name="TreeView1" HorizontalAlignment="Left" VerticalAlignment="Top" Width="194" Height="200">
<TreeViewItem Header="Cold Drinks">
<TreeViewItem Header="Coke" Visibility="False"></TreeViewItem>
<TreeViewItem Header="Pepsi" Visibility="False"></TreeViewItem>
</TreeViewItem>
</TreeView>
How would i get the Cold Drinks TreeViewItem to hide the toggle arrow?
If you see the deafult controlTemplate of TreeViewItem, you will see that visibility of Toggle button is bound to ItemsControl.HasItems. Trigger look like this -
<Trigger Property="ItemsControl.HasItems">
<Setter TargetName="Expander" Property="UIElement.Visibility" Value="{x:Static Visibility.Hidden}" />
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
So, as a workaround, you can create your own Custom Control derived from TabItem and bind your HasItems with your own CLR property which will loop through all your childItems(TreeViewItems) and will return True if any of the Item is visible or False if all items are hidden/collapsed state. That way your toggle button will automatically will hide as per Trigger.
In case you want to know how to create Custom control and bind it to your CLR property, you can refer to this -
WPF TreeView databinding to hide/show expand/collapse icon
This is somewhat same what you has been looking for. Hope this helps..
Both internally (i.e. for keyboard navigation) and in its default template the TreeViewItem is relying on its HasItems property to know if it has children or not. You will likely need to set the ItemsSource of the TreeViewItem to a list and filter out the collapsed items.

WPF Listbox items are cleared but reappear on restart

I have a listbox in Wpf. I directly add items to this listbox. I added a clear button which runs the items.clear() command and it deletes all the items. However when restarting the app, all the items are back in the list! Are they stored somewhere and if so, how can I disable this?
Another question: Can a datatemplate be applied to a listbox in which items are directly added and not bound?
Code example:
<ListBox x:Name="Results" Margin="222,31,8,44" />
Midiinput.ChannelMessageReceived += delegate(object sender, ChannelMessageEventArgs e)
{
string result = e.Message.MessageType.ToString() + " " + e.Message.Command.ToString() + " " + e.Message.Data1.ToString() + " " + e.Message.Data2.ToString();
Results.Items.Add(result); Clearbutton.IsEnabled = true;
};
the listbox items is not persisted (as any other property in fact).
How do you populate your listbox ? is there any backend storage ?
I guess that your application simply have some items declared in the markup and when the application starts, the list items are parsed.
If the items return when you restart your app, I would think one of the following is true:
1) You are populating the listbox at DESIGN time by using the Items property and entering strings into the collection by hand.
2) You are running code that is populating the list from a storage location, either in the code or in a file.
-C
For your second question
Can a datatemplate be applied to a
listbox in which items are directly
added and not bound?
The ItemTemplate of a ListBox is copied to the ContentTemplate of a ListBoxItem during UI generation. However, when adding the ListBoxItems directly, ItemTemplate is ignored for items already of the ItemsControl's container type (ListBoxItem). So you'll have to use the ContentTemplate of ListBoxItem instead. Here's an example
<ListBox>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Foreground="Green" Text="{Binding}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBoxItem Content="Item 1"/>
<ListBoxItem Content="Item 2"/>
<ListBoxItem Content="Item 3"/>
</ListBox>
For your problem with items that are re-appearing when re-starting your app:
I'd try to find all the places where you add items to your ListBox in code-behind (search for Results.Items.Add). Add a breakpoint to each of those places to see in the debugger when you're adding them. The ListBox itself won't have any memory of how it looked when it closed unless you implement this.
If this doesn't work, try to change the name of your ListBox to ResultsTest or something, compile and fix all the errors you get by commenting out all the code that is referencing the ListBox and run the program again. This should leave you with no items in the ListBox. After this, start to uncomment your code, step by step until you find the place of the error.

How can I set the LISTBOX tooltip through XAML

I have a list box in WPF as under
<ListBox Name="lstName" DisplayMemberPath ="ListName" ToolTip="{Binding Path=ListName}" />
My requirement is that what ever items I am displaying in the listbox, should also appear in the tooltip. i.e. if the items are say "Item1", "Item2" etc. then when the user will point(hover) to "Item1" through mouse, the toolltip should display "Item1". Same for others
So my DisplayMemberPath is set to the Property which I am supposed to display (and it is coming properly). However, the tooltip is not coming at all.
The entity is as under
public class ItemList
{
public string ListName { get; set; }
}
The binding is happening as under
this.lstName.ItemsSource = GetData(); // Assume that the data is coming properly
Instead of setting the ToolTip property on the ListBox, set it on the ListBoxItems by applying a style:
<ListBox Name="lstName" DisplayMemberPath="ListName">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="ToolTip" Value="{Binding ListName}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
That way, each ListBoxItem will have its own tooltip that displays the value for that item.
Since you are setting the ItemsSource on the ListBox directly, you probably haven't set a DataContext, so the Binding won't work there. If you do set the DataContext to the list, then that binding would display the currently selected item as the tooltip no matter where the mouse was on the ListBox.

Categories

Resources