Listview滚动触发Combobox SelectedValue并抛出异常

时间:2012-09-27 18:16:05

标签: c# wpf mvvm binding

我在WPF的应用程序中有一个非常奇怪的问题,有很多屏幕可以很好地处理绑定和Comboboxes。但其中一个问题导致了我的问题。

我创建了一个屏幕,为应用中定义的每个用户定义配置文件。所以这是一个Listview,每行都是一个标签(用户名)和一个带有配置文件列表的组合框。 一切都是通过绑定来定义的。

这是ListView的XAML(我删除了样式):

<ListView Name="lv_UserProfils" ItemsSource="{Binding ListeEntites}" AlternationCount="2"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
    <ListView.View>
        <GridView>
            <GridViewColumn Header="Nom d'utilisateur" Width="250">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Border Height="25">
                            <TextBlock Text="{Binding UserLogin}" Width="Auto" />
                        </Border>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="Profil" Width="Auto">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox 
                                        ItemsSource="{Binding DataContext.ListeProfils, ElementName=lv_UserProfils}" 
                                        DisplayMemberPath="LibProfil" SelectedValuePath="IdProfil" 
                                        SelectedValue="{Binding Profil.IdProfil}" 
                                        SelectedItem="{Binding Profil}" Width="200" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

DataContext是自定义ViewModel类的一个实例,它提供名为ListeEntites的ObservableCollection<UserBE>

UserBE或多或少:

public sealed class UserBE
{
public bool IsAdmin { get; set; }
public bool IsUpdateGranted { get; set; }

private string _userLogin;
public string UserLogin
{
    get { return _userLogin; }
    set { _userLogin = value; OnPropertyChanged("UserLogin"); }
}

private ProfilBE _profil;
public ProfilBE Profil
{
    get { return _profil; }
    set
    {
        _profil = value;
        OnPropertyChanged("Profil");
    }
}
}

ProfilBE

public sealed class ProfilBE
{
    public long IdProfil { get; set; }

    private string _codProfil;
    public string CodProfil
    {
        get { return _codProfil; }
        set { _codProfil = value; OnPropertyChanged("CodProfil"); }
    }

    private string _libProfil;
    public string LibProfil
    {
        get { return _libProfil; }
        set { _libProfil = value; OnPropertyChanged("LibProfil"); }
    }
}

这是我的问题:
用户列表很长,所以有一个滚动条。我可以按照我想要的方式向下滚动但是只要我向上滚动(但只有当我向下滚动),所有未显示的组合框一旦出现在屏幕上就会立即被清除。

有趣的事实:

  • 当我滚动时,Profil setter会不断调用与显示的行相关联的对象。我不确定为什么(没有理由,Profil属性已定义)
  • 有一次,如果我向上滚动,我会收到很多例外情况,Profil setter开始接收null作为值

System.Windows.Data Error: 23 : Cannot convert 'BanquePrivee.AssuranceVie.Net.BE.ProfilBE' from type 'ProfilBE' to type 'System.Int64' for 'fr-FR' culture with default conversions; consider using Converter property of Binding. NotSupportedException:'System.NotSupportedException: Int64Converter cannot convert from BanquePrivee.AssuranceVie.Net.BE.ProfilBE.
   at System.ComponentModel.TypeConverter.GetConvertFromException(Object value)
   at System.ComponentModel.TypeConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   at System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
   at MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)'

System.Windows.Data Error: 7 : ConvertBack cannot convert value 'BanquePrivee.AssuranceVie.Net.BE.ProfilBE' (type 'ProfilBE'). BindingExpression:Path=Profil.IdProfil; DataItem='UserBE' (HashCode=59629589); target element is 'ComboBox' (Name=''); target property is 'SelectedValue' (type 'Object') NotSupportedException:'System.NotSupportedException: Int64Converter cannot convert from BanquePrivee.AssuranceVie.Net.BE.ProfilBE.
   at MS.Internal.Data.DefaultValueConverter.ConvertHelper(Object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, Boolean isForward)
   at MS.Internal.Data.ObjectTargetConverter.ConvertBack(Object o, Type type, Object parameter, CultureInfo culture)
   at System.Windows.Data.BindingExpression.ConvertBackHelper(IValueConverter converter, Object value, Type sourceType, Object parameter, CultureInfo culture)'

很明显SelectedValue="{Binding Profil.IdProfil}"是问题,但我不明白为什么 我不明白为什么在某些时候它试图将IdProfil强制转换为ProfilBE。我不应该在那里使用转换器 我做了很多测试,数据看起来很好(没有空值,不应该等等)。

有人能指出我做错了什么吗?

2 个答案:

答案 0 :(得分:1)

我认为这与设置SelectedValueSelectedItem有关。两个属性都做同样的事情:他们设置选定的项目。但是,可以根据Value的内容按SelectedValuePath设置,另一个只是将其设置为ItemsSource中的项目。

我猜测WPF在某处感到困惑,并试图将SelectedValueint)设置为SelectedItem,其类型为ProfilBE,抛出异常是因为ProfilBE不能转换为int。

但无论如何,要修复它,请尝试删除ComboBox中的SelectedItem绑定

<ComboBox ItemsSource="{Binding DataContext.ListeProfils, ElementName=lv_UserProfils}" 
    DisplayMemberPath="LibProfil" SelectedValuePath="IdProfil" 
    SelectedValue="{Binding Profil.IdProfil}" 
    Width="200" />

答案 1 :(得分:0)

WPF正在虚拟化当前未显示的对象。 但是当我尝试向上滚动时,它似乎尝试做一些对虚拟化的项目不起作用并且即将再次出现在屏幕上的内容。

我使用的解决方案是使用VirtualizingStackPanel.IsVirtualizing="False"禁用ListView的虚拟化。它的性能很小,但现在可以使用了。

<ListView Name="lv_UserProfils" ItemsSource="{Binding ListeEntites}" AlternationCount="2" VirtualizingStackPanel.IsVirtualizing="False"
        ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
    <ListView.View>
        [...]
    </ListView.View>
</ListView>