/ src / modules / cmdpal / Core / Microsoft.CmdPal.Core.ViewModels / IconDataViewModel.cs
IconDataViewModel.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using CommunityToolkit.Mvvm.ComponentModel;
 6  using Microsoft.CmdPal.Core.ViewModels.Models;
 7  using Microsoft.CommandPalette.Extensions;
 8  using Microsoft.CommandPalette.Extensions.Toolkit;
 9  using Windows.Storage.Streams;
10  
11  namespace Microsoft.CmdPal.Core.ViewModels;
12  
13  public partial class IconDataViewModel : ObservableObject, IIconData
14  {
15      private readonly ExtensionObject<IIconData> _model = new(null);
16  
17      // If the extension previously gave us a Data, then died, the data will
18      // throw if we actually try to read it, but the pointer itself won't be
19      // null, so this is relatively safe.
20      public bool HasIcon => !string.IsNullOrEmpty(Icon) || Data.Unsafe is not null;
21  
22      // Locally cached properties from IIconData.
23      public string Icon { get; private set; } = string.Empty;
24  
25      // Streams are not trivially copy-able, so we can't copy the data locally
26      // first. Hence why we're sticking this into an ExtensionObject
27      public ExtensionObject<IRandomAccessStreamReference> Data { get; private set; } = new(null);
28  
29      IRandomAccessStreamReference? IIconData.Data => Data.Unsafe;
30  
31      public string? FontFamily { get; private set; }
32  
33      public IconDataViewModel(IIconData? icon)
34      {
35          _model = new(icon);
36      }
37  
38      // Unsafe, needs to be called on BG thread
39      public void InitializeProperties()
40      {
41          var model = _model.Unsafe;
42          if (model is null)
43          {
44              return;
45          }
46  
47          Icon = model.Icon;
48          Data = new(model.Data);
49  
50          if (model is IExtendedAttributesProvider icon2)
51          {
52              var props = icon2.GetProperties();
53  
54              // From Raymond Chen:
55              // Make sure you don't try do do something like
56              //    icon2.GetProperties().TryGetValue("awesomeKey", out var awesomeValue);
57              //    icon2.GetProperties().TryGetValue("slackerKey", out var slackerValue);
58              // because each call to GetProperties() is a cross process hop, and if you
59              // marshal-by-value the property set, then you don't want to throw it away and
60              // re-marshal it for every property. MAKE SURE YOU CACHE IT.
61              if (props?.TryGetValue(WellKnownExtensionAttributes.FontFamily, out var family) ?? false)
62              {
63                  FontFamily = family as string;
64              }
65          }
66      }
67  }