How do I set multiple items to a Windows Runtime vector in a single call?

Raymond Chen

Suppose you want to set multiple items to a Windows Runtime IVector<T>. This is common in the cases where the system provides a vector that you are expected to fill with stuff. For example:

// C#
var picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".gif");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".png");

Surely there is an easier way to do this than calling Add multiple times, right?

Yes, there is an easier way, but the easier way depends on what language you are using. Each language expresses the Windows Runtime IVector<T> in its own language-specific way.

C# projects the IVector<T> as an System.Collections.Generic.IList<T>. You can use object and collection initializer syntax to fill the collection as part of the object initialization.

// C#
var picker = new FileOpenPicker()
    {
        FileTypeFilter = { ".bmp", ".gif", ".jpg", ".png" }
    };

Note, however, that this syntax works only in an object initializer.

// doesn't work
picker.FileTypeFilter = { ".bmp", ".gif", ".jpg", ".png" };

You might be tempted to use List<T>.AddRange(), but that doesn’t work either because what you have is an IList<T>, not a List<T>. Many people have solved this problem by using an extension method.

C++/WinRT exposes the IVector<T> very close to how it is defined in the ABI. In particular, there is a Replace­All method.

// C++/WinRT
auto picker = FileOpenPicker();
picker.FileTypeFilter().
    ReplaceAll({ L".bmp", L".gif", L".jpg", L".png" });

C++/CX is a bit more annoying because you have to pass a Platform::Array^ to the Replace­All method, and those Array^ types are frustrating to manufacture.

// C++/CX
auto picker = ref new FileOpenPicker();
String^ extensions[]{ L".bmp", L".gif", L".jpg", L".png" };
picker->FileTypeFilter->ReplaceAll(
    ArrayReference<String^>(extensions, _ARRAYSIZE(extensions)));

Sadly, there are no deduction guides for Array­Reference so you end up having to repeat String^.

JavaScript projects IVector<T> as a native JavaScript Array, and those objects have quite a rich panoply of available methods. One that is useful for us today is splice.

// JavaScript
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.fileTypeFilter.splice(0, 0, ".bmp", ".gif", ".jpg", ".png");

The JavaScript projection is kind enough to project the original replaceAll method as well, which leads us to this somewhat simpler version:

// JavaScript
var picker = new Windows.Storage.Pickers.FileOpenPicker();
picker.fileTypeFilter.replaceAll([ ".bmp", ".gif", ".jpg", ".png" ]);

3 comments

Discussion is closed. Login to edit/delete existing comments.

  • Alexis Ryan 0

    being unable to use collection initializer syntax to assign a collection in C# is a little annoying but can work around it by creating a struct that take a collection as an argument to its constructor and initializes a property to that collection and then use a collection initializer on that property and it just works cause it actually just calls add for each value in the initializer, after the constructor is called
    Something like this for the struct

        public struct collectioninit
        {
            public T collection { get; set; }
    
            public collectioninit(T col)
            {
                collection = col;
            }
        };

    and then using it like this

                List<int> list = new List<int>();
                collectioninit<List<int>> cl = new collectioninit<List<int>>(list)
                {
                    collection = { 0, 1, 2, 3, 4 },
        
    
                };
    
            Console.WriteLine(string.Join(",",list)); // prints 0,1,2,3,4
    

    Really not something i would rely on to work and wouldn’t use it in any sort of production code.

    • Danstur 0

      You just replaced `list = new List{ 0, 1, 2, 3, 4 }` which is 37 characters long with a 102 character long monstrosity where I have to look up the struct definition to understand what it is doing.

      So yeah, please don’t use that one in production code or anywhere else except for obfuscation contests 😉

  • David Trapp 0

    The JavaScript example seems a bit weird. `array.splice(0, 0, a, b, c)` does the same as `array.unshift(a, b, c)` (which is shorter) – inserting the elements at the start of the array (not removing anything). You could also do `array.push(a, b, c)` to insert at the end instead. If you wanted to replace the contents, you’d need to write `array.splice(0, array.length, a, b, c)`.

Feedback usabilla icon