mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 11:48:06 +01:00
CmdPal: Fix grid views (#43991)
## Summary of the Pull Request
This PR fixes the crash due to binding to a trimmed property. For this
it converts runtime bindings on GridView to use `{x:Bind}` so this issue
can't happen in the future.
- Fixes a crash related to the `Visibility` property in gallery/grid
views when trimmed during AOT builds.
- Fixes ShowTitle and ShowSubtitle properties, they are now taken into
account in a view.
- Improves UI layout, removes some margins and maches the corner radius
of the item contaienr with the item content in the gallery view.
- Refactores gallery and grid views to move logic from the view to the
view model so we can x:Bind to them.
- Replaces `{Binding}` with `{x:Bind}` to improve performance and enable
compile-time binding validation.
- Properties related to grids are splatted on to the common
`IGridPropertiesViewModel` interface. Subclassing would add extra
overhead without substential benefit.
- Adds new samples to showcase various grid view configurations.
## Pictures? Pictures!
A) Gallery view (with title and subtitle)
<img width="909" height="583" alt="image"
src="https://github.com/user-attachments/assets/b807e7a8-412f-4817-8121-e3470c49e0c0"
/>
B) Gallery view (only title)
<img width="903" height="582" alt="image"
src="https://github.com/user-attachments/assets/b619d63f-04d0-42f2-9207-de256dc5e481"
/>
C) Gallery view (no title or subtitle)
<img width="900" height="583" alt="image"
src="https://github.com/user-attachments/assets/c48cd1fc-8f51-40c1-8bce-607916e9f742"
/>
D) Small icons
<img width="907" height="582" alt="image"
src="https://github.com/user-attachments/assets/8327da0a-fa45-443f-b52c-f0f1edd7b861"
/>
E) Medium icons (with labels)
<img width="914" height="588" alt="image"
src="https://github.com/user-attachments/assets/dee9fab1-54e8-45f8-96d7-502b121a6ac2"
/>
F) Medium icons (no labels)
<img width="915" height="588" alt="image"
src="https://github.com/user-attachments/assets/a32e8af2-6cb1-4106-91db-ca396253c0a3"
/>
<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist
- [x] Closes: #43973
<!-- - [ ] Closes: #yyy (add separate lines for additional resolved
issues) -->
- [ ] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [ ] **Tests:** Added/updated and all pass
- [ ] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx
<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments
<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed
This commit is contained in:
@@ -11,15 +11,15 @@ public class GalleryGridPropertiesViewModel : IGridPropertiesViewModel
|
|||||||
{
|
{
|
||||||
private readonly ExtensionObject<IGalleryGridLayout> _model;
|
private readonly ExtensionObject<IGalleryGridLayout> _model;
|
||||||
|
|
||||||
|
public bool ShowTitle { get; private set; }
|
||||||
|
|
||||||
|
public bool ShowSubtitle { get; private set; }
|
||||||
|
|
||||||
public GalleryGridPropertiesViewModel(IGalleryGridLayout galleryGridLayout)
|
public GalleryGridPropertiesViewModel(IGalleryGridLayout galleryGridLayout)
|
||||||
{
|
{
|
||||||
_model = new(galleryGridLayout);
|
_model = new(galleryGridLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowTitle { get; set; }
|
|
||||||
|
|
||||||
public bool ShowSubtitle { get; set; }
|
|
||||||
|
|
||||||
public void InitializeProperties()
|
public void InitializeProperties()
|
||||||
{
|
{
|
||||||
var model = _model.Unsafe;
|
var model = _model.Unsafe;
|
||||||
|
|||||||
@@ -6,5 +6,9 @@ namespace Microsoft.CmdPal.Core.ViewModels;
|
|||||||
|
|
||||||
public interface IGridPropertiesViewModel
|
public interface IGridPropertiesViewModel
|
||||||
{
|
{
|
||||||
|
bool ShowTitle { get; }
|
||||||
|
|
||||||
|
bool ShowSubtitle { get; }
|
||||||
|
|
||||||
void InitializeProperties();
|
void InitializeProperties();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,9 @@ using Microsoft.CommandPalette.Extensions.Toolkit;
|
|||||||
|
|
||||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||||
|
|
||||||
public partial class ListItemViewModel(IListItem model, WeakReference<IPageContext> context)
|
public partial class ListItemViewModel : CommandItemViewModel
|
||||||
: CommandItemViewModel(new(model), context)
|
|
||||||
{
|
{
|
||||||
public new ExtensionObject<IListItem> Model { get; } = new(model);
|
public new ExtensionObject<IListItem> Model { get; }
|
||||||
|
|
||||||
public List<TagViewModel>? Tags { get; set; }
|
public List<TagViewModel>? Tags { get; set; }
|
||||||
|
|
||||||
@@ -32,6 +31,40 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
|||||||
|
|
||||||
public string AccessibleName { get; private set; } = string.Empty;
|
public string AccessibleName { get; private set; } = string.Empty;
|
||||||
|
|
||||||
|
public bool ShowTitle { get; private set; }
|
||||||
|
|
||||||
|
public bool ShowSubtitle { get; private set; }
|
||||||
|
|
||||||
|
public bool LayoutShowsTitle
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref field, value))
|
||||||
|
{
|
||||||
|
UpdateShowsTitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool LayoutShowsSubtitle
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref field, value))
|
||||||
|
{
|
||||||
|
UpdateShowsSubtitle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListItemViewModel(IListItem model, WeakReference<IPageContext> context)
|
||||||
|
: base(new(model), context)
|
||||||
|
{
|
||||||
|
Model = new ExtensionObject<IListItem>(model);
|
||||||
|
}
|
||||||
|
|
||||||
public override void InitializeProperties()
|
public override void InitializeProperties()
|
||||||
{
|
{
|
||||||
if (IsInitialized)
|
if (IsInitialized)
|
||||||
@@ -93,16 +126,18 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
|||||||
|
|
||||||
switch (propertyName)
|
switch (propertyName)
|
||||||
{
|
{
|
||||||
case nameof(Tags):
|
case nameof(model.Tags):
|
||||||
UpdateTags(model.Tags);
|
UpdateTags(model.Tags);
|
||||||
break;
|
break;
|
||||||
case nameof(TextToSuggest):
|
case nameof(model.TextToSuggest):
|
||||||
this.TextToSuggest = model.TextToSuggest ?? string.Empty;
|
TextToSuggest = model.TextToSuggest ?? string.Empty;
|
||||||
|
UpdateProperty(nameof(TextToSuggest));
|
||||||
break;
|
break;
|
||||||
case nameof(Section):
|
case nameof(model.Section):
|
||||||
this.Section = model.Section ?? string.Empty;
|
Section = model.Section ?? string.Empty;
|
||||||
|
UpdateProperty(nameof(Section));
|
||||||
break;
|
break;
|
||||||
case nameof(Details):
|
case nameof(model.Details):
|
||||||
var extensionDetails = model.Details;
|
var extensionDetails = model.Details;
|
||||||
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
|
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
|
||||||
Details?.InitializeProperties();
|
Details?.InitializeProperties();
|
||||||
@@ -110,16 +145,24 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
|||||||
UpdateProperty(nameof(HasDetails));
|
UpdateProperty(nameof(HasDetails));
|
||||||
UpdateShowDetailsCommand();
|
UpdateShowDetailsCommand();
|
||||||
break;
|
break;
|
||||||
case nameof(MoreCommands):
|
case nameof(model.MoreCommands):
|
||||||
|
UpdateProperty(nameof(MoreCommands));
|
||||||
AddShowDetailsCommands();
|
AddShowDetailsCommands();
|
||||||
break;
|
break;
|
||||||
case nameof(Title):
|
case nameof(model.Title):
|
||||||
case nameof(Subtitle):
|
UpdateProperty(nameof(Title));
|
||||||
|
UpdateShowsTitle();
|
||||||
UpdateAccessibleName();
|
UpdateAccessibleName();
|
||||||
break;
|
break;
|
||||||
|
case nameof(model.Subtitle):
|
||||||
|
UpdateProperty(nameof(Subtitle));
|
||||||
|
UpdateShowsSubtitle();
|
||||||
|
UpdateAccessibleName();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
UpdateProperty(propertyName);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateProperty(propertyName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Do we want filters to match descriptions and other properties? Tags, etc... Yes?
|
// TODO: Do we want filters to match descriptions and other properties? Tags, etc... Yes?
|
||||||
@@ -206,11 +249,32 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
|||||||
// many COM exception issues.
|
// many COM exception issues.
|
||||||
Tags = [.. newTags];
|
Tags = [.. newTags];
|
||||||
|
|
||||||
UpdateProperty(nameof(Tags));
|
// We're already in UI thread, so just raise the events
|
||||||
UpdateProperty(nameof(HasTags));
|
OnPropertyChanged(nameof(Tags));
|
||||||
|
OnPropertyChanged(nameof(HasTags));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateShowsTitle()
|
||||||
|
{
|
||||||
|
var oldShowTitle = ShowTitle;
|
||||||
|
ShowTitle = LayoutShowsTitle;
|
||||||
|
if (oldShowTitle != ShowTitle)
|
||||||
|
{
|
||||||
|
UpdateProperty(nameof(ShowTitle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateShowsSubtitle()
|
||||||
|
{
|
||||||
|
var oldShowSubtitle = ShowSubtitle;
|
||||||
|
ShowSubtitle = LayoutShowsSubtitle && !string.IsNullOrWhiteSpace(Subtitle);
|
||||||
|
if (oldShowSubtitle != ShowSubtitle)
|
||||||
|
{
|
||||||
|
UpdateProperty(nameof(ShowSubtitle));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void UnsafeCleanup()
|
protected override void UnsafeCleanup()
|
||||||
{
|
{
|
||||||
base.UnsafeCleanup();
|
base.UnsafeCleanup();
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
|
|
||||||
// Observable from MVVM Toolkit will auto create public properties that use INotifyPropertyChange change
|
// Observable from MVVM Toolkit will auto create public properties that use INotifyPropertyChange change
|
||||||
// https://learn.microsoft.com/dotnet/communitytoolkit/mvvm/observablegroupedcollections for grouping support
|
// https://learn.microsoft.com/dotnet/communitytoolkit/mvvm/observablegroupedcollections for grouping support
|
||||||
[ObservableProperty]
|
public ObservableCollection<ListItemViewModel> FilteredItems { get; } = [];
|
||||||
public partial ObservableCollection<ListItemViewModel> FilteredItems { get; set; } = [];
|
|
||||||
|
|
||||||
public FiltersViewModel? Filters { get; set; }
|
public FiltersViewModel? Filters { get; set; }
|
||||||
|
|
||||||
@@ -224,6 +223,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
// TODO we can probably further optimize this by also keeping a
|
// TODO we can probably further optimize this by also keeping a
|
||||||
// HashSet of every ExtensionObject we currently have, and only
|
// HashSet of every ExtensionObject we currently have, and only
|
||||||
// building new viewmodels for the ones we haven't already built.
|
// building new viewmodels for the ones we haven't already built.
|
||||||
|
var showsTitle = GridProperties?.ShowTitle ?? true;
|
||||||
|
var showsSubtitle = GridProperties?.ShowSubtitle ?? true;
|
||||||
foreach (var item in newItems)
|
foreach (var item in newItems)
|
||||||
{
|
{
|
||||||
// Check for cancellation during item processing
|
// Check for cancellation during item processing
|
||||||
@@ -237,6 +238,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
// If an item fails to load, silently ignore it.
|
// If an item fails to load, silently ignore it.
|
||||||
if (viewModel.SafeFastInit())
|
if (viewModel.SafeFastInit())
|
||||||
{
|
{
|
||||||
|
viewModel.LayoutShowsTitle = showsTitle;
|
||||||
|
viewModel.LayoutShowsSubtitle = showsSubtitle;
|
||||||
newViewModels.Add(viewModel);
|
newViewModels.Add(viewModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -583,6 +586,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
|
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
|
||||||
GridProperties?.InitializeProperties();
|
GridProperties?.InitializeProperties();
|
||||||
UpdateProperty(nameof(GridProperties));
|
UpdateProperty(nameof(GridProperties));
|
||||||
|
ApplyLayoutToItems();
|
||||||
|
|
||||||
ShowDetails = model.ShowDetails;
|
ShowDetails = model.ShowDetails;
|
||||||
UpdateProperty(nameof(ShowDetails));
|
UpdateProperty(nameof(ShowDetails));
|
||||||
@@ -608,22 +612,15 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
model.ItemsChanged += Model_ItemsChanged;
|
model.ItemsChanged += Model_ItemsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private IGridPropertiesViewModel? LoadGridPropertiesViewModel(IGridProperties? gridProperties)
|
private static IGridPropertiesViewModel? LoadGridPropertiesViewModel(IGridProperties? gridProperties)
|
||||||
{
|
{
|
||||||
if (gridProperties is IMediumGridLayout mediumGridLayout)
|
return gridProperties switch
|
||||||
{
|
{
|
||||||
return new MediumGridPropertiesViewModel(mediumGridLayout);
|
IMediumGridLayout mediumGridLayout => new MediumGridPropertiesViewModel(mediumGridLayout),
|
||||||
}
|
IGalleryGridLayout galleryGridLayout => new GalleryGridPropertiesViewModel(galleryGridLayout),
|
||||||
else if (gridProperties is IGalleryGridLayout galleryGridLayout)
|
ISmallGridLayout smallGridLayout => new SmallGridPropertiesViewModel(smallGridLayout),
|
||||||
{
|
_ => null,
|
||||||
return new GalleryGridPropertiesViewModel(galleryGridLayout);
|
};
|
||||||
}
|
|
||||||
else if (gridProperties is ISmallGridLayout smallGridLayout)
|
|
||||||
{
|
|
||||||
return new SmallGridPropertiesViewModel(smallGridLayout);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadMoreIfNeeded()
|
public void LoadMoreIfNeeded()
|
||||||
@@ -685,6 +682,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
|
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
|
||||||
GridProperties?.InitializeProperties();
|
GridProperties?.InitializeProperties();
|
||||||
UpdateProperty(nameof(IsGridView));
|
UpdateProperty(nameof(IsGridView));
|
||||||
|
ApplyLayoutToItems();
|
||||||
break;
|
break;
|
||||||
case nameof(ShowDetails):
|
case nameof(ShowDetails):
|
||||||
ShowDetails = model.ShowDetails;
|
ShowDetails = model.ShowDetails;
|
||||||
@@ -730,6 +728,21 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyLayoutToItems()
|
||||||
|
{
|
||||||
|
lock (_listLock)
|
||||||
|
{
|
||||||
|
var showsTitle = GridProperties?.ShowTitle ?? true;
|
||||||
|
var showsSubtitle = GridProperties?.ShowSubtitle ?? true;
|
||||||
|
|
||||||
|
foreach (var item in Items)
|
||||||
|
{
|
||||||
|
item.LayoutShowsTitle = showsTitle;
|
||||||
|
item.LayoutShowsSubtitle = showsSubtitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
|
|||||||
@@ -11,13 +11,15 @@ public class MediumGridPropertiesViewModel : IGridPropertiesViewModel
|
|||||||
{
|
{
|
||||||
private readonly ExtensionObject<IMediumGridLayout> _model;
|
private readonly ExtensionObject<IMediumGridLayout> _model;
|
||||||
|
|
||||||
|
public bool ShowTitle { get; private set; }
|
||||||
|
|
||||||
|
public bool ShowSubtitle => false;
|
||||||
|
|
||||||
public MediumGridPropertiesViewModel(IMediumGridLayout mediumGridLayout)
|
public MediumGridPropertiesViewModel(IMediumGridLayout mediumGridLayout)
|
||||||
{
|
{
|
||||||
_model = new(mediumGridLayout);
|
_model = new(mediumGridLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ShowTitle { get; set; }
|
|
||||||
|
|
||||||
public void InitializeProperties()
|
public void InitializeProperties()
|
||||||
{
|
{
|
||||||
var model = _model.Unsafe;
|
var model = _model.Unsafe;
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ public class SmallGridPropertiesViewModel : IGridPropertiesViewModel
|
|||||||
{
|
{
|
||||||
private readonly ExtensionObject<ISmallGridLayout> _model;
|
private readonly ExtensionObject<ISmallGridLayout> _model;
|
||||||
|
|
||||||
|
public bool ShowTitle => false;
|
||||||
|
|
||||||
|
public bool ShowSubtitle => false;
|
||||||
|
|
||||||
public SmallGridPropertiesViewModel(ISmallGridLayout smallGridLayout)
|
public SmallGridPropertiesViewModel(ISmallGridLayout smallGridLayout)
|
||||||
{
|
{
|
||||||
_model = new(smallGridLayout);
|
_model = new(smallGridLayout);
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// 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.Core.ViewModels;
|
||||||
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Controls;
|
||||||
|
|
||||||
|
namespace Microsoft.CmdPal.UI;
|
||||||
|
|
||||||
|
internal sealed partial class GridItemContainerStyleSelector : StyleSelector
|
||||||
|
{
|
||||||
|
public IGridPropertiesViewModel? GridProperties { get; set; }
|
||||||
|
|
||||||
|
public Style? Small { get; set; }
|
||||||
|
|
||||||
|
public Style? Medium { get; set; }
|
||||||
|
|
||||||
|
public Style? Gallery { get; set; }
|
||||||
|
|
||||||
|
protected override Style? SelectStyleCore(object item, DependencyObject container)
|
||||||
|
{
|
||||||
|
return GridProperties switch
|
||||||
|
{
|
||||||
|
SmallGridPropertiesViewModel => Small,
|
||||||
|
MediumGridPropertiesViewModel => Medium,
|
||||||
|
GalleryGridPropertiesViewModel => Gallery,
|
||||||
|
_ => Medium,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,21 +20,12 @@ internal sealed partial class GridItemTemplateSelector : DataTemplateSelector
|
|||||||
|
|
||||||
protected override DataTemplate? SelectTemplateCore(object item, DependencyObject dependencyObject)
|
protected override DataTemplate? SelectTemplateCore(object item, DependencyObject dependencyObject)
|
||||||
{
|
{
|
||||||
DataTemplate? dataTemplate = Medium;
|
return GridProperties switch
|
||||||
|
|
||||||
if (GridProperties is SmallGridPropertiesViewModel)
|
|
||||||
{
|
{
|
||||||
dataTemplate = Small;
|
SmallGridPropertiesViewModel => Small,
|
||||||
}
|
MediumGridPropertiesViewModel => Medium,
|
||||||
else if (GridProperties is MediumGridPropertiesViewModel)
|
GalleryGridPropertiesViewModel => Gallery,
|
||||||
{
|
_ => Medium,
|
||||||
dataTemplate = Medium;
|
};
|
||||||
}
|
|
||||||
else if (GridProperties is GalleryGridPropertiesViewModel)
|
|
||||||
{
|
|
||||||
dataTemplate = Gallery;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dataTemplate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,33 +5,151 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:cmdpalUI="using:Microsoft.CmdPal.UI"
|
xmlns:cmdpalUI="using:Microsoft.CmdPal.UI"
|
||||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
|
||||||
xmlns:coreViewModels="using:Microsoft.CmdPal.Core.ViewModels"
|
xmlns:coreViewModels="using:Microsoft.CmdPal.Core.ViewModels"
|
||||||
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
|
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
|
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
|
||||||
xmlns:local="using:Microsoft.CmdPal.UI"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
|
||||||
xmlns:viewModels="using:Microsoft.CmdPal.UI.ViewModels"
|
|
||||||
x:Name="PageRoot"
|
x:Name="PageRoot"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
DataContext="{x:Bind ViewModel, Mode=OneWay}"
|
DataContext="{x:Bind ViewModel, Mode=OneWay}"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
|
|
||||||
<Page.Resources>
|
<Page.Resources>
|
||||||
<!-- TODO: Figure out what we want to do here for filtering/grouping and where -->
|
|
||||||
<!-- https://learn.microsoft.com/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.data.collectionviewsource -->
|
|
||||||
<!--<CollectionViewSource
|
|
||||||
x:Name="ItemsCVS"
|
|
||||||
IsSourceGrouped="True"
|
|
||||||
Source="{x:Bind ViewModel.Items, Mode=OneWay}" />-->
|
|
||||||
|
|
||||||
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
|
<!--
|
||||||
<converters:StringVisibilityConverter
|
GridViewItemCornerRadius is the corner radius defined in GridView template; make
|
||||||
x:Key="StringVisibilityConverter"
|
it bigger to match the radii of the gallery
|
||||||
EmptyValue="Collapsed"
|
-->
|
||||||
NotEmptyValue="Visible" />
|
<CornerRadius x:Key="GalleryGridViewItemContainerCornerRadius">6</CornerRadius>
|
||||||
|
<CornerRadius x:Key="IconGridViewItemContainerCornerRadius">4</CornerRadius>
|
||||||
|
<CornerRadius x:Key="GalleryGridViewItemRadius">4</CornerRadius>
|
||||||
|
<CornerRadius x:Key="SmallGridViewItemCornerRadius">8</CornerRadius>
|
||||||
|
<CornerRadius x:Key="MediumGridViewItemCornerRadius">8</CornerRadius>
|
||||||
|
|
||||||
|
<Style x:Key="IconGridViewItemStyle" TargetType="GridViewItem">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="GridViewItem">
|
||||||
|
<ListViewItemPresenter
|
||||||
|
x:Name="Root"
|
||||||
|
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
CheckBoxBorderBrush="{ThemeResource GridViewItemCheckBoxBorderBrush}"
|
||||||
|
CheckBoxBrush="{ThemeResource GridViewItemCheckBoxBrush}"
|
||||||
|
CheckBoxCornerRadius="{ThemeResource GridViewItemCheckBoxCornerRadius}"
|
||||||
|
CheckBoxDisabledBorderBrush="{ThemeResource GridViewItemCheckBoxDisabledBorderBrush}"
|
||||||
|
CheckBoxDisabledBrush="{ThemeResource GridViewItemCheckBoxDisabledBrush}"
|
||||||
|
CheckBoxPointerOverBorderBrush="{ThemeResource GridViewItemCheckBoxPointerOverBorderBrush}"
|
||||||
|
CheckBoxPointerOverBrush="{ThemeResource GridViewItemCheckBoxPointerOverBrush}"
|
||||||
|
CheckBoxPressedBorderBrush="{ThemeResource GridViewItemCheckBoxPressedBorderBrush}"
|
||||||
|
CheckBoxPressedBrush="{ThemeResource GridViewItemCheckBoxPressedBrush}"
|
||||||
|
CheckBoxSelectedBrush="{ThemeResource GridViewItemCheckBoxSelectedBrush}"
|
||||||
|
CheckBoxSelectedDisabledBrush="{ThemeResource GridViewItemCheckBoxSelectedDisabledBrush}"
|
||||||
|
CheckBoxSelectedPointerOverBrush="{ThemeResource GridViewItemCheckBoxSelectedPointerOverBrush}"
|
||||||
|
CheckBoxSelectedPressedBrush="{ThemeResource GridViewItemCheckBoxSelectedPressedBrush}"
|
||||||
|
CheckBrush="{ThemeResource GridViewItemCheckBrush}"
|
||||||
|
CheckDisabledBrush="{ThemeResource GridViewItemCheckDisabledBrush}"
|
||||||
|
CheckMode="{ThemeResource GridViewItemCheckMode}"
|
||||||
|
CheckPressedBrush="{ThemeResource GridViewItemCheckPressedBrush}"
|
||||||
|
ContentMargin="{TemplateBinding Padding}"
|
||||||
|
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||||
|
Control.IsTemplateFocusTarget="True"
|
||||||
|
CornerRadius="{StaticResource IconGridViewItemContainerCornerRadius}"
|
||||||
|
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
|
||||||
|
DragBackground="{ThemeResource GridViewItemDragBackground}"
|
||||||
|
DragForeground="{ThemeResource GridViewItemDragForeground}"
|
||||||
|
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
|
||||||
|
FocusBorderBrush="{ThemeResource GridViewItemFocusBorderBrush}"
|
||||||
|
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
|
||||||
|
FocusVisualPrimaryBrush="{TemplateBinding FocusVisualPrimaryBrush}"
|
||||||
|
FocusVisualPrimaryThickness="{TemplateBinding FocusVisualPrimaryThickness}"
|
||||||
|
FocusVisualSecondaryBrush="{TemplateBinding FocusVisualSecondaryBrush}"
|
||||||
|
FocusVisualSecondaryThickness="{TemplateBinding FocusVisualSecondaryThickness}"
|
||||||
|
PlaceholderBackground="{ThemeResource GridViewItemPlaceholderBackground}"
|
||||||
|
PointerOverBackground="{ThemeResource GridViewItemBackgroundPointerOver}"
|
||||||
|
PointerOverBorderBrush="{ThemeResource GridViewItemPointerOverBorderBrush}"
|
||||||
|
PointerOverForeground="{ThemeResource GridViewItemForegroundPointerOver}"
|
||||||
|
PressedBackground="{ThemeResource GridViewItemBackgroundPressed}"
|
||||||
|
ReorderHintOffset="{ThemeResource GridViewItemReorderHintThemeOffset}"
|
||||||
|
SelectedBackground="{ThemeResource GridViewItemBackgroundSelected}"
|
||||||
|
SelectedBorderBrush="{ThemeResource GridViewItemSelectedBorderBrush}"
|
||||||
|
SelectedBorderThickness="{ThemeResource GridViewItemSelectedBorderThickness}"
|
||||||
|
SelectedDisabledBackground="{ThemeResource GridViewItemBackgroundSelectedDisabled}"
|
||||||
|
SelectedDisabledBorderBrush="{ThemeResource GridViewItemSelectedDisabledBorderBrush}"
|
||||||
|
SelectedForeground="{ThemeResource GridViewItemForegroundSelected}"
|
||||||
|
SelectedInnerBorderBrush="{ThemeResource GridViewItemSelectedInnerBorderBrush}"
|
||||||
|
SelectedPointerOverBackground="{ThemeResource GridViewItemBackgroundSelectedPointerOver}"
|
||||||
|
SelectedPointerOverBorderBrush="{ThemeResource GridViewItemSelectedPointerOverBorderBrush}"
|
||||||
|
SelectedPressedBackground="{ThemeResource GridViewItemBackgroundSelectedPressed}"
|
||||||
|
SelectedPressedBorderBrush="{ThemeResource GridViewItemSelectedPressedBorderBrush}"
|
||||||
|
SelectionCheckMarkVisualEnabled="{ThemeResource GridViewItemSelectionCheckMarkVisualEnabled}" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="GalleryGridViewItemStyle" TargetType="GridViewItem">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="GridViewItem">
|
||||||
|
<ListViewItemPresenter
|
||||||
|
x:Name="Root"
|
||||||
|
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||||
|
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
|
CheckBoxBorderBrush="{ThemeResource GridViewItemCheckBoxBorderBrush}"
|
||||||
|
CheckBoxBrush="{ThemeResource GridViewItemCheckBoxBrush}"
|
||||||
|
CheckBoxCornerRadius="{ThemeResource GridViewItemCheckBoxCornerRadius}"
|
||||||
|
CheckBoxDisabledBorderBrush="{ThemeResource GridViewItemCheckBoxDisabledBorderBrush}"
|
||||||
|
CheckBoxDisabledBrush="{ThemeResource GridViewItemCheckBoxDisabledBrush}"
|
||||||
|
CheckBoxPointerOverBorderBrush="{ThemeResource GridViewItemCheckBoxPointerOverBorderBrush}"
|
||||||
|
CheckBoxPointerOverBrush="{ThemeResource GridViewItemCheckBoxPointerOverBrush}"
|
||||||
|
CheckBoxPressedBorderBrush="{ThemeResource GridViewItemCheckBoxPressedBorderBrush}"
|
||||||
|
CheckBoxPressedBrush="{ThemeResource GridViewItemCheckBoxPressedBrush}"
|
||||||
|
CheckBoxSelectedBrush="{ThemeResource GridViewItemCheckBoxSelectedBrush}"
|
||||||
|
CheckBoxSelectedDisabledBrush="{ThemeResource GridViewItemCheckBoxSelectedDisabledBrush}"
|
||||||
|
CheckBoxSelectedPointerOverBrush="{ThemeResource GridViewItemCheckBoxSelectedPointerOverBrush}"
|
||||||
|
CheckBoxSelectedPressedBrush="{ThemeResource GridViewItemCheckBoxSelectedPressedBrush}"
|
||||||
|
CheckBrush="{ThemeResource GridViewItemCheckBrush}"
|
||||||
|
CheckDisabledBrush="{ThemeResource GridViewItemCheckDisabledBrush}"
|
||||||
|
CheckMode="{ThemeResource GridViewItemCheckMode}"
|
||||||
|
CheckPressedBrush="{ThemeResource GridViewItemCheckPressedBrush}"
|
||||||
|
ContentMargin="{TemplateBinding Padding}"
|
||||||
|
ContentTransitions="{TemplateBinding ContentTransitions}"
|
||||||
|
Control.IsTemplateFocusTarget="True"
|
||||||
|
CornerRadius="{StaticResource GalleryGridViewItemContainerCornerRadius}"
|
||||||
|
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
|
||||||
|
DragBackground="{ThemeResource GridViewItemDragBackground}"
|
||||||
|
DragForeground="{ThemeResource GridViewItemDragForeground}"
|
||||||
|
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
|
||||||
|
FocusBorderBrush="{ThemeResource GridViewItemFocusBorderBrush}"
|
||||||
|
FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
|
||||||
|
FocusVisualPrimaryBrush="{TemplateBinding FocusVisualPrimaryBrush}"
|
||||||
|
FocusVisualPrimaryThickness="{TemplateBinding FocusVisualPrimaryThickness}"
|
||||||
|
FocusVisualSecondaryBrush="{TemplateBinding FocusVisualSecondaryBrush}"
|
||||||
|
FocusVisualSecondaryThickness="{TemplateBinding FocusVisualSecondaryThickness}"
|
||||||
|
PlaceholderBackground="{ThemeResource GridViewItemPlaceholderBackground}"
|
||||||
|
PointerOverBackground="{ThemeResource GridViewItemBackgroundPointerOver}"
|
||||||
|
PointerOverBorderBrush="{ThemeResource GridViewItemPointerOverBorderBrush}"
|
||||||
|
PointerOverForeground="{ThemeResource GridViewItemForegroundPointerOver}"
|
||||||
|
PressedBackground="{ThemeResource GridViewItemBackgroundPressed}"
|
||||||
|
ReorderHintOffset="{ThemeResource GridViewItemReorderHintThemeOffset}"
|
||||||
|
SelectedBackground="{ThemeResource GridViewItemBackgroundSelected}"
|
||||||
|
SelectedBorderBrush="{ThemeResource GridViewItemSelectedBorderBrush}"
|
||||||
|
SelectedBorderThickness="{ThemeResource GridViewItemSelectedBorderThickness}"
|
||||||
|
SelectedDisabledBackground="{ThemeResource GridViewItemBackgroundSelectedDisabled}"
|
||||||
|
SelectedDisabledBorderBrush="{ThemeResource GridViewItemSelectedDisabledBorderBrush}"
|
||||||
|
SelectedForeground="{ThemeResource GridViewItemForegroundSelected}"
|
||||||
|
SelectedInnerBorderBrush="{ThemeResource GridViewItemSelectedInnerBorderBrush}"
|
||||||
|
SelectedPointerOverBackground="{ThemeResource GridViewItemBackgroundSelectedPointerOver}"
|
||||||
|
SelectedPointerOverBorderBrush="{ThemeResource GridViewItemSelectedPointerOverBorderBrush}"
|
||||||
|
SelectedPressedBackground="{ThemeResource GridViewItemBackgroundSelectedPressed}"
|
||||||
|
SelectedPressedBorderBrush="{ThemeResource GridViewItemSelectedPressedBorderBrush}"
|
||||||
|
SelectionCheckMarkVisualEnabled="{ThemeResource GridViewItemSelectionCheckMarkVisualEnabled}" />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<DataTemplate x:Key="TagTemplate" x:DataType="coreViewModels:TagViewModel">
|
<DataTemplate x:Key="TagTemplate" x:DataType="coreViewModels:TagViewModel">
|
||||||
<cpcontrols:Tag
|
<cpcontrols:Tag
|
||||||
@@ -48,10 +166,17 @@
|
|||||||
x:Key="GridItemTemplateSelector"
|
x:Key="GridItemTemplateSelector"
|
||||||
x:DataType="coreViewModels:ListItemViewModel"
|
x:DataType="coreViewModels:ListItemViewModel"
|
||||||
Gallery="{StaticResource GalleryGridItemViewModelTemplate}"
|
Gallery="{StaticResource GalleryGridItemViewModelTemplate}"
|
||||||
GridProperties="{x:Bind ViewModel.GridProperties}"
|
GridProperties="{x:Bind ViewModel.GridProperties, Mode=OneWay}"
|
||||||
Medium="{StaticResource MediumGridItemViewModelTemplate}"
|
Medium="{StaticResource MediumGridItemViewModelTemplate}"
|
||||||
Small="{StaticResource SmallGridItemViewModelTemplate}" />
|
Small="{StaticResource SmallGridItemViewModelTemplate}" />
|
||||||
|
|
||||||
|
<cmdpalUI:GridItemContainerStyleSelector
|
||||||
|
x:Key="GridItemContainerStyleSelector"
|
||||||
|
Gallery="{StaticResource GalleryGridViewItemStyle}"
|
||||||
|
GridProperties="{x:Bind ViewModel.GridProperties, Mode=OneWay}"
|
||||||
|
Medium="{StaticResource IconGridViewItemStyle}"
|
||||||
|
Small="{StaticResource IconGridViewItemStyle}" />
|
||||||
|
|
||||||
<!-- https://learn.microsoft.com/windows/apps/design/controls/itemsview#specify-the-look-of-the-items -->
|
<!-- https://learn.microsoft.com/windows/apps/design/controls/itemsview#specify-the-look-of-the-items -->
|
||||||
<DataTemplate x:Key="ListItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
<DataTemplate x:Key="ListItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||||
<Grid
|
<Grid
|
||||||
@@ -94,7 +219,7 @@
|
|||||||
Text="{x:Bind Subtitle, Mode=OneWay}"
|
Text="{x:Bind Subtitle, Mode=OneWay}"
|
||||||
TextTrimming="CharacterEllipsis"
|
TextTrimming="CharacterEllipsis"
|
||||||
TextWrapping="NoWrap"
|
TextWrapping="NoWrap"
|
||||||
Visibility="{x:Bind Subtitle, Mode=OneWay, Converter={StaticResource StringVisibilityConverter}}" />
|
Visibility="{x:Bind ShowSubtitle, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
@@ -124,11 +249,11 @@
|
|||||||
Padding="8,16"
|
Padding="8,16"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AutomationProperties.Name="{x:Bind Title}"
|
AutomationProperties.Name="{x:Bind Title, Mode=OneWay}"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
CornerRadius="8"
|
CornerRadius="{StaticResource SmallGridViewItemCornerRadius}"
|
||||||
Orientation="Vertical"
|
Orientation="Vertical"
|
||||||
ToolTipService.ToolTip="{x:Bind Title}">
|
ToolTipService.ToolTip="{x:Bind Title, Mode=OneWay}">
|
||||||
|
|
||||||
<cpcontrols:IconBox
|
<cpcontrols:IconBox
|
||||||
x:Name="GridIconBorder"
|
x:Name="GridIconBorder"
|
||||||
@@ -145,23 +270,22 @@
|
|||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="MediumGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
<DataTemplate x:Key="MediumGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||||
<StackPanel
|
<Grid
|
||||||
Width="100"
|
Width="100"
|
||||||
Height="100"
|
Height="100"
|
||||||
Padding="8,16"
|
Padding="8"
|
||||||
HorizontalAlignment="Center"
|
AutomationProperties.Name="{x:Bind Title, Mode=OneWay}"
|
||||||
VerticalAlignment="Center"
|
CornerRadius="{StaticResource MediumGridViewItemCornerRadius}"
|
||||||
AutomationProperties.Name="{x:Bind Title}"
|
ToolTipService.ToolTip="{x:Bind Title, Mode=OneWay}">
|
||||||
BorderThickness="0"
|
<Grid.RowDefinitions>
|
||||||
CornerRadius="8"
|
<RowDefinition Height="*" />
|
||||||
Orientation="Vertical"
|
<RowDefinition Height="Auto" />
|
||||||
ToolTipService.ToolTip="{x:Bind Title}">
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<cpcontrols:IconBox
|
<cpcontrols:IconBox
|
||||||
x:Name="GridIconBorder"
|
x:Name="GridIconBorder"
|
||||||
|
Grid.Row="0"
|
||||||
Width="36"
|
Width="36"
|
||||||
Height="36"
|
Height="36"
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
CharacterSpacing="12"
|
CharacterSpacing="12"
|
||||||
@@ -169,21 +293,20 @@
|
|||||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||||
|
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="TitleTextBlock"
|
x:Name="TitleTextBlock"
|
||||||
MaxHeight="40"
|
Grid.Row="1"
|
||||||
Margin="0,8,0,4"
|
Height="32"
|
||||||
|
Margin="0,8,0,0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
|
||||||
CharacterSpacing="12"
|
CharacterSpacing="12"
|
||||||
FontSize="12"
|
FontSize="12"
|
||||||
Text="{x:Bind Title}"
|
Text="{x:Bind Title, Mode=OneWay}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextTrimming="WordEllipsis"
|
TextTrimming="WordEllipsis"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Visibility="{Binding ElementName=PageRoot, Path=DataContext.GridProperties.ShowTitle, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
Visibility="{x:Bind LayoutShowsTitle, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</Grid>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
|
|
||||||
<DataTemplate x:Key="GalleryGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
<DataTemplate x:Key="GalleryGridItemViewModelTemplate" x:DataType="coreViewModels:ListItemViewModel">
|
||||||
@@ -193,11 +316,11 @@
|
|||||||
Padding="0"
|
Padding="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
AutomationProperties.Name="{x:Bind Title}"
|
AutomationProperties.Name="{x:Bind Title, Mode=OneWay}"
|
||||||
BorderThickness="0"
|
BorderThickness="0"
|
||||||
CornerRadius="4"
|
CornerRadius="{StaticResource GalleryGridViewItemRadius}"
|
||||||
Orientation="Vertical"
|
Orientation="Vertical"
|
||||||
ToolTipService.ToolTip="{x:Bind Title}">
|
ToolTipService.ToolTip="{x:Bind Title, Mode=OneWay}">
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
Width="160"
|
Width="160"
|
||||||
@@ -205,12 +328,8 @@
|
|||||||
Margin="0"
|
Margin="0"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
CornerRadius="4">
|
CornerRadius="{StaticResource GalleryGridViewItemRadius}">
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Viewbox
|
<Viewbox
|
||||||
Grid.Row="1"
|
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Stretch="UniformToFill"
|
Stretch="UniformToFill"
|
||||||
StretchDirection="Both">
|
StretchDirection="Both">
|
||||||
@@ -222,35 +341,39 @@
|
|||||||
</Viewbox>
|
</Viewbox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Padding="4" Orientation="Vertical">
|
<StackPanel
|
||||||
|
Padding="4"
|
||||||
|
Orientation="Vertical"
|
||||||
|
Spacing="4"
|
||||||
|
Visibility="{x:Bind help:BindTransformers.VisibleWhenAny(ShowTitle, ShowSubtitle)}">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="TitleTextBlock"
|
x:Name="TitleTextBlock"
|
||||||
MaxWidth="152"
|
MaxWidth="152"
|
||||||
MaxHeight="40"
|
MaxHeight="40"
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
CharacterSpacing="12"
|
CharacterSpacing="12"
|
||||||
FontSize="14"
|
FontSize="14"
|
||||||
Foreground="{ThemeResource TextFillColorPrimary}"
|
Foreground="{ThemeResource TextFillColorPrimary}"
|
||||||
Text="{x:Bind Title}"
|
Text="{x:Bind Title, Mode=OneWay}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextTrimming="WordEllipsis"
|
TextTrimming="WordEllipsis"
|
||||||
TextWrapping="NoWrap" />
|
TextWrapping="NoWrap"
|
||||||
|
Visibility="{x:Bind ShowTitle, Mode=OneWay}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
x:Name="SubTitleTextBlock"
|
x:Name="SubTitleTextBlock"
|
||||||
MaxWidth="152"
|
MaxWidth="152"
|
||||||
MaxHeight="40"
|
MaxHeight="40"
|
||||||
Margin="0,4,0,0"
|
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
CharacterSpacing="11"
|
CharacterSpacing="11"
|
||||||
FontSize="11"
|
FontSize="11"
|
||||||
Foreground="{ThemeResource TextFillColorTertiary}"
|
Foreground="{ThemeResource TextFillColorTertiary}"
|
||||||
Text="{x:Bind Subtitle}"
|
Text="{x:Bind Subtitle, Mode=OneWay}"
|
||||||
TextAlignment="Center"
|
TextAlignment="Center"
|
||||||
TextTrimming="WordEllipsis"
|
TextTrimming="WordEllipsis"
|
||||||
TextWrapping="NoWrap" />
|
TextWrapping="NoWrap"
|
||||||
|
Visibility="{x:Bind ShowSubtitle, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
@@ -295,6 +418,7 @@
|
|||||||
IsDoubleTapEnabled="True"
|
IsDoubleTapEnabled="True"
|
||||||
IsItemClickEnabled="True"
|
IsItemClickEnabled="True"
|
||||||
ItemClick="Items_ItemClick"
|
ItemClick="Items_ItemClick"
|
||||||
|
ItemContainerStyleSelector="{StaticResource GridItemContainerStyleSelector}"
|
||||||
ItemTemplateSelector="{StaticResource GridItemTemplateSelector}"
|
ItemTemplateSelector="{StaticResource GridItemTemplateSelector}"
|
||||||
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
ItemsSource="{x:Bind ViewModel.FilteredItems, Mode=OneWay}"
|
||||||
RightTapped="Items_RightTapped"
|
RightTapped="Items_RightTapped"
|
||||||
@@ -302,6 +426,7 @@
|
|||||||
<GridView.ItemContainerTransitions>
|
<GridView.ItemContainerTransitions>
|
||||||
<TransitionCollection />
|
<TransitionCollection />
|
||||||
</GridView.ItemContainerTransitions>
|
</GridView.ItemContainerTransitions>
|
||||||
|
<GridView.ItemContainerStyle />
|
||||||
</GridView>
|
</GridView>
|
||||||
</controls:Case>
|
</controls:Case>
|
||||||
</controls:SwitchPresenter>
|
</controls:SwitchPresenter>
|
||||||
|
|||||||
@@ -15,4 +15,7 @@ internal static class BindTransformers
|
|||||||
|
|
||||||
public static Visibility EmptyOrWhitespaceToCollapsed(string? input)
|
public static Visibility EmptyOrWhitespaceToCollapsed(string? input)
|
||||||
=> string.IsNullOrWhiteSpace(input) ? Visibility.Collapsed : Visibility.Visible;
|
=> string.IsNullOrWhiteSpace(input) ? Visibility.Collapsed : Visibility.Visible;
|
||||||
|
|
||||||
|
public static Visibility VisibleWhenAny(bool value1, bool value2)
|
||||||
|
=> (value1 || value2) ? Visibility.Visible : Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,13 +9,6 @@ namespace SamplePagesExtension;
|
|||||||
|
|
||||||
internal sealed partial class SampleGalleryListPage : ListPage
|
internal sealed partial class SampleGalleryListPage : ListPage
|
||||||
{
|
{
|
||||||
public SampleGalleryListPage()
|
|
||||||
{
|
|
||||||
Icon = new IconInfo("\uE7C5");
|
|
||||||
Name = "Sample Gallery List Page";
|
|
||||||
GridProperties = new GalleryGridLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override IListItem[] GetItems()
|
public override IListItem[] GetItems()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// 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.CommandPalette.Extensions;
|
||||||
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
|
||||||
|
namespace SamplePagesExtension;
|
||||||
|
|
||||||
|
internal sealed partial class SampleGridsListPage : ListPage
|
||||||
|
{
|
||||||
|
private readonly IListItem[] _items =
|
||||||
|
[
|
||||||
|
new ListItem(new SampleGalleryListPage { GridProperties = new GalleryGridLayout { ShowTitle = true, ShowSubtitle = true } })
|
||||||
|
{
|
||||||
|
Title = "Gallery list page (title and subtitle)",
|
||||||
|
Subtitle = "A sample gallery list page with images",
|
||||||
|
Icon = IconHelpers.FromRelativePath("Assets/Images/Swirls.png"),
|
||||||
|
},
|
||||||
|
new ListItem(new SampleGalleryListPage { GridProperties = new GalleryGridLayout { ShowTitle = true, ShowSubtitle = false } })
|
||||||
|
{
|
||||||
|
Title = "Gallery list page (title, no subtitle)",
|
||||||
|
Subtitle = "A sample gallery list page with images",
|
||||||
|
Icon = IconHelpers.FromRelativePath("Assets/Images/Swirls.png"),
|
||||||
|
},
|
||||||
|
new ListItem(new SampleGalleryListPage { GridProperties = new GalleryGridLayout { ShowTitle = false, ShowSubtitle = false } })
|
||||||
|
{
|
||||||
|
Title = "Gallery list page (no title, no subtitle)",
|
||||||
|
Subtitle = "A sample gallery list page with images",
|
||||||
|
Icon = IconHelpers.FromRelativePath("Assets/Images/Swirls.png"),
|
||||||
|
},
|
||||||
|
new ListItem(new SampleGalleryListPage { GridProperties = new SmallGridLayout() })
|
||||||
|
{
|
||||||
|
Title = "Small grid list page",
|
||||||
|
Subtitle = "A sample grid list page with text items",
|
||||||
|
Icon = IconHelpers.FromRelativePath("Assets/Images/Win-Digital.png"),
|
||||||
|
},
|
||||||
|
new ListItem(new SampleGalleryListPage { GridProperties = new MediumGridLayout { ShowTitle = true } })
|
||||||
|
{
|
||||||
|
Title = "Medium grid (with title)",
|
||||||
|
Subtitle = "A sample grid list page with text items",
|
||||||
|
Icon = IconHelpers.FromRelativePath("Assets/Images/Win-Digital.png"),
|
||||||
|
},
|
||||||
|
new ListItem(new SampleGalleryListPage { GridProperties = new MediumGridLayout { ShowTitle = false } })
|
||||||
|
{
|
||||||
|
Title = "Medium grid (hidden title)",
|
||||||
|
Subtitle = "A sample grid list page with text items",
|
||||||
|
Icon = IconHelpers.FromRelativePath("Assets/Images/Win-Digital.png"),
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
public SampleGridsListPage()
|
||||||
|
{
|
||||||
|
Icon = new IconInfo("\uE7C5");
|
||||||
|
Name = "Grid and gallery lists";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IListItem[] GetItems() => _items;
|
||||||
|
}
|
||||||
@@ -34,9 +34,9 @@ public partial class SamplesListPage : ListPage
|
|||||||
Title = "Dynamic List Page Command",
|
Title = "Dynamic List Page Command",
|
||||||
Subtitle = "Changes the list of items in response to the typed query",
|
Subtitle = "Changes the list of items in response to the typed query",
|
||||||
},
|
},
|
||||||
new ListItem(new SampleGalleryListPage())
|
new ListItem(new SampleGridsListPage())
|
||||||
{
|
{
|
||||||
Title = "Gallery List Page Command",
|
Title = "Grid views and galleries",
|
||||||
Subtitle = "Displays items as a gallery",
|
Subtitle = "Displays items as a gallery",
|
||||||
},
|
},
|
||||||
new ListItem(new OnLoadPage())
|
new ListItem(new OnLoadPage())
|
||||||
|
|||||||
Reference in New Issue
Block a user