2017-03-31 5 views
0

크로스 플랫폼 타사 레이아웃 엔진을 사용하여 UI elementsVisual Tree (캔버스에 넣음)에 배치하는 앱에서 작업하고 있습니다. 내 시나리오에서는 가상화가 필요합니다. ListView 모든 항목이이 레이아웃 엔진을 통과합니다.UWP 앱에서 GetContainerForItemOverride

목록보기에서 항목을 삭제하려고 시도하기 전까지는 문제가 없습니다. 나는 내 목록보기에 대해 ListViewItem을 반환하는 대신 GetContainerForItemOverride()를 호출 할 때 Canvas을 반환한다는 사실에이 문제를 좁혀 냈습니다. 레이아웃 엔진이 Canvas의 특정 좌표에 물건을 넣을 수 있도록 물론 Canvas이 필요합니다.

아래에 아주 바보 같은 샘플이 만들어져서 내가 겪고있는 문제가 재현됩니다. 기본적으로 내가 .RemoveAt() 또는 .Remove()을 호출하여 항목을 삭제하려고하면 .Items에 직접 추가하는 대신 ItemsSource을 사용하는 경우 동일한 문제가 발생하므로 InvalidCastException이 발생합니다.

누구든지이 문제를 해결하는 방법을 알고 있습니까?

여기에 코드

<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 

답변

0

System.InvalidCastException "의 예외에서 : 지정 캐스트가 유효하지 않습니다. ", ListView의 컨테이너는여야합니다..

CustomListViewCrashItemsControl에서 상속되어 ListView을 대체 할 수 있도록 설정해야합니다. CustomListViewCrash 클래스가 ItemsControl에서 상속되면 CustomListViewCrash 컨테이너가 ListViewItem이 아닙니다. 당신이 당신의 클래스는 ListView에서 상속하려면

, 당신은 ListViewItemContentCanvas을 설정 할 수 있어야한다. 그리고 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; 
    } 
} 
+0

예 당신이 말한 일을하면 충돌을 타격하지 않는 문제를 해결한다. 비록 당신의 접근 방식으로 다른 렌더링 문제 (깜박임)를보고 있습니다. 하지만 그게 내 애플 리케이션과 관련이있을 수 있으므로 솔루션으로 표시하는 것 같아요. 감사. –