locked
WinRT XAML - Change ListView's ItemTemplate and ItemsPanel using Storyboard - AccessViolation

    Question

  • Hi,

    I tried to change ItemTemplate and ItemsPanel using VisualStateManager. After data is loaded to my ViewModel I got Unhandled AccessViolation error. It only throws it when I've changed both ItemsPanel and ItemTemplate using storyboard.

    ListView:

    <ListView x:Name="MainListView"
            SelectionMode="None"
            ScrollViewer.ZoomMode="Disabled"
            ItemsSource="{Binding MainData}" />

    VisualStateManager:

    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="PortraitLayout">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MainListView" Storyboard.TargetProperty="ItemTemplate">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource StackPanelContentVertical}"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MainListView" Storyboard.TargetProperty="ItemsPanel">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource StackPanelVertical}"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="HorizontalLayout">
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MainListView" Storyboard.TargetProperty="ItemTemplate">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource StackPanelContentHorizontal}"/>
                    </ObjectAnimationUsingKeyFrames>
                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="MainListView" Storyboard.TargetProperty="ItemsPanel">
                        <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource StackPanelHorizontal}"/>
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>

    It doesn't depend on DataTemplates. I tried with TextBlocks without any binding and it also fails.

    The ItemsPanels are simple StackPanels:

    <ItemsPanelTemplate x:Key="StackPanelHorizontal">
        <StackPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>
    <ItemsPanelTemplate x:Key="StackPanelVertical">
        <StackPanel Orientation="Vertical" />
    </ItemsPanelTemplate>

    Error from output:

    First-chance exception at 0x05104717 (Windows.UI.Xaml.dll) in FirstAttempt.WindowsCommon.Windows.exe: 0xC0000005: Access violation reading location 0x00000000.
    

    Callstack:

    >	Windows.UI.Xaml.dll!DirectUI::ItemsControl::AddContainers() Line 655	C++
     	Windows.UI.Xaml.dll!DirectUI::ItemsControl::RecreateVisualChildren(CItemsControl * pNativeItemsControl) Line 446	C++
     	Windows.UI.Xaml.dll!CItemsControl::ValidateItemsHost() Line 424	C++
     	Windows.UI.Xaml.dll!CItemsControl::MeasureOverride(XSIZEF availableSize, XSIZEF & desiredSize) Line 343	C++
     	Windows.UI.Xaml.dll!DirectUI::FrameworkElement::MeasureOverrideImpl(Windows::Foundation::Size availableSize, Windows::Foundation::Size * returnValue) Line 197	C++
     	Windows.UI.Xaml.dll!DirectUI::FrameworkElementGenerated::MeasureOverride(Windows::Foundation::Size availableSize, Windows::Foundation::Size * returnValue) Line 7592	C++
     	Windows.UI.Xaml.dll!DirectUI::FrameworkElementGenerated::MeasureOverrideProtected(Windows::Foundation::Size availableSize, Windows::Foundation::Size * returnValue) Line 7578	C++
     	Windows.UI.Xaml.dll!DirectUI::FrameworkElement::MeasureOverrideFromCore(CFrameworkElement * nativeTarget, float inWidth, float inHeight, float * outWidth, float * outHeight) Line 237	C++
     	Windows.UI.Xaml.dll!CFrameworkElement::MeasureCore(XSIZEF availableSize, XSIZEF & desiredSize) Line 1731	C++
     	Windows.UI.Xaml.dll!CUIElement::MeasureInternal(XSIZEF availableSize) Line 3735	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3589	C++
     	Windows.UI.Xaml.dll!CGrid::MeasureCellsGroup(unsigned int cellsHead, unsigned int cellCount, XSIZEF referenceSize, unsigned char ignoreColumnDesiredSize, unsigned char forceRowToInfinity) Line 420	C++
     	Windows.UI.Xaml.dll!CGrid::MeasureOverride(XSIZEF availableSize, XSIZEF & desiredSize) Line 1312	C++
     	Windows.UI.Xaml.dll!CFrameworkElement::MeasureCore(XSIZEF availableSize, XSIZEF & desiredSize) Line 1735	C++
     	Windows.UI.Xaml.dll!CUIElement::MeasureInternal(XSIZEF availableSize) Line 3735	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3589	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CUIElement::Measure(XSIZEF availableSize) Line 3647	C++
     	Windows.UI.Xaml.dll!CLayoutManager::UpdateLayout(unsigned int controlWidth, unsigned int controlHeight) Line 256	C++
     	Windows.UI.Xaml.dll!CCoreServices::NWDrawTree(HWWalk * pHWWalk, ICoreRenderTarget * pIRenderTarget, VisualTree * pVisualTree, unsigned int forceRedraw, unsigned int needsToReleaseHardwareResources, XRECT_WH * prcDirtyRect) Line 9768	C++
     	Windows.UI.Xaml.dll!CCoreServices::NWDrawMainTree(ICoreRenderTarget * pIRenderTarget, unsigned int fForceRedraw, unsigned int needsToReleaseHardwareResources, XRECT_WH * prcDirtyRect) Line 9600	C++
     	Windows.UI.Xaml.dll!CWindowRenderTarget::Draw(ICoreServices * pCore, unsigned int fForceRedraw, XRECT_WH * prcDirtyRect) Line 131	C++
     	Windows.UI.Xaml.dll!CXcpBrowserHost::OnTick() Line 819	C++
     	Windows.UI.Xaml.dll!CXcpDispatcher::Tick() Line 1086	C++
     	Windows.UI.Xaml.dll!CXcpDispatcher::OnReentrancyProtectedWindowMessage(HWND__ * msg, unsigned int wParam, unsigned int lParam, long) Line 665	C++
     	Windows.UI.Xaml.dll!CXcpDispatcher::WindowProc(HWND__ * hwnd, unsigned int msg, unsigned int wParam, long lParam) Line 417	C++
     	user32.dll!__InternalCallWinProc@20()	Unknown
     	user32.dll!UserCallWinProcCheckWow()	Unknown
     	user32.dll!DispatchMessageWorker()	Unknown
     	user32.dll!_DispatchMessageW@4()	Unknown
     	Windows.UI.dll!Windows::UI::Core::CDispatcher::WaitAndProcessMessages(void * hEventWait) Line 321	C++
     	Windows.UI.dll!Windows::UI::Core::CDispatcher::ProcessEvents(Windows::UI::Core::CoreProcessEventsOption options) Line 390	C++
     	Windows.UI.Xaml.dll!DirectUI::FrameworkView::Run() Line 93	C++
     	twinapi.appcore.dll!Windows::ApplicationModel::Core::CoreApplicationView::Run(void)	Unknown
     	twinapi.appcore.dll!Windows::ApplicationModel::Core::CoreApplicationView::SetWindowAndGetDispatcher(struct Windows::UI::Core::ICoreWindowFactory *,struct Windows::UI::Core::ICoreWindow * *,struct Windows::UI::Core::ICoreDispatcher * *)	Unknown
     	SHCore.dll!_SHCreateStreamOnFileW@12()	Unknown
     	kernel32.dll!@BaseThreadInitThunk@12()	Unknown
     	ntdll.dll!__RtlUserThreadStart()	Unknown
     	ntdll.dll!__RtlUserThreadStart@8()	Unknown
    

    I tried to delay ItemsPanel ObjectAnimation (and ItemTemplate too) but this doesn't change anything.

    What am I doing wrong?

    Thanks in advance!
    Friday, November 21, 2014 12:18 AM

