简体   繁体   English

当我调整窗口大小时,带有数据选择器的 UWP Treeview 在 App.g.cs 中生成错误

[英]UWP Treeview with Data selector generating an error in App.g.cs when I resize the window

Team, this is something very strange and I do not understand how to debug it.团队,这是很奇怪的事情,我不明白如何调试它。 I have a tree view.我有一个树视图。 Within the tree view I have 2 types: Customer Visit在树视图中,我有两种类型:客户访问

ALL root elements are Customers ALL child elements are Visits所有根元素都是客户 所有子元素都是访问

I've done some selectors to show the correct icons for the level:我做了一些选择器来显示关卡的正确图标: 1 级加载

Now when I open the leafs IF the list does NOT exceed the end of the tree view it works:现在,当我打开叶子时,如果列表没有超过树视图的结尾,它会起作用: 在窗口大小内打开

But if I open a leaf that EXCEEDS the window side:但是如果我打开一片超出窗边的叶子: 儿童打开超出窗口大小

I get this error:我收到此错误: App.g.cs 中的错误

Sender: the App Exception: {"Specified cast is not valid."}发件人:应用程序异常: {"Specified cast is not valid."}

Message:信息:

"System.InvalidCastException: Unable to cast object of type 'TitoDoc2020.Models.MTreeViewVisit' to type 'TitoDoc2020.Models.MTreeViewPaz'.\r\n   at TitoDoc2020.Views.TitoDocPage.TitoDocPage_obj107_Bindings.SetDataRoot(Object newDataRoot)\r\n   at TitoDoc2020.Views.TitoDocPage.TitoDocPage_obj107_Bindings.ProcessBindings(Object item, Int32 itemIndex, Int32 phase, Int32& nextPhase)"

BUT I'm NOT casting that!但我不是在铸造那个! I really do not understand where it could happen.我真的不明白它可能发生在哪里。

Complete project visible here.在这里可以看到完整的项目

According to the description of the error message, the reason for this is on the type conversion of the binding and has nothing to do with whether it is out of the window.根据错误信息的描述,出现这种情况的原因在于绑定的类型转换,与是否出窗无关。

Please check your binding data to see if you have incorrectly bound MTreeViewVisit to MTreeViewPaz .请检查您的绑定数据,看看您是否错误地将MTreeViewVisit绑定到MTreeViewPaz


Update更新

The initial speculation may be that the adjustment of the window caused the change in the visible area, which in turn caused some TreeView entry loading problems.初步猜测可能是窗口的调整导致了可见区域的变化,进而导致了一些TreeView入口加载问题。

I noticed that in the project you will create a TitoDocContext whenever it comes to loading data, which is not recommended.我注意到在项目中你会在加载数据时创建一个TitoDocContext ,这是不推荐的。

You should only create a TitoDocContext , and pass the reference where it is needed, not use the using statement to release the Context.你应该只创建一个TitoDocContext ,并在需要的地方传递引用,而不是使用using语句来释放上下文。 Because the frequent creation of DbContext will bring huge resource overhead, this may also be related to your TreeView entry loading exception.因为频繁创建DbContext会带来巨大的资源开销,这也可能和你的TreeView入口加载异常有关。 In fact, I created a List with 1000 entries and after getting rid of SqlServer, it worked well.事实上,我创建了一个包含 1000 个条目的列表,在去掉 SqlServer 后,它运行良好。


Update更新

I reproduced your question.我转载了你的问题。 From the point of view of the actual problem, it should be due to the reuse of entries within the TreeView .从实际问题来看,应该是因为TreeView内部的条目重用。 In order to reduce the overhead of system resources, TreeView (including ListView and GridView ) will reuse previously rendered templates.为了减少系统资源的开销, TreeView (包括ListViewGridView )会复用之前渲染的模板。 Because you used ItemTemplateSelector , the actual data type and the reused template are inconsistent, causing an error.因为你使用了ItemTemplateSelector ,所以实际数据类型和复用的模板不一致,导致错误。

My suggestion is to create a UserControl to replace ItemTemplateSelector .我的建议是创建一个UserControl来替换ItemTemplateSelector

1. Extract the Visits collection and create a base class 1. 提取 Visits 集合并创建基类

public class MTreeViewBase
{
    public ObservableCollection<MTreeViewVisit> Visits { get; } = new ObservableCollection<MTreeViewVisit>();
}

public class MTreeViewVisit : MTreeViewBase { }
public class MTreeViewPaz : MTreeViewBase { }

2. Create a UserControl 2. 创建一个用户控件

TestControl.xaml测试控件.xaml

<UserControl.Resources>
    <DataTemplate x:Name="PAZTemplate" x:DataType="model:MTreeViewPaz">
        <StackPanel Orientation="Horizontal">
            <FontIcon
                    Margin="{StaticResource XXSmallTopRightBottomMargin}"
                    FontFamily="{StaticResource SymbolThemeFontFamily}"
                    Glyph="&#xE77B;" />
            <TextBlock
                    Margin="{StaticResource XXSmallTopRightBottomMargin}"
                    VerticalAlignment="Center"
                    Text="{x:Bind Name}" />
        </StackPanel>
    </DataTemplate>
    <DataTemplate x:Name="VisitTemplate" x:DataType="model:MTreeViewVisit">
        <StackPanel Orientation="Horizontal">
            <FontIcon
                    Margin="{StaticResource XXSmallTopRightBottomMargin}"
                    FontFamily="{StaticResource SymbolThemeFontFamily}"
                    Foreground="{x:Bind ImageColor}"
                    Glyph="{x:Bind ImageSrc}" />
            <TextBlock
                    Margin="{StaticResource XXSmallTopRightBottomMargin}"
                    VerticalAlignment="Center"
                    Text="{x:Bind VisitDescr}" />
        </StackPanel>
    </DataTemplate>
</UserControl.Resources>
<Grid>
    <ContentControl x:Name="MainContent"/>
</Grid>

3. Create dependent attributes for internal conversion 3.创建内部转换的依赖属性

TestControl.xaml.cs测试控件.xaml.cs

public MTreeViewBase Data
{
    get { return (MTreeViewBase)GetValue(DataProperty); }
    set { SetValue(DataProperty, value); }
}

// Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
    DependencyProperty.Register("Data", typeof(MTreeViewBase), typeof(TestControl), new PropertyMetadata(null,new PropertyChangedCallback(Data_Changed)));

private static void Data_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (e.NewValue != null)
    {
        var instance = d as TestControl;
        if(e.NewValue is MTreeViewPaz)
        {
            instance.MainContent.ContentTemplate = instance.PAZTemplate;
        }
        else
        {
            instance.MainContent.ContentTemplate = instance.VisitTemplate;
        }
    }
}

4. Modify your TreeView and ItemTemplate 4. 修改你的 TreeView 和 ItemTemplate

<DataTemplate x:Key="BaseTemplate" x:DataType="model:MTreeViewBase">
    <winui:TreeViewItem
        IsExpanded="False"
        ItemsSource="{x:Bind Visits}">
        <controls1:TestControl Data="{Binding}"/>
    </winui:TreeViewItem>
</DataTemplate>

<winui:TreeView
    ...
    ItemTemplate="{StaticResource BaseTemplate}"
    ... />

This can ensure that the two types have the same entrance, and the conversion is done internally, which can effectively solve this problem.这样可以保证两种类型有相同的入口,并且在内部进行转换,可以有效的解决这个问题。

Thanks.谢谢。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM