Where is the 'EnablePinning' property in the ribbon framework's recent items?

172 views Asked by At

The Windows ribbon framework markup supports an EnablePinning attribute for the recent items menu in the application menu:

<ApplicationMenu.RecentItems>
  <RecentItems CommandName="MRU" EnablePinning="true" />
</ApplicationMenu.RecentItems>

I expected that there would be a matching property that can be queried/updated at runtime, but I can't find a property key. Does anyone know if there is one, and, if so, what it is?

Alternatively, is there another way to turn pinning on/off at runtime? Neither the element nor its parent support application modes.

TIA

Clarification: What I'm trying to do is enable/disable pinning for the entire menu at runtime. I'm not concerned about the pin states of the individual items.

3

There are 3 answers

1
Daniel Lemke On

Hmm... this will be quite difficult to accomplish as the flag is defined in the XML which will be compiled into a resource file that is linked to the application and then loaded on start up. You could create another resource definition and reload the ribbon if you want to disable/enable the flagging, but that's quite a lot overhead and certainly noticeable from an users perspective as it requires the creation of a new window handle.

1
Daniel Lemke On

I'm not sure if you can modify the pinned state from existing entries but it's definitely possible to programmatically query the state and add new items with a specific state using the UI_PKEY_Pinned property: https://msdn.microsoft.com/en-us/library/windows/desktop/dd940401(v=vs.85).aspx

Wrappers such as the Windows Ribbon Framework for Delphi or the Windows Ribbon for WinForms (.NET) provide an easy access to the API model. This CodeProject article also describes how to query/add recent items using C#.

If you want to change the state during runtime, you could for example query the state of all items, remove them from the list, adjust whetever you need and add them to the list again. Didn't do that yet, could be worth a try however.

0
Tahtu On

I place the recent items by inside UpdateProperty

  TRecentItem = class(TInterfacedObject, IUISimplePropertySet)
    private
      FRecentFile: TSSettings.TRecentFile;
    protected
      function GetValue(const key: TUIPropertyKey; out value: TPropVariant): HRESULT; stdcall;
    public
      procedure Initialize(const RecentFile: TSSettings.TRecentFile); safecall;
    end;

function TMyForm.UpdateProperty(commandId: UInt32; const key: TUIPropertyKey;
  currentValue: PPropVariant; out newValue: TPropVariant): HRESULT;
var
  I: Integer;
  psa: PSafeArray;
  pv: Pointer;
  RecentItem: TRecentItem;
begin
  if (key = UI_PKEY_RecentItems) then
  begin
    psa := SafeArrayCreateVector(VT_UNKNOWN, 0, Settings.RecentFiles.Count);

    if (not Assigned(psa)) then
      Result := E_FAIL
    else
    begin
      for I := 0 to Settings.RecentFiles.Count - 1 do
      begin
        RecentItem := TRecentItem.NewInstance() as TRecentItem;
        RecentItem.Initialize(Settings.RecentFiles[I]);
        pv := Pointer(IUnknown(RecentItem));
        Check(SafeArrayPutElement(psa, I, pv^));
      end;

      Result := UIInitPropertyFromIUnknownArray(UI_PKEY_RecentItems, psa, PropVar);

      SafeArrayDestroy(psa);
    end;
  end;

If a pin was changed, I get this command while closing the application menu:

function TMyForm.Execute(commandId: UInt32; verb: _UIExecutionVerb;
  key: PUIPropertyKey; currentValue: PPropVariant;
  commandExecutionProperties: IUISimplePropertySet): HRESULT; stdcall;
var
  Count: Integer;
  I: Integer;
  Pinned: Boolean;
  psa: PSafeArray;
  pv: IUnknown;
  RecentFile: UInt32;
  SimplePropertySet: IUISimplePropertySet;
  Value: TPropVariant;
begin
  if ((commandId = cmdAppRecentItems)
    and Assigned(key) and (key^ = UI_PKEY_RecentItems)
    and Assigned(currentValue) and (currentValue^.vt = VT_ARRAY + VT_UNKNOWN)) then
  begin
    psa := nil;
    Result := UIPropertyToIUnknownArrayAlloc(key^, currentValue^, psa);
    if (Succeeded(Result)) then
    begin
      Result := SafeArrayGetUBound(psa, 1, Count);
      for I := 0 to Count do
        if (Succeeded(Result)) then
        begin
          Result := SafeArrayGetElement(psa, I, pv);
          if (Succeeded(Result) and Assigned(pv)) then
          begin
            Result := pv.QueryInterface(IUISimplePropertySet, SimplePropertySet);
            if (Succeeded(Result)) then
              Result := SimplePropertySet.GetValue(UI_PKEY_Pinned, Value);
            if (Succeeded(Result)) then
              Result := UIPropertyToBoolean(UI_PKEY_Pinned, Value, Pinned);
            if (Succeeded(Result)) then
              Settings.RecentFiles.SetPinned(I, Pinned);
          end;
        end;
      SafeArrayDestroy(psa);
    end;
  end
end;

... but I didn't find a documentation of this solution.