Answers

  • I don't know how your MVVM binding data to the View but here I will give a really easy solution.

    By my code, you should be able to see a list is binding to ListView and when you change size of the screen, ListView will apply different itemPanelTemplate.

    xaml:

    <Page
        x:Class="App1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
            <ItemsPanelTemplate x:Key="StackPanelHorizontal">
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
            <ItemsPanelTemplate x:Key="StackPanelVertical">
                <StackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
        </Page.Resources>
    
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <ListView x:Name="MainListView"
                SelectionMode="None"
                ScrollViewer.ZoomMode="Disabled"
                ItemsSource="{Binding MainData}" Margin="49,161,606,198" />
        </Grid>
    </Page>
    

    CS:

    public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
    
                this.SizeChanged += MainPage_SizeChanged;
    
                List<string> lists = new List<string>(){"asd","asd","asd","asd","asd","asd","asd"};
    
                MainListView.ItemsSource = lists;
            }
    
            void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                if (e.NewSize.Width < e.NewSize.Height)
                { //Portrait or Narrow here
                    MainListView.ItemsPanel = Resources["StackPanelVertical"] as ItemsPanelTemplate;
                    //var t = VisualStateManager.GoToState(this, "Portrait", true);
                }
                else
                { //Landscape here
                    //VisualStateManager.GoToState(this, "Landscape", true);
                    MainListView.ItemsPanel = Resources["StackPanelHorizontal"] as ItemsPanelTemplate;
                }
            }
        }

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Tuesday, November 25, 2014 1:48 PM
    Moderator

