mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-11 23:06:45 +01:00
Fix #213 by implementing a light-weight IconBox control
Replaces PR #218 IconBox is a custom control that's a ContentControl, it's generic (toolkitable) and should be able to be styled and templated. It knows how to take an IconSource and create the underlying IconElement as its content. It can also take any general value as a `SourceKey` and via an implementation of the SourceRequested event, translate a bound general object into the `IconSource` required. This is how caching can be provided by an application as well, for instance (like we'll do here). This uses the deferred events pattern to await the call to the `SourceRequested` event which may need to load data asynchronously We create a static x:Bind helper `IconCacheProvider` to encapsulate our shared logic for our eventual Icon cache. Renamed IconCacheService.xaml.cs -> IconCacheService.cs Removed old broken behavior (believe ultimate issue was due to instability in loaded/unloaded events, i.e. issue https://github.com/microsoft/microsoft-ui-xaml/issues/1900) XAML Styler also did its thing...
This commit is contained in:
@@ -3,14 +3,14 @@
|
||||
x:Class="Microsoft.CmdPal.UI.Controls.ActionBar"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:cmdpalUI="using:Microsoft.CmdPal.UI"
|
||||
xmlns:local="using:Microsoft.CmdPal.UI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
xmlns:viewmodels="using:Microsoft.CmdPal.UI.ViewModels"
|
||||
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
Background="Transparent"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -30,16 +30,13 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border x:Name="IconBorder"
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="0,0,0,0">
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<cmdpalUI:LoadIconBehavior Source="{x:Bind Icon, Mode=OneWay}"/>
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
<cpcontrols:IconBox
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="0,0,0,0"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
<TextBlock Grid.Column="1" Text="{x:Bind Title}" />
|
||||
</Grid>
|
||||
@@ -55,18 +52,16 @@
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<Border x:Name="IconBorder"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="12,0,0,0"
|
||||
CornerRadius="{StaticResource ControlCornerRadius}">
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<cmdpalUI:LoadIconBehavior Source="{x:Bind ViewModel.CurrentPage.Icon, Mode=OneWay}"/>
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
|
||||
<cpcontrols:IconBox
|
||||
x:Name="IconBorder"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="12,0,0,0"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
CornerRadius="{StaticResource ControlCornerRadius}"
|
||||
SourceKey="{x:Bind ViewModel.CurrentPage.Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
@@ -81,21 +76,19 @@
|
||||
Spacing="6">
|
||||
<Button
|
||||
x:Name="PrimaryButton"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
Height="40"
|
||||
Padding="8,4,8,4"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.PrimaryAction.Name, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}">
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<!-- <FontIcon Glyph="" /> -->
|
||||
<Border Width="16"
|
||||
Height="16"
|
||||
Margin="4,4,4,4">
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<cmdpalUI:LoadIconBehavior Source="{x:Bind ViewModel.PrimaryAction.Icon, Mode=OneWay}"/>
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
<cpcontrols:IconBox
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="4,4,4,4"
|
||||
SourceKey="{x:Bind ViewModel.PrimaryAction.Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
<StackPanel Orientation="Vertical" Spacing="2">
|
||||
<TextBlock
|
||||
@@ -113,21 +106,19 @@
|
||||
</Button>
|
||||
<Button
|
||||
x:Name="SecondaryButton"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
Height="40"
|
||||
Padding="8,4,8,4"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.HasSecondaryCommand, Mode=OneWay}">
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<!-- <FontIcon Glyph="" /> -->
|
||||
|
||||
<Border Width="16"
|
||||
Height="16"
|
||||
Margin="4,4,4,4">
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<cmdpalUI:LoadIconBehavior Source="{x:Bind ViewModel.SecondaryAction.Icon, Mode=OneWay}" />
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
|
||||
<cpcontrols:IconBox
|
||||
Width="16"
|
||||
Height="16"
|
||||
Margin="4,4,4,4"
|
||||
SourceKey="{x:Bind ViewModel.SecondaryAction.Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
<StackPanel Orientation="Vertical" Spacing="1">
|
||||
<TextBlock
|
||||
|
||||
110
src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/IconBox.cs
Normal file
110
src/modules/cmdpal/Microsoft.CmdPal.UI/Controls/IconBox.cs
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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 CommunityToolkit.Common.Deferred;
|
||||
using CommunityToolkit.WinUI;
|
||||
using CommunityToolkit.WinUI.Deferred;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// A helper control which takes an <see cref="IconSource"/> and creates the corresponding <see cref="IconElement"/>.
|
||||
/// </summary>
|
||||
public partial class IconBox : ContentControl
|
||||
{
|
||||
private readonly DispatcherQueue _queue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="IconSource"/> to display within the <see cref="IconBox"/>. Overwritten, if <see cref="SourceKey"/> is used instead.
|
||||
/// </summary>
|
||||
public IconSource? Source
|
||||
{
|
||||
get => (IconSource?)GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register(nameof(Source), typeof(IconSource), typeof(IconBox), new PropertyMetadata(null, OnSourcePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value to use as the <see cref="SourceKey"/> to retrieve an <see cref="IconSource"/> to set as the <see cref="Source"/>.
|
||||
/// </summary>
|
||||
public object? SourceKey
|
||||
{
|
||||
get => (object?)GetValue(SourceKeyProperty);
|
||||
set => SetValue(SourceKeyProperty, value);
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for SourceKey. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty SourceKeyProperty =
|
||||
DependencyProperty.Register(nameof(SourceKey), typeof(object), typeof(IconBox), new PropertyMetadata(null, OnSourceKeyPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="SourceRequested"/> event handler to provide the value of the <see cref="IconSource"/> for the <see cref="Source"/> property from the provided <see cref="SourceKey"/>.
|
||||
/// </summary>
|
||||
public event TypedEventHandler<IconBox, SourceRequestedEventArgs>? SourceRequested;
|
||||
|
||||
private static void OnSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is IconBox @this)
|
||||
{
|
||||
switch (e.NewValue)
|
||||
{
|
||||
case null:
|
||||
@this.Content = null;
|
||||
break;
|
||||
case FontIconSource fontIco:
|
||||
fontIco.FontSize = @this.Width;
|
||||
|
||||
// For inexplicable reasons, FontIconSource.CreateIconElement
|
||||
// doesn't work, so do it ourselves
|
||||
// TODO: File platform bug?
|
||||
IconSourceElement elem = new()
|
||||
{
|
||||
IconSource = fontIco,
|
||||
};
|
||||
@this.Content = elem;
|
||||
break;
|
||||
case IconSource source:
|
||||
@this.Content = source.CreateIconElement();
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"New value of {e.NewValue} is not of type IconSource.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnSourceKeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is IconBox @this)
|
||||
{
|
||||
if (e.NewValue == null)
|
||||
{
|
||||
@this.Source = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = @this._queue.EnqueueAsync(async () =>
|
||||
{
|
||||
var eventArgs = new SourceRequestedEventArgs(e.NewValue);
|
||||
|
||||
if (@this.SourceRequested != null)
|
||||
{
|
||||
await @this.SourceRequested.InvokeAsync(@this, eventArgs);
|
||||
|
||||
if (eventArgs.Value != null)
|
||||
{
|
||||
@this.Source = eventArgs.Value;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// 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 CommunityToolkit.Common.Deferred;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Controls;
|
||||
|
||||
/// <summary>
|
||||
/// See <see cref="IconBox.SourceRequested"/> event.
|
||||
/// </summary>
|
||||
public class SourceRequestedEventArgs(object? key) : DeferredEventArgs
|
||||
{
|
||||
public object? Key { get; private set; } = key;
|
||||
|
||||
public IconSource? Value { get; set; }
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
x:Class="Microsoft.CmdPal.UI.ListPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:Interactions="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
|
||||
xmlns:local="using:Microsoft.CmdPal.UI"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewmodels="using:Microsoft.CmdPal.UI.ViewModels"
|
||||
@@ -33,25 +33,23 @@
|
||||
Spacing="8" />
|
||||
|
||||
<DataTemplate x:Key="TagTemplate" x:DataType="viewmodels:TagViewModel">
|
||||
<!-- TODO: Actually colorize the tags again -->
|
||||
<!-- TODO: Actually colorize the tags again -->
|
||||
<StackPanel
|
||||
Padding="4,2,4,2"
|
||||
VerticalAlignment="Center"
|
||||
BorderBrush="{ThemeResource TextBoxBorderThemeBrush}"
|
||||
BorderThickness="1"
|
||||
Orientation="Horizontal"
|
||||
CornerRadius="4">
|
||||
<Border x:Name="IconBorder"
|
||||
Width="12"
|
||||
Height="12"
|
||||
Margin="0,0,4,0"
|
||||
Visibility="{x:Bind HasIcon, Mode=OneWay}">
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<local:LoadIconBehavior Source="{x:Bind Icon, Mode=OneWay}"/>
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
|
||||
CornerRadius="4"
|
||||
Orientation="Horizontal">
|
||||
<cpcontrols:IconBox
|
||||
x:Name="IconBorder"
|
||||
Width="12"
|
||||
Height="12"
|
||||
Margin="0,0,4,0"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}"
|
||||
Visibility="{x:Bind HasIcon, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
VerticalAlignment="Center"
|
||||
FontSize="12"
|
||||
@@ -72,16 +70,14 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<Border x:Name="IconBorder"
|
||||
Grid.Column="0"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="4,0,4,0">
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<local:LoadIconBehavior Source="{x:Bind Icon, Mode=OneWay}"/>
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
<cpcontrols:IconBox
|
||||
x:Name="IconBorder"
|
||||
Grid.Column="0"
|
||||
Width="20"
|
||||
Height="20"
|
||||
Margin="4,0,4,0"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}" />
|
||||
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
@@ -105,12 +101,13 @@
|
||||
TextWrapping="NoWrap"
|
||||
Visibility="{x:Bind Subtitle, Mode=OneWay, Converter={StaticResource StringVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
|
||||
<ItemsRepeater ItemTemplate="{StaticResource TagTemplate}"
|
||||
ItemsSource="{x:Bind Tags}"
|
||||
Grid.Column="2"
|
||||
Visibility="{x:Bind HasTags}"
|
||||
Layout="{StaticResource HorizontalStackLayout}" />
|
||||
|
||||
<ItemsRepeater
|
||||
Grid.Column="2"
|
||||
ItemTemplate="{StaticResource TagTemplate}"
|
||||
ItemsSource="{x:Bind Tags}"
|
||||
Layout="{StaticResource HorizontalStackLayout}"
|
||||
Visibility="{x:Bind HasTags}" />
|
||||
</Grid>
|
||||
</ListViewItem>
|
||||
</DataTemplate>
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// 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.Extensions;
|
||||
using Microsoft.CmdPal.UI.Controls;
|
||||
using Microsoft.CmdPal.UI.ExtViews;
|
||||
|
||||
namespace Microsoft.CmdPal.UI.Helpers;
|
||||
|
||||
/// <summary>
|
||||
/// Common async event handler provides the cache lookup function for the <see cref="IconBox.SourceRequested"/> deferred event.
|
||||
/// </summary>
|
||||
public static partial class IconCacheProvider
|
||||
{
|
||||
private static readonly IconCacheService IconService = new(Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
|
||||
|
||||
#pragma warning disable IDE0060 // Remove unused parameter
|
||||
public static async void SourceRequested(IconBox sender, SourceRequestedEventArgs args)
|
||||
#pragma warning restore IDE0060 // Remove unused parameter
|
||||
{
|
||||
if (args.Key == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.Key is IconDataType iconData)
|
||||
{
|
||||
var deferral = args.GetDeferral();
|
||||
|
||||
args.Value = await IconService.GetIconSource(iconData);
|
||||
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
// 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.Extensions;
|
||||
using Microsoft.CmdPal.UI.ExtViews;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Xaml.Interactivity;
|
||||
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
public partial class LoadIconBehavior : DependencyObject, IBehavior
|
||||
{
|
||||
private static readonly IconCacheService IconService = new(Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
|
||||
|
||||
public IconDataType? Source
|
||||
{
|
||||
get => (IconDataType?)GetValue(SourceProperty);
|
||||
set => SetValue(SourceProperty, value);
|
||||
}
|
||||
|
||||
// Using a DependencyProperty as the backing store for Source. This enables animation, styling, binding, etc...
|
||||
public static readonly DependencyProperty SourceProperty =
|
||||
DependencyProperty.Register(nameof(Source), typeof(IconDataType), typeof(LoadIconBehavior), new PropertyMetadata(null, OnSourcePropertyChanged));
|
||||
|
||||
public DependencyObject? AssociatedObject { get; private set; }
|
||||
|
||||
public void Attach(DependencyObject associatedObject) => AssociatedObject = associatedObject;
|
||||
|
||||
public void Detach() => AssociatedObject = null;
|
||||
|
||||
private static async void OnSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is LoadIconBehavior @this
|
||||
&& @this.AssociatedObject is Border border)
|
||||
{
|
||||
var icoSource = await IconService.GetIconSource(@this.Source ?? new(string.Empty));
|
||||
|
||||
/* This causes a catastrophic failure...
|
||||
if (border.Child != null)
|
||||
{
|
||||
VisualTreeHelper.DisconnectChildrenRecursive(border.Child);
|
||||
border.Child = null;
|
||||
}*/
|
||||
|
||||
if (icoSource is FontIconSource fontIco)
|
||||
{
|
||||
fontIco.FontSize = border.Width;
|
||||
|
||||
// For inexplicable reasons, FontIconSource.CreateIconElement
|
||||
// doesn't work, so do it ourselves
|
||||
IconSourceElement elem = new()
|
||||
{
|
||||
IconSource = fontIco,
|
||||
};
|
||||
border.Child = elem;
|
||||
}
|
||||
else
|
||||
{
|
||||
var icoElement = icoSource?.CreateIconElement();
|
||||
border.Child = icoElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,12 @@
|
||||
x:Class="Microsoft.CmdPal.UI.ShellPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.CmdPal.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Microsoft.CmdPal.UI"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:labs="using:CommunityToolkit.Labs.WinUI.MarkdownTextBlock"
|
||||
xmlns:converters="using:CommunityToolkit.WinUI.Converters"
|
||||
xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
|
||||
xmlns:cpcontrols="using:Microsoft.CmdPal.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:help="using:Microsoft.CmdPal.UI.Helpers"
|
||||
xmlns:labs="using:CommunityToolkit.Labs.WinUI.MarkdownTextBlock"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Background="Transparent"
|
||||
mc:Ignorable="d">
|
||||
|
||||
@@ -32,7 +31,7 @@
|
||||
|
||||
<VisualState x:Name="DetailsVisible">
|
||||
<VisualState.StateTriggers>
|
||||
<StateTrigger IsActive="{x:Bind ViewModel.IsDetailsVisible, Mode=OneWay}"/>
|
||||
<StateTrigger IsActive="{x:Bind ViewModel.IsDetailsVisible, Mode=OneWay}" />
|
||||
</VisualState.StateTriggers>
|
||||
<VisualState.Setters>
|
||||
<Setter Target="DetailsContent.Visibility" Value="Visible" />
|
||||
@@ -49,13 +48,14 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<controls:SearchBar
|
||||
<cpcontrols:SearchBar
|
||||
x:Name="SearchBox"
|
||||
Grid.Row="0"
|
||||
VerticalAlignment="Top"
|
||||
CurrentPageViewModel="{x:Bind ViewModel.CurrentPage, Mode=OneWay}" />
|
||||
|
||||
<Grid x:Name="ContentGrid"
|
||||
<Grid
|
||||
x:Name="ContentGrid"
|
||||
Grid.Row="1"
|
||||
Background="{ThemeResource LayerOnAcrylicFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
@@ -66,18 +66,19 @@
|
||||
<ColumnDefinition x:Name="DetailsColumn" Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Frame Name="RootFrame"
|
||||
Grid.Column="0"
|
||||
IsNavigationStackEnabled="True" />
|
||||
<Frame
|
||||
Name="RootFrame"
|
||||
Grid.Column="0"
|
||||
IsNavigationStackEnabled="True" />
|
||||
|
||||
<Grid
|
||||
<Grid
|
||||
x:Name="DetailsContent"
|
||||
Grid.Column="1"
|
||||
Visibility="Collapsed"
|
||||
Grid.Column="1"
|
||||
Padding="8"
|
||||
Background="{ThemeResource LayerFillColorDefaultBrush}"
|
||||
BorderBrush="{ThemeResource CardStrokeColorDefaultBrush}"
|
||||
BorderThickness="1,0,0,0">
|
||||
BorderThickness="1,0,0,0"
|
||||
Visibility="Collapsed">
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -85,40 +86,37 @@
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border x:Name="HeroImageBorder"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
Width="64"
|
||||
Height="64"
|
||||
Visibility="{x:Bind ViewModel.Details.HasHeroImage, Mode=OneWay}" >
|
||||
<!-- LoadIconBehavior will magically fill this border up with an icon -->
|
||||
<Interactivity:Interaction.Behaviors>
|
||||
<local:LoadIconBehavior Source="{x:Bind ViewModel.Details.HeroImage, Mode=OneWay}" />
|
||||
</Interactivity:Interaction.Behaviors>
|
||||
</Border>
|
||||
<cpcontrols:IconBox
|
||||
x:Name="HeroImageBorder"
|
||||
Width="64"
|
||||
Height="64"
|
||||
x:Load="{x:Bind IsLoaded, Mode=OneWay}"
|
||||
SourceKey="{x:Bind ViewModel.Details.HeroImage, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind help:IconCacheProvider.SourceRequested}"
|
||||
Visibility="{x:Bind ViewModel.Details.HasHeroImage, Mode=OneWay}" />
|
||||
|
||||
<TextBlock
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
HorizontalAlignment="Center"
|
||||
FontSize="20"
|
||||
TextWrapping="WrapWholeWords"
|
||||
Style="{StaticResource SubtitleTextBlockStyle}"
|
||||
Text="{x:Bind ViewModel.Details.Title, Mode=OneWay}"
|
||||
Visibility="{x:Bind ViewModel.Details.Title, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}"/>
|
||||
Text="{x:Bind ViewModel.Details.Title, Mode=OneWay}"
|
||||
TextWrapping="WrapWholeWords"
|
||||
Visibility="{x:Bind ViewModel.Details.Title, Converter={StaticResource StringNotEmptyToVisibilityConverter}, Mode=OneWay}" />
|
||||
|
||||
<ScrollViewer Grid.Row="2" HorizontalAlignment="Stretch">
|
||||
<labs:MarkdownTextBlock
|
||||
<labs:MarkdownTextBlock
|
||||
x:Name="DetailsMarkdown"
|
||||
Text="{x:Bind ViewModel.Details.Body, Mode=OneWay}"
|
||||
Background="Transparent" >
|
||||
|
||||
</labs:MarkdownTextBlock>
|
||||
|
||||
Background="Transparent"
|
||||
Text="{x:Bind ViewModel.Details.Body, Mode=OneWay}" />
|
||||
|
||||
</ScrollViewer>
|
||||
</Grid> <!--/DetailsContent-->
|
||||
|
||||
</Grid>
|
||||
<!-- /DetailsContent -->
|
||||
|
||||
</Grid>
|
||||
|
||||
<controls:ActionBar
|
||||
<cpcontrols:ActionBar
|
||||
Grid.Row="2"
|
||||
VerticalAlignment="Top"
|
||||
CurrentPageViewModel="{x:Bind ViewModel.CurrentPage, Mode=OneWay}" />
|
||||
|
||||
Reference in New Issue
Block a user