mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 02:36:19 +02:00
CmdPal: Implement IDetailsCommand in details (#39911)
Implemented IDetailsCommands in details. This will close #38339. This works very similar to Tags in that it is a list of commands. This was done to allow for styling without the 12 spacing of the ItemsRepeater and looks like you'd find in the OS-inbox like:   Also added to our sample extension: 
This commit is contained in:
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using Microsoft.CmdPal.UI.ViewModels.Models;
|
||||||
|
using Microsoft.CommandPalette.Extensions;
|
||||||
|
|
||||||
|
namespace Microsoft.CmdPal.UI.ViewModels;
|
||||||
|
|
||||||
|
public partial class DetailsCommandsViewModel(
|
||||||
|
IDetailsElement _detailsElement,
|
||||||
|
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
|
||||||
|
{
|
||||||
|
public List<CommandViewModel> Commands { get; private set; } = [];
|
||||||
|
|
||||||
|
public bool HasCommands => Commands.Count > 0;
|
||||||
|
|
||||||
|
private readonly ExtensionObject<IDetailsCommands> _dataModel =
|
||||||
|
new(_detailsElement.Data as IDetailsCommands);
|
||||||
|
|
||||||
|
public override void InitializeProperties()
|
||||||
|
{
|
||||||
|
base.InitializeProperties();
|
||||||
|
var model = _dataModel.Unsafe;
|
||||||
|
if (model == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Commands = model
|
||||||
|
.Commands?
|
||||||
|
.Select(c =>
|
||||||
|
{
|
||||||
|
var vm = new CommandViewModel(c, PageContext);
|
||||||
|
vm.InitializeProperties();
|
||||||
|
return vm;
|
||||||
|
})
|
||||||
|
.ToList() ?? [];
|
||||||
|
UpdateProperty(nameof(HasCommands));
|
||||||
|
UpdateProperty(nameof(Commands));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
|
|||||||
{
|
{
|
||||||
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext),
|
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext),
|
||||||
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext),
|
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext),
|
||||||
|
IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext),
|
||||||
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext),
|
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext),
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ public partial class DetailsDataTemplateSelector : DataTemplateSelector
|
|||||||
|
|
||||||
public DataTemplate? TagTemplate { get; set; }
|
public DataTemplate? TagTemplate { get; set; }
|
||||||
|
|
||||||
|
public DataTemplate? CommandTemplate { get; set; }
|
||||||
|
|
||||||
protected override DataTemplate? SelectTemplateCore(object item)
|
protected override DataTemplate? SelectTemplateCore(object item)
|
||||||
{
|
{
|
||||||
if (item is DetailsElementViewModel element)
|
if (item is DetailsElementViewModel element)
|
||||||
@@ -27,6 +29,7 @@ public partial class DetailsDataTemplateSelector : DataTemplateSelector
|
|||||||
{
|
{
|
||||||
DetailsSeparatorViewModel => SeparatorTemplate,
|
DetailsSeparatorViewModel => SeparatorTemplate,
|
||||||
DetailsLinkViewModel => LinkTemplate,
|
DetailsLinkViewModel => LinkTemplate,
|
||||||
|
DetailsCommandsViewModel => CommandTemplate,
|
||||||
DetailsTagsViewModel => TagTemplate,
|
DetailsTagsViewModel => TagTemplate,
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
<cmdpalUI:DetailsDataTemplateSelector
|
<cmdpalUI:DetailsDataTemplateSelector
|
||||||
x:Key="DetailsDataTemplateSelector"
|
x:Key="DetailsDataTemplateSelector"
|
||||||
|
CommandTemplate="{StaticResource DetailsCommandsTemplate}"
|
||||||
LinkTemplate="{StaticResource DetailsLinkTemplate}"
|
LinkTemplate="{StaticResource DetailsLinkTemplate}"
|
||||||
SeparatorTemplate="{StaticResource DetailsSeparatorTemplate}"
|
SeparatorTemplate="{StaticResource DetailsSeparatorTemplate}"
|
||||||
TagTemplate="{StaticResource DetailsTagsTemplate}" />
|
TagTemplate="{StaticResource DetailsTagsTemplate}" />
|
||||||
@@ -50,6 +51,27 @@
|
|||||||
ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" />
|
ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
|
<DataTemplate x:Key="CommandTemplate" x:DataType="viewModels:CommandViewModel">
|
||||||
|
<StackPanel Orientation="Vertical">
|
||||||
|
<Button
|
||||||
|
Name="Command"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Left"
|
||||||
|
Click="Command_Click"
|
||||||
|
Style="{StaticResource SubtleButtonStyle}">
|
||||||
|
<StackPanel VerticalAlignment="Center" Orientation="Horizontal">
|
||||||
|
<cpcontrols:IconBox
|
||||||
|
Width="16"
|
||||||
|
Height="16"
|
||||||
|
Margin="0,3,8,0"
|
||||||
|
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||||
|
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||||
|
<TextBlock Text="{x:Bind Name}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="DetailsLinkTemplate" x:DataType="viewModels:DetailsLinkViewModel">
|
<DataTemplate x:Key="DetailsLinkTemplate" x:DataType="viewModels:DetailsLinkViewModel">
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
@@ -71,6 +93,18 @@
|
|||||||
Visibility="{x:Bind IsLink, Mode=OneWay}" />
|
Visibility="{x:Bind IsLink, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
<DataTemplate x:Key="DetailsCommandsTemplate" x:DataType="viewModels:DetailsCommandsViewModel">
|
||||||
|
<StackPanel Orientation="Vertical" Spacing="4">
|
||||||
|
<TextBlock
|
||||||
|
IsTextSelectionEnabled="True"
|
||||||
|
Text="{x:Bind Key, Mode=OneWay}"
|
||||||
|
TextWrapping="WrapWholeWords" />
|
||||||
|
<ItemsControl
|
||||||
|
ItemTemplate="{StaticResource CommandTemplate}"
|
||||||
|
ItemsSource="{x:Bind Commands, Mode=OneWay}"
|
||||||
|
Visibility="{x:Bind HasCommands, Mode=OneWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
<DataTemplate x:Key="DetailsSeparatorTemplate" x:DataType="viewModels:DetailsSeparatorViewModel">
|
<DataTemplate x:Key="DetailsSeparatorTemplate" x:DataType="viewModels:DetailsSeparatorViewModel">
|
||||||
<StackPanel Margin="0,8,8,0" Orientation="Vertical">
|
<StackPanel Margin="0,8,8,0" Orientation="Vertical">
|
||||||
<Border
|
<Border
|
||||||
|
|||||||
@@ -629,4 +629,12 @@ public sealed partial class ShellPage : Microsoft.UI.Xaml.Controls.Page,
|
|||||||
return iconInfoVM?.HasIcon(requestedTheme == Microsoft.UI.Xaml.ElementTheme.Light) ?? false;
|
return iconInfoVM?.HasIcon(requestedTheme == Microsoft.UI.Xaml.ElementTheme.Light) ?? false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Command_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is Button button && button.DataContext is CommandViewModel commandViewModel)
|
||||||
|
{
|
||||||
|
WeakReferenceMessenger.Default.Send<PerformCommandMessage>(new(commandViewModel.Model));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using Microsoft.CommandPalette.Extensions;
|
using Microsoft.CommandPalette.Extensions;
|
||||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
|
||||||
namespace SamplePagesExtension;
|
namespace SamplePagesExtension;
|
||||||
|
|
||||||
@@ -129,6 +130,25 @@ internal sealed partial class SampleListPageWithDetails : ListPage
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
new DetailsElement()
|
||||||
|
{
|
||||||
|
Key = "Commands",
|
||||||
|
Data = new DetailsCommands()
|
||||||
|
{
|
||||||
|
Commands = [
|
||||||
|
new ToastCommand("Hey! You clicked it!", MessageState.Success)
|
||||||
|
{
|
||||||
|
Name = "Do something amazing",
|
||||||
|
Icon = new("\uE945"),
|
||||||
|
},
|
||||||
|
new ToastCommand("I warned you!", MessageState.Error)
|
||||||
|
{
|
||||||
|
Name = "Don't click me",
|
||||||
|
Icon = new("\uEA39"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
|
||||||
public partial class DetailsCommand : IDetailsCommand
|
public partial class DetailsCommands : IDetailsCommands
|
||||||
{
|
{
|
||||||
public ICommand? Command { get; set; }
|
public ICommand[]? Commands { get; set; }
|
||||||
}
|
}
|
||||||
@@ -182,8 +182,8 @@ namespace Microsoft.CommandPalette.Extensions
|
|||||||
String Text { get; };
|
String Text { get; };
|
||||||
}
|
}
|
||||||
[contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]
|
[contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]
|
||||||
interface IDetailsCommand requires IDetailsData {
|
interface IDetailsCommands requires IDetailsData {
|
||||||
ICommand Command { get; };
|
ICommand[] Commands { get; };
|
||||||
}
|
}
|
||||||
[uuid("58070392-02bb-4e89-9beb-47ceb8c3d741")]
|
[uuid("58070392-02bb-4e89-9beb-47ceb8c3d741")]
|
||||||
[contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]
|
[contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]
|
||||||
|
|||||||
Reference in New Issue
Block a user