-
- darthmaule2
- Posts: 98
- Joined:
ListView Template with ScrollViewer containing custom Panel instantiated twice and ItemsOwner(this) returns null
I have the following abbreviated XAML for displaying thumbnails on a filesystem. I specify a custom panel in the Template.
I can then find my customized Panel in code-behind like this:
But that Panel is not the one used by Noesis, since I can see that two are instantiated if I put a breakpoint on the Panel's constructor. The first is created when FileManagerView.xaml is loaded, second one is created when I call listView.UpdateLayout().
Also ItemsControl.ItemsOwner(this) from my panel returns null
I've tried several combinations of this per suggestions here but no luck:
https://stackoverflow.com/questions/285 ... emshost-do
Code: Select all
<UserControl x:Class="Modules.FileManager.FileManagerView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:noesis="clr-namespace:NoesisGUIExtensions;assembly=Noesis.GUI.Extensions"
xmlns:local="clr-namespace:Modules.FileManager">
<UserControl.Resources>
<Style x:Key="FileManagerListViewStyle" TargetType="{x:Type ListView}">
<Setter Property="BorderBrush" Value="Black"></Setter>
<Setter Property="BorderThickness" Value="2"></Setter>
<Setter Property="Grid.IsSharedSizeScope" Value="True"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<ScrollViewer ScrollChanged="OnScrollChanged" Margin="1" Style="{StaticResource StandardScrollViewer}" CanContentScroll="True" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled" PanningMode="VerticalOnly" Focusable="false">
<local:VirtualizingTilePanel x:Name="tilePanel" IsItemsHost="True" ItemsPerRow="5" ItemsPerCol="3"></local:VirtualizingTilePanel>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid Background="{StaticResource ControlBackgroundBrush}">
<ListView
x:Name="CurrentDirectoryListView"
KeyDown="OnListViewKeyDown"
SelectionMode="Single"
Initialized="ListView_OnInitialized"
Loaded="ListView_OnLoaded"
Style="{StaticResource FileManagerListViewStyle}"
ItemContainerStyle="{StaticResource FileManagerListViewItemStyle}"
ItemsSource="{Binding CurrentDirectoryContents}">
<ListView.ItemTemplate>
<!-- lots of xaml -->
<ListView.ItemTemplate>
</ListView>
</Grid>
</UserControl>
Code: Select all
listView = (ListView)FindName("CurrentDirectoryListView") ?? throw new MemberAccessException("CurrentDirectoryListView");
virtualizingTilePanel = (VirtualizingTilePanel)listView.Template.FindName("tilePanel") ?? throw new MemberAccessException("tilePanel");
Also ItemsControl.ItemsOwner(this) from my panel returns null
Code: Select all
public class VirtualizingTilePanel : VirtualizingPanel, IScrollInfo
{
...
ItemsControl itemsControl = ItemsControl.GetItemsOwner(this); // This returns null
https://stackoverflow.com/questions/285 ... emshost-do
-
-
sfernandez
Site Admin
- Posts: 3250
- Joined:
Re: ListView Template with ScrollViewer containing custom Panel instantiated twice and ItemsOwner(this) returns null
Sorry for the late answer on this.
The first instantiation of your custom panel corresponds to the element that defines the visual tree of the template (that's why it is created when xaml gets loaded). The second instance is created while applying the template during the layout of the ListView. That last one is the panel you're interested in, and you almost got the code right, just needed to provide the TemplatedParent to the FindName function, so the lookup is made on the actual control, and not in the template definition:
Hope this helps.
The first instantiation of your custom panel corresponds to the element that defines the visual tree of the template (that's why it is created when xaml gets loaded). The second instance is created while applying the template during the layout of the ListView. That last one is the panel you're interested in, and you almost got the code right, just needed to provide the TemplatedParent to the FindName function, so the lookup is made on the actual control, and not in the template definition:
Code: Select all
listView = (ListView)FindName("CurrentDirectoryListView") ?? throw new MemberAccessException("CurrentDirectoryListView");
virtualizingTilePanel = (VirtualizingTilePanel)listView.Template.FindName("tilePanel", listView) ?? throw new MemberAccessException("tilePanel");
-
- darthmaule2
- Posts: 98
- Joined:
Re: ListView Template with ScrollViewer containing custom Panel instantiated twice and ItemsOwner(this) returns null
That works but now scrolling is broken. My VirtualizingTilePanel's ScrollOwner property is set to null by the framework. Things like mouse wheel don't work despite my VirtualizingTilePanel implementing IScrollInfo.
Even if I set the ScrollOwner manually it doesn't scroll:
None of these functions get called:
And if I sign up for a ScrollChanged event, it's only ever called once, the first time the ListView is loaded but then never again, even if I scroll via arrow keys (that works because I'm manually changing the panel's vertical offset on arrow up/down so I can control how much it scrolls:
Even if I set the ScrollOwner manually it doesn't scroll:
Code: Select all
private void ListView_OnLoaded(object sender, Noesis.EventArgs args)
{
listView = (ListView)FindName("CurrentDirectoryListView") ?? throw new MemberAccessException("CurrentDirectoryListView");
virtualizingTilePanel = (VirtualizingTilePanel)listView.Template.FindName("tilePanel", listView) ?? throw new MemberAccessException("tilePanel");
ScrollViewer sv = virtualizingTilePanel.FindAncestors().OfType<ScrollViewer>().FirstOrDefault();
virtualizingTilePanel.ScrollOwner = sv;
virtualizingTilePanel.ScrollOwner.ScrollChanged += OnScrollChanged;
if (viewModel.CurrentDirectoryContents.Count >= 1)
{
// Pre-generates item containers
listView.UpdateLayout();
var item = (ListViewItem)listView
.ItemContainerGenerator
.ContainerFromIndex(0);
listView.SelectedItem = item;
listView.Focus();
}
}
Code: Select all
public void MouseWheelUp()
{
MouseWheelUp(10);
}
public void MouseWheelUp(float delta)
{
SetVerticalOffset(this.VerticalOffset - delta);
}
public void MouseWheelDown()
{
MouseWheelDown(10);
}
public void MouseWheelDown(float delta)
{
SetVerticalOffset(this.VerticalOffset + delta);
}
Code: Select all
public void SetVerticalOffset(float offset)
{
if (offset < 0 || _viewport.Height >= _extent.Height)
{
offset = 0;
}
else
{
if (offset + _viewport.Height >= _extent.Height)
{
offset = _extent.Height - _viewport.Height;
}
}
_offset.Y = offset;
if (_owner != null)
_owner.InvalidateScrollInfo();
_trans.Y = -offset;
// Force us to realize the correct children
InvalidateMeasure();
}
-
-
sfernandez
Site Admin
- Posts: 3250
- Joined:
Re: ListView Template with ScrollViewer containing custom Panel instantiated twice and ItemsOwner(this) returns null
I was able to reproduce the problem, C# implementations of IScrollInfo are not exposed to our native library and are ignored.
Could you please report this issue and we will fix it for the next release?
Sorry for the inconvenience.
Could you please report this issue and we will fix it for the next release?
Sorry for the inconvenience.
-
-
sfernandez
Site Admin
- Posts: 3250
- Joined:
Who is online
Users browsing this forum: Google [Bot] and 3 guests