EDIT: If you're interested, you can clone the source code of the application from GitHub.
https://github.com/jamesqo/Sirloin
Here are the steps to repro:
git clone
the URL- open up the Sirloin.Example project (under src/Sirloin.Example) in VS
- double-click the Package.appxmanifest, go to Packaging, and generate the .pfx file (necessary since it gets gitignored, more info here)
- run the project under x86 and you should hit the exception
Original Post
I'm developing an app for Windows 10. I'm running into a problem where, for some reason, I'm unable to add a subclass of Object
to a collections of objects. Here is the code:
ObservableList.cs (basically a wrapper for List which implements IObservableVector
)
public sealed class ObservableList : IObservableVector<object>, IReadOnlyList<object>, INotifyPropertyChanged
{
private const string IndexerName = "Item[]";
// This is non-generic so we can expose it thru the .winmd component
private readonly List<object> list;
public event PropertyChangedEventHandler PropertyChanged;
public event VectorChangedEventHandler<object> VectorChanged;
public ObservableList()
{
this.list = new List<object>();
}
public ObservableList(IEnumerable<object> items)
{
this.list = new List<object>(items);
}
public int Count => list.Count;
int IReadOnlyCollection<object>.Count => Count;
public bool IsReadOnly => false;
public object this[int index]
{
get { return list[index]; }
set { list[index] = value; }
}
object IReadOnlyList<object>.this[int index] => this[index];
public int IndexOf(object item) => list.IndexOf(item);
public void Insert(int index, object item)
{
list.Insert(index, item);
OnPropertyChanged(nameof(Count));
OnPropertyChanged(IndexerName);
OnVectorChanged(CollectionChange.ItemInserted, (uint)index);
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
OnPropertyChanged(nameof(Count));
OnPropertyChanged(IndexerName);
OnVectorChanged(CollectionChange.ItemRemoved, (uint)index);
}
public void Add(object item) =>
Insert(this.Count, item);
public void Clear()
{
list.Clear();
OnPropertyChanged(nameof(Count));
OnVectorChanged(CollectionChange.Reset, 0);
}
public bool Contains(object item) => list.Contains(item);
public void CopyTo(object[] array, int arrayIndex) =>
list.CopyTo(array, arrayIndex);
public bool Remove(object item)
{
int index = this.IndexOf(item);
if (index == -1)
return false;
this.RemoveAt(index);
OnPropertyChanged(nameof(Count));
OnVectorChanged(CollectionChange.ItemRemoved, (uint)index);
return true;
}
public IEnumerator<object> GetEnumerator() => list.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
private void OnVectorChanged(CollectionChange change, uint index)
{
VectorChanged?.Invoke(this, new VectorChangedArgs(change, index));
}
private void OnPropertyChanged(string name)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
Relevant portion of AppView.xaml.cs:
public sealed partial class AppView : UserControl
{
// Some generic extensions I wrote to minimize boilerplate
public ObservableList LowerItems =>
this.GetValue<ObservableList>(LowerItemsProperty);
public static DependencyProperty LowerItemsProperty { get; } =
Dependency.Register<ObservableList, AppView>(nameof(LowerItems), LowerItemsPropertyChanged);
private static void LowerItemsPropertyChanged(AppView o, IPropertyChangedArgs<ObservableList> args)
{
var src = args.NewValue;
var dest = o.lowerView.Items;
dest.Clear();
foreach (var item in src) dest.Add(item);
}
}
MainPage.xaml (where I use the AppView)
<Page
x:Class="Sirloin.Example.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="using:Sirloin">
<s:AppView>
<!--This is the part that's failing-->
<s:AppView.LowerItems>
<s:MenuItem Symbol="Contact"/>
<s:MenuItem Symbol="Contact"/>
</s:AppView.LowerItems>
</s:AppView>
</Page>
For some reason, when I run the app, I'm getting this error:
Cannot add instance of type 'Sirloin.MenuItem' to a collection of type 'Sirloin.ObservableList'.
Seeing is how ObservableList
is essentially a collection of objects, and of course MenuItem
is a subclass of Object
, I don't see why this is the case. Do the types have to exactly match or something?
Unfortunately, I can't use generics here since I'm exposing the first two files as part of a winmd
component, which (bizarrely) means no public generic types. So I have to make everything that would be generic a collection of objects.