开发者

passing generic class with different type parameters between UserControls

I currently have a couple different user controls that provide the same functionality: three different buttons called Select All, Deselect All, and Toggle Selected. These perform actions on a list of items that implement my ICheckable interface in each user control. I wanted to unify this stuff so that the commands and buttons would all be defined in one place only--a new user control--instead of being duplicated in two different user controls. My problem is that in one user control I'm dealing with a list of my Template class, and the other user control has a list of a Defect class. Both Template and Defect implement ICheckable, meaning the Select All, Deselect All, and Toggle Selected apply to them.

I have a generic container class SelectableItems<T> that requires T fit these constraints: where T : ICheckable, IEquatable<T>, IDeepCloneable<T>. SelectableItems<T> provides an ObservableCollection<T> Items property, along with other useful properties such as bool IsAnyItemSelected, T SelectedItem, etc. These properties would be used in implementing the Select All, etc. commands. Both Template and Defect fit all those constraints. I was going to create a dependency property in my new user control to which I would bind a SelectableItems<Template> and SelectableItems<Defect> property from my other user controls. I don't think it's possible to do a generic dependency property, though, because I can't have a generic UserControl class since I'm using XAML. How should I go about this? I'm using .NET 3.5.

To sum up, this is what I want:

TemplateList user con开发者_运维技巧trol                             ItemSelection user control
-------------------------------------------           --------------------------
SelectableItems<Template> TemplateContainer ==Bind==> unknownType? ItemContainer

DefectList user control                           ItemSelection user control
---------------------------------------           --------------------------
SelectableItems<Defect> DefectContainer ==Bind==> unknownType? ItemContainer

Edit: I considered just adding dependency properties to my new ItemSelection user control for all the useful properties in the SelectableItems<T> view model, such as IsAnyItemSelected, etc. That would be fine for most of the properties, but I was hesitant to do it for ObservableCollection<T> Items because I hit the same generic problem as described above, and I didn't trust things to work okay if I just used IEnumerable instead of ObservableCollection<something>. Maybe I should make an ObservableCollection class that isn't generic (like in this question)?


Creating a non-generic ObservableCollection class and then using a value converter to convert my ObservableCollection<T> value to an ObservableCollection seems to have worked.

Here are the important parts of my ObservableCollection class:

public class ObservableCollection : ICollection<object>,
    INotifyCollectionChanged
{
    private ObservableCollection<object> _collection;

    public ObservableCollection()
    {
        _collection = new ObservableCollection<object>();
        _collection.CollectionChanged +=
            new NotifyCollectionChangedEventHandler(collectionChanged);
    }

    public ObservableCollection(IEnumerable items)
    {
        if (null == items)
        {
            throw new ArgumentNullException("items");
        }
        _collection = new ObservableCollection<object>();
        foreach (object item in items)
        {
            Add(item);
        }
        _collection.CollectionChanged +=
            new NotifyCollectionChangedEventHandler(collectionChanged);
    }

    ...stuff necessary to implement ICollection<object>...

    public event NotifyCollectionChangedEventHandler CollectionChanged;

    void collectionChanged(object sender,
        NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler handler = CollectionChanged;
        if (null != handler)
        {
            handler(this, e);
        }
    }
}

And here's the value converter:

public class EnumerableToObservableCollectionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        if (targetType != typeof(ObservableCollection))
        {
            throw new ArgumentException("Do not use this converter except " +
                "when going to ObservableCollection");
        }
        var enumerable = value as IEnumerable;
        if (null == enumerable)
        {
            return new ObservableCollection();
        }
        return new ObservableCollection(enumerable);
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        return value;
    }
}

And I bind like so:

<local:ItemSelection SelectedItems="{Binding Path=MyViewModel.SelectedItems,
    Mode=OneWay}"
    Items="{Binding Path=MyViewModel.Items, Mode=OneWay,
        Converter={StaticResource observCollConverter}}"
    IsAnyItemSelected="{Binding Path=MyViewModel.IsAnyItemSelected,
        Mode=OneWay}"/>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