UWP 应用中的 GetContainerForItemOverride
GetContainerForItemOverride in UWP app
我正在开发一个应用程序,该应用程序使用跨平台第三方布局引擎将 UI elements
放置在 Visual Tree
中的特定坐标(通过将内容放入画布中)。在我的场景中,我需要一个虚拟化 ListView
,它的每一项都通过这个布局引擎。
一切正常,直到我尝试从列表视图中删除项目。我已将问题缩小到这样一个事实,即对于我的列表视图,我在调用 GetContainerForItemOverride() 时返回 Canvas
,而不是返回 ListViewItem
。但是我当然需要一个 Canvas
以便布局引擎可以将内容放在 Canvas
.
中的特定坐标处
我在下面创建了一个非常愚蠢的示例,它将重现我遇到的问题。基本上,当我尝试通过调用 .RemoveAt()
或 .Remove()
删除一个项目时,我会得到一个 InvalidCastException
(顺便说一句,如果我在这个例子中使用 ItemsSource
而不是直接添加到 .Items
).
有人知道如何解决这个问题吗?
这是代码
<Page x:Class="Sample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sample="using:Sample">
<StackPanel>
<sample:CustomListViewCrash x:Name="MyListViewCrash">
<sample:CustomListViewCrash.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</sample:CustomListViewCrash.ItemsPanel>
</sample:CustomListViewCrash>
<Button Content="Delete" Tapped="Delete_OnTapped" />
</StackPanel>
</Page>
以及背后的代码
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
MyListViewCrash.Items.Add("blah blah");
}
private void Delete_OnTapped(object sender, TappedRoutedEventArgs e)
{
if (MyListViewCrash.Items.Count > 0)
{
MyListViewCrash.Items.RemoveAt(0);
}
}
}
public class CustomListViewCrash : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
var canvas = new Canvas
{
Width = 100,
Height = 50
};
canvas.Children.Add(new Button());
return canvas;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var canvas = (Canvas) element;
var button = (Button) canvas.Children[0];
button.Content = item;
base.PrepareContainerForItemOverride(element, item);
}
}
这里是关于异常的信息:
System.InvalidCastException occurred
HResult=0x80004002
Message=Specified cast is not valid.
Source=System.Private.CoreLib
StackTrace:
at System.Runtime.InteropServices.WindowsRuntime.IVector`1.RemoveAt(UInt32 index)
at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.RemoveAtHelper[T](IVector`1 _this, UInt32 index)
at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.RemoveAt[T](Int32 index)
at ReactiveDelete.MainPage.Delete_OnTapped(Object sender, TappedRoutedEventArgs e) in MainPage.xaml.cs:line 31
除了 "System.InvalidCastException: Specified cast is not valid" 之外,ListView
的容器应该是 ListViewItem
。
您应该能够设置 CustomListViewCrash
从 ItemsControl
继承来替换 ListView
。当CustomListViewCrash
class继承自ItemsControl
时,CustomListViewCrash
的容器不是ListViewItem
.
如果您希望 class 继承自 ListView
,您应该能够将 Canvas
设置为 ListViewItem
的 Content
。我们应该能够删除 PrepareContainerForItemOverride
.
中的 base.PrepareContainerForItemOverride(element, item)
方法
例如:
public class CustomListViewCrash : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
var canvas = new Canvas
{
Width = 100,
Height = 50
};
canvas.Children.Add(new Button());
var listViewItem = new ListViewItem();
listViewItem.Content = canvas;
return listViewItem;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var listViewItem = (ListViewItem)element;
var canvas = (Canvas)listViewItem.Content;
var button = (Button)canvas.Children[0];
button.Content = item;
}
}
我正在开发一个应用程序,该应用程序使用跨平台第三方布局引擎将 UI elements
放置在 Visual Tree
中的特定坐标(通过将内容放入画布中)。在我的场景中,我需要一个虚拟化 ListView
,它的每一项都通过这个布局引擎。
一切正常,直到我尝试从列表视图中删除项目。我已将问题缩小到这样一个事实,即对于我的列表视图,我在调用 GetContainerForItemOverride() 时返回 Canvas
,而不是返回 ListViewItem
。但是我当然需要一个 Canvas
以便布局引擎可以将内容放在 Canvas
.
我在下面创建了一个非常愚蠢的示例,它将重现我遇到的问题。基本上,当我尝试通过调用 .RemoveAt()
或 .Remove()
删除一个项目时,我会得到一个 InvalidCastException
(顺便说一句,如果我在这个例子中使用 ItemsSource
而不是直接添加到 .Items
).
有人知道如何解决这个问题吗?
这是代码
<Page x:Class="Sample.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sample="using:Sample">
<StackPanel>
<sample:CustomListViewCrash x:Name="MyListViewCrash">
<sample:CustomListViewCrash.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</sample:CustomListViewCrash.ItemsPanel>
</sample:CustomListViewCrash>
<Button Content="Delete" Tapped="Delete_OnTapped" />
</StackPanel>
</Page>
以及背后的代码
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
MyListViewCrash.Items.Add("blah blah");
}
private void Delete_OnTapped(object sender, TappedRoutedEventArgs e)
{
if (MyListViewCrash.Items.Count > 0)
{
MyListViewCrash.Items.RemoveAt(0);
}
}
}
public class CustomListViewCrash : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
var canvas = new Canvas
{
Width = 100,
Height = 50
};
canvas.Children.Add(new Button());
return canvas;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var canvas = (Canvas) element;
var button = (Button) canvas.Children[0];
button.Content = item;
base.PrepareContainerForItemOverride(element, item);
}
}
这里是关于异常的信息:
System.InvalidCastException occurred
HResult=0x80004002
Message=Specified cast is not valid.
Source=System.Private.CoreLib
StackTrace:
at System.Runtime.InteropServices.WindowsRuntime.IVector`1.RemoveAt(UInt32 index)
at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.RemoveAtHelper[T](IVector`1 _this, UInt32 index)
at System.Runtime.InteropServices.WindowsRuntime.VectorToListAdapter.RemoveAt[T](Int32 index)
at ReactiveDelete.MainPage.Delete_OnTapped(Object sender, TappedRoutedEventArgs e) in MainPage.xaml.cs:line 31
除了 "System.InvalidCastException: Specified cast is not valid" 之外,ListView
的容器应该是 ListViewItem
。
您应该能够设置 CustomListViewCrash
从 ItemsControl
继承来替换 ListView
。当CustomListViewCrash
class继承自ItemsControl
时,CustomListViewCrash
的容器不是ListViewItem
.
如果您希望 class 继承自 ListView
,您应该能够将 Canvas
设置为 ListViewItem
的 Content
。我们应该能够删除 PrepareContainerForItemOverride
.
base.PrepareContainerForItemOverride(element, item)
方法
例如:
public class CustomListViewCrash : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
var canvas = new Canvas
{
Width = 100,
Height = 50
};
canvas.Children.Add(new Button());
var listViewItem = new ListViewItem();
listViewItem.Content = canvas;
return listViewItem;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
var listViewItem = (ListViewItem)element;
var canvas = (Canvas)listViewItem.Content;
var button = (Button)canvas.Children[0];
button.Content = item;
}
}