当ListView绑定到带转换器的

时间:2017-11-17 03:01:40

标签: c# wpf binding uicollectionview converter

我的ViewModel中有一个ICollectionView:

public class ContactsPanelViewModel : ViewModelBase
{
    private ICollectionView accountContactsView;
    public ICollectionView AccountContactsView
    {
        get => accountContactsView;
        set => NotifyPropertyChangedAndSet(ref accountContactsView, value);
    }
public ContactsPanelViewModel()
    {
        AccountContactsView = CollectionViewSource.GetDefaultView(G.AccountContacts); //G.AccountContacts is an IEnumarable<Contact> object
        AccountContactsView.SortDescriptions.Add(new SortDescription("FullName_LastNameFirst", ListSortDirection.Ascending));
        AccountContactsView.CurrentChanged += NewContactSelected;
        AccountContactsView.MoveCurrentToFirst();
    }
}

这是它所绑定的列表:

<ListView 
      x:Name="ContactList" 
      HorizontalAlignment="Left" 
      ItemsSource="{Binding Path=AccountContactsView, Converter={StaticResource ContactCardConverter}}"
      IsSynchronizedWithCurrentItem="True"/>

这是我创建的转换器:

public class ContactCardConverter : IValueConverter
{
    public object Convert(object Value, Type TargetType, object Parameter, CultureInfo Culture)
    {
        if (Value is ListCollectionView)
        {
            List<ContactCard> contactCards = new List<ContactCard>(); //ContactCard is a UserControl
            ListCollectionView data = Value as ListCollectionView;
            if (data.Count > 0 && data.GetItemAt(0) is Contact)
            {
                foreach(Contact contact in data)
                {
                    contactCards.Add(new ContactCard(contact));
                }
                return contactCards;
            }
            else
            {
                return null;
            }
        }
        else
        {
            return null;
        }
    }

    public object ConvertBack(object Value, Type TargetType, object Parameter, CultureInfo Culture)
    {
        if (Value is ContactCard)
        {
            return (Value as ContactCard).Contact;
        }
        else
        {
            return null;
        }
    }
}

问题在于,因为我使用转换器,CurrentItem选项更改时ICollectionView ListView中的ICollectionView未同步。转换器肯定是问题,因为移除转换器使其工作完美。

我在ConvertBack函数中添加了一个函数,认为如果使用了转换器,它会调用它,但它不起作用。

理论上我可以创建ContactCard类型的Contact(这是一个UserControl),但是从我理解的ViewModel应该不应该这样做不依赖于View的外观。这也会增加一些complecity,因为我需要保持ICollectionView与我的实际<!DOCTYPE html> <html> <head> <style> #map { height: 400px; width: 100%; } </style> </head> <body> <h3>My Google Maps Demo</h3> <div id="map"></div> <script> function initMap() { var direccion=[ { lugar:'CICESE', lat:31.8675375, lng: -116.6686867 }, { lugar: 'Casa', lat:31.8915163, lng:-116.6879557 } ]; var uluru = {lat: direccion.lat, lng: direccion.lng};//{lat: -25.363, lng: 131.044}; var map = new google.maps.Map(document.getElementById('map'), { zoom: 4, center: uluru }); var marker = new google.maps.Marker({ position: uluru, map: map }); } </script> <script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDgMyVeh8DwebGfZHjiNjyle4xFe9pKSdc&callback=initMap"> </script> </body> </html>对象集合同步。

当ListView使用转换器时,同步ListView和ICollectionView的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

正确的方法是不要使用转换器。

您不应该将viewmodel-CollectionView转换为List(如您的情况)或转换器中的其他CollectionView,否则如果您在转换器中创建了CollectionView,则会同步您的视图(和IsSynchronizedWithCurrentItem工作正常)反对转换器创建的集合。列表无法同步,因为它未实现IColectionView且未CurrentItem

正确的方法是不使用转换器并将ContactCard - UserControl放到ListView.ItemTemplate

<ListView.ItemTemplate>
    <DataTemplate>
        <youCustomCtlNameSpace:ContactCard Contact="{Binding}"/>
     </DataTemplate>
</ListView.ItemTemplate>

如果你强制要使用转换器,那么IsSynchronizedWithCurrentItem没有任何意义,你必须自己同步V和VM,通过绑定转换器到ListView.SelectedItem,你的Contact必须保持对UI对象的引用(如果你没有依赖于View,请遵守它的MVVM:Is MVVM pattern broken?)。但正如我已经指出的那样,它不是首选方式!