Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wpf ICollectionView Binding item cannot resolve property of type object

I have bound a GridView with an ICollectionView in the XAML designer the properties are not known because the entity in the CollectionView have been transformed into type Object and the entity properties can't be accessed, it runs fine no error but the designer shows it as an error, if I bind to the collection I can access the properties fine

Example the entity is a Person with a string Name property I place them in an ObservableCollection<Person> and get the view from it and bind it to the GridView.ItemsSource now when I try to set the column header DataMemberBinding.FirstName property the designer shows it as an error

Cannot Resolve property 'FirstName' in data Context of type object

Is it a bug or is it Resharper playing tricks on me

Sample code:

public class Person 
{
    public string FirstName{
       get { return _firstName; }
       set { SetPropertyValue("FirstName", ref _firstName, value); }
    }
}
public class DataService 
{
    public IDataSource DataContext { get; set; }
    public ICollectionView PersonCollection{ get; set; }

    public DataService()
    {
        DataContext = new DataSource();
        //QueryableCollectionView is from Telerik 
        //but if i use any other CollectionView same thing
        //DataContext Persons is an ObservableCollection<Person> Persons
        PersonCollection = new QueryableCollectionView(DataContext.Persons);
    }
}

<telerik:RadGridView x:Name="ParentGrid" 
    ItemsSource="{Binding DataService.PersonCollection}"
    AutoGenerateColumns="False">
    <telerik:RadGridView.Columns >
        <telerik:GridViewDataColumn Header="{lex:Loc Key=FirstName}"  
            DataMemberBinding="{Binding FirstName}"/>
    </telerik:RadGridView.Columns>
</telerik:RadGridView>

enter image description here

like image 627
ramon22 Avatar asked Nov 27 '13 22:11

ramon22


2 Answers

The warnings that Resharper is giving you in the XAML view is because the design-time view of the control does not know what type it's data-context is. You can use a d:DesignInstance to help with your bindings.

Add the following (replacing Assembly/Namespace/Binding Target names appropriately)

<UserControl x:Class="MyNamespace.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup‐compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:lcl="clr‐namespace:MyAssembly"
d:DataContext="{d:DesignInstance Type=lcl:ViewModel}">
like image 118
robowahoo Avatar answered Oct 22 '22 11:10

robowahoo


Your entity has not been transformed in object, it's because the interface ICollectionView is not a generic collection so ReSharper has no way to know that it holds a collection of Person.

You can create a generic version of ICollectionView and use it for your PersonCollection property as demonstrated in this post https://benoitpatra.com/2014/10/12/a-generic-version-of-icollectionview-used-in-a-mvvm-searchable-list/.

First some interfaces:

public interface ICollectionView<T> : IEnumerable<T>, ICollectionView
{
}

public interface IEditableCollectionView<T> : IEditableCollectionView
{
}

The implementation:

public class GenericCollectionView<T> : ICollectionView<T>, IEditableCollectionView<T>
{
    readonly ListCollectionView collectionView;

    public CultureInfo Culture
    {
        get => collectionView.Culture;
        set => collectionView.Culture = value;
    }

    public IEnumerable SourceCollection => collectionView.SourceCollection;

    public Predicate<object> Filter
    {
        get => collectionView.Filter;
        set => collectionView.Filter = value;
    }

    public bool CanFilter => collectionView.CanFilter;

    public SortDescriptionCollection SortDescriptions => collectionView.SortDescriptions;

    public bool CanSort => collectionView.CanSort;

    public bool CanGroup => collectionView.CanGroup;

    public ObservableCollection<GroupDescription> GroupDescriptions => collectionView.GroupDescriptions;

    public ReadOnlyObservableCollection<object> Groups => collectionView.Groups;

    public bool IsEmpty => collectionView.IsEmpty;

    public object CurrentItem => collectionView.CurrentItem;

    public int CurrentPosition => collectionView.CurrentPosition;

    public bool IsCurrentAfterLast => collectionView.IsCurrentAfterLast;

    public bool IsCurrentBeforeFirst => collectionView.IsCurrentBeforeFirst;

    public NewItemPlaceholderPosition NewItemPlaceholderPosition
    {
        get => collectionView.NewItemPlaceholderPosition;
        set => collectionView.NewItemPlaceholderPosition = value;
    }

    public bool CanAddNew => collectionView.CanAddNew;

    public bool IsAddingNew => collectionView.IsAddingNew;

    public object CurrentAddItem => collectionView.CurrentAddItem;

    public bool CanRemove => collectionView.CanRemove;

    public bool CanCancelEdit => collectionView.CanCancelEdit;

    public bool IsEditingItem => collectionView.IsEditingItem;

    public object CurrentEditItem => collectionView.CurrentEditItem;

    public event NotifyCollectionChangedEventHandler CollectionChanged
    {
        add => ((ICollectionView) collectionView).CollectionChanged += value;
        remove => ((ICollectionView) collectionView).CollectionChanged -= value;
    }

    public event CurrentChangingEventHandler CurrentChanging
    {
        add => ((ICollectionView) collectionView).CurrentChanging += value;
        remove => ((ICollectionView) collectionView).CurrentChanging -= value;
    }

    public event EventHandler CurrentChanged
    {
        add => ((ICollectionView) collectionView).CurrentChanged += value;
        remove => ((ICollectionView) collectionView).CurrentChanged -= value;
    }

    public GenericCollectionView([NotNull] ListCollectionView collectionView)
    {
        this.collectionView = collectionView ?? throw new ArgumentNullException(nameof(collectionView));
    }

    public IEnumerator<T> GetEnumerator()
    {
        return (IEnumerator<T>) ((ICollectionView) collectionView).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((ICollectionView) collectionView).GetEnumerator();
    }

    public bool Contains(object item)
    {
        return collectionView.Contains(item);
    }

    public void Refresh()
    {
        collectionView.Refresh();
    }

    public IDisposable DeferRefresh()
    {
        return collectionView.DeferRefresh();
    }

    public bool MoveCurrentToFirst()
    {
        return collectionView.MoveCurrentToFirst();
    }

    public bool MoveCurrentToLast()
    {
        return collectionView.MoveCurrentToLast();
    }

    public bool MoveCurrentToNext()
    {
        return collectionView.MoveCurrentToNext();
    }

    public bool MoveCurrentToPrevious()
    {
        return collectionView.MoveCurrentToPrevious();
    }

    public bool MoveCurrentTo(object item)
    {
        return collectionView.MoveCurrentTo(item);
    }

    public bool MoveCurrentToPosition(int position)
    {
        return collectionView.MoveCurrentToPosition(position);
    }

    public object AddNew()
    {
        return collectionView.AddNew();
    }

    public void CommitNew()
    {
        collectionView.CommitNew();
    }

    public void CancelNew()
    {
        collectionView.CancelNew();
    }

    public void RemoveAt(int index)
    {
        collectionView.RemoveAt(index);
    }

    public void Remove(object item)
    {
        collectionView.Remove(item);
    }

    public void EditItem(object item)
    {
        collectionView.EditItem(item);
    }

    public void CommitEdit()
    {
        collectionView.CommitEdit();
    }

    public void CancelEdit()
    {
        collectionView.CancelEdit();
    }
}

And finally the usage:

ICollectionView<Person> PersonCollectionView { get; }

In the constructor:

var view = (ListCollectionView) CollectionViewSource.GetDefaultView(PersonCollection);
PersonCollectionView = new GenericCollectionView<Person>(view);
like image 1
Maxence Avatar answered Oct 22 '22 11:10

Maxence