All replies

  • Hi tlaguz,

    I think your purpose is to update the listview layout while the app orientation changed.

    As I can see from the documentation Designing your app with XAML: Orientation, looks like your code is correct, however I would like to know how you manage orientation states.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, November 21, 2014 2:18 AM
    Moderator
  • You are right: I'm trying to make 3 visual states: Portrait, Landscape and Narrow (I've posted code only for Portrait and Landscape).

    Here is my code-behind responsible for changing VisualState:

    void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (e.NewSize.Width < e.NewSize.Height)
        { //Portrait or Narrow here
            VisualStateManager.GoToState(this, PortraitLayout.Name, true);
        }
        else
        { //Landscape here
            VisualStateManager.GoToState(this, HorizontalLayout.Name, true);
        }
    }

    This method is of course added to SizeChanged event listener in MainPage's constructor:

    this.SizeChanged += MainPage_SizeChanged;


    I know I can make 3 ListViews with hard-coded ItemTemplate and ItemsPanel properties and just change their Visibility, however in this approach these 3 ListViews rebuild themselves every time the data in ViewModel changes.

    Friday, November 21, 2014 2:32 AM
  • Hi tlaguz,

    Thanks for your code, but I would like to know more things, for instance where you put the <VisualStateManager.VisualStateGroups>.

    I've just tested something different, which works fine:

            void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                if (e.NewSize.Width < e.NewSize.Height)
                { //Portrait or Narrow here
                    MainListView.ItemsPanel = Resources["StackPanelVertical"] as ItemsPanelTemplate;
                    //var t = VisualStateManager.GoToState(this, "Portrait", true);
                }
                else
                { //Landscape here
                    //VisualStateManager.GoToState(this, "Landscape", true);
                    MainListView.ItemsPanel = Resources["StackPanelHorizontal"] as ItemsPanelTemplate;
                }
            }

    To ensure your VisualStateManager method works correctly, you have to get the return value from it, if its false, then it means the VisualStateManager.GoToState() is not correctly executed, and you may need some other configuration, see GoToState method for more information.

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Friday, November 21, 2014 6:10 AM
    Moderator
  • Your code doesn't work for me.

    MainPage_SizeChanged method executes properly and GoToState return true in both Landscape and Portrait cases.

    AccessViolation is thrown when binded property from ViewModel changes and ListView tries to rebuild itself.

    My test binded property's type looks like this:

    public class DataModel
        {
           public int id { get; set; }
           public string signature { get; set; }
           public string description { get; set; }
        }

    When ItemsPanel property is not changed by the code (or VSM) I see list populated with strings: MyApp.Core.Models.DataModel

    Friday, November 21, 2014 7:56 AM
  • I don't know how your MVVM binding data to the View but here I will give a really easy solution.

    By my code, you should be able to see a list is binding to ListView and when you change size of the screen, ListView will apply different itemPanelTemplate.

    xaml:

    <Page
        x:Class="App1.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:App1"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
            <ItemsPanelTemplate x:Key="StackPanelHorizontal">
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
            <ItemsPanelTemplate x:Key="StackPanelVertical">
                <StackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
        </Page.Resources>
    
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <ListView x:Name="MainListView"
                SelectionMode="None"
                ScrollViewer.ZoomMode="Disabled"
                ItemsSource="{Binding MainData}" Margin="49,161,606,198" />
        </Grid>
    </Page>
    

    CS:

    public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
    
                this.SizeChanged += MainPage_SizeChanged;
    
                List<string> lists = new List<string>(){"asd","asd","asd","asd","asd","asd","asd"};
    
                MainListView.ItemsSource = lists;
            }
    
            void MainPage_SizeChanged(object sender, SizeChangedEventArgs e)
            {
                if (e.NewSize.Width < e.NewSize.Height)
                { //Portrait or Narrow here
                    MainListView.ItemsPanel = Resources["StackPanelVertical"] as ItemsPanelTemplate;
                    //var t = VisualStateManager.GoToState(this, "Portrait", true);
                }
                else
                { //Landscape here
                    //VisualStateManager.GoToState(this, "Landscape", true);
                    MainListView.ItemsPanel = Resources["StackPanelHorizontal"] as ItemsPanelTemplate;
                }
            }
        }

    --James


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Tuesday, November 25, 2014 1:48 PM
    Moderator