Merge branch 'main' into niels9001/titlebar-experiment

This commit is contained in:
Niels Laute 2023-07-24 10:25:58 +02:00 коммит произвёл GitHub
Родитель 4dfd4ae680 a5771031e6
Коммит 4337e645df
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
100 изменённых файлов: 93 добавлений и 6683 удалений

Просмотреть файл

@ -2,7 +2,7 @@
<PropertyGroup>
<ToolkitComponentName>MarqueeText</ToolkitComponentName>
<Description>This package contains MarqueeText.</Description>
<Version>0.0.2</Version>
<Version>0.0.3</Version>
<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.Labs.WinUI.MarqueeTextRns</RootNamespace>

Просмотреть файл

@ -22,6 +22,7 @@ public enum MarqueeBehavior
/// </remarks>
Looping,
// Waiting on AutoReverse implementation for Uno storyboards
#if !HAS_UNO
/// <summary>
/// The text bounces back and forth across the screen.

Просмотреть файл

@ -41,14 +41,16 @@ public partial class MarqueeText
private void Container_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (_marqueeContainer is not null)
if (_marqueeContainer is null)
{
// Clip the marquee within its bounds
_marqueeContainer.Clip = new RectangleGeometry
{
Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height)
};
return;
}
// Clip the marquee within its bounds
_marqueeContainer.Clip = new RectangleGeometry
{
Rect = new Rect(0, 0, e.NewSize.Width, e.NewSize.Height)
};
// The marquee should run when the size changes in case the text gets cutoff
StartMarquee();

Просмотреть файл

@ -26,8 +26,10 @@ public partial class MarqueeText
private static readonly DependencyProperty DirectionProperty =
DependencyProperty.Register(nameof(Direction), typeof(MarqueeDirection), typeof(MarqueeText), new PropertyMetadata(MarqueeDirection.Left, DirectionPropertyChanged));
#if !HAS_UNO
private static readonly DependencyProperty TextDecorationsProperty =
DependencyProperty.Register(nameof(TextDecorations), typeof(TextDecorations), typeof(MarqueeText), new PropertyMetadata(TextDecorations.None));
#endif
/// <summary>
/// Gets or sets the text being displayed in Marquee.
@ -91,6 +93,8 @@ public partial class MarqueeText
private bool IsDirectionInverse => Direction is MarqueeDirection.Up or MarqueeDirection.Right;
// Waiting on https://github.com/unoplatform/uno/issues/12929
#if !HAS_UNO
/// <summary>
/// Gets or sets a value that indicates what decorations are applied to the text.
/// </summary>
@ -99,6 +103,7 @@ public partial class MarqueeText
get => (TextDecorations)GetValue(TextDecorationsProperty);
set => SetValue(TextDecorationsProperty, value);
}
#endif
private static void BehaviorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{

Просмотреть файл

@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI.MarqueeTextRns;
/// <summary>
@ -68,6 +67,7 @@ public partial class MarqueeText : Control
{
base.OnApplyTemplate();
// Explicit casting throws early when parts are missing from the template
_marqueeContainer = (Panel)GetTemplateChild(MarqueeContainerPartName);
_segment1 = (FrameworkElement)GetTemplateChild(Segment1PartName);
_segment2 = (FrameworkElement)GetTemplateChild(Segment2PartName);
@ -112,6 +112,7 @@ public partial class MarqueeText : Control
/// <summary>
/// Begins the Marquee animation if not running.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when template parts are not supplied.</exception>
public void StartMarquee()
{
bool initial = _isActive;
@ -128,18 +129,20 @@ public partial class MarqueeText : Control
/// <summary>
/// Stops the Marquee animation.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown when template parts are not supplied.</exception>
public void StopMarquee()
{
StopMarquee(_isActive);
}
private void StopMarquee(bool stopping)
private void StopMarquee(bool initialState)
{
// Set _isActive and update the animation to match
_isActive = false;
bool playing = UpdateAnimation(false);
// Invoke MarqueeStopped if Marquee is not playing and was before
if (!playing && stopping)
if (!playing && initialState)
{
MarqueeStopped?.Invoke(this, EventArgs.Empty);
}
@ -149,9 +152,13 @@ public partial class MarqueeText : Control
/// Updates the animation to match the current control state.
/// </summary>
/// <param name="resume">True if animation should resume from its current position, false if it should restart.</param>
/// <returns>True if the Animation is now playing</returns>
/// <exception cref="InvalidOperationException">Thrown when template parts are not supplied.</exception>
/// <returns>True if the Animation is now playing.</returns>
private bool UpdateAnimation(bool resume = true)
{
// Crucial template parts are missing!
// This can happen during initialization of certain properties.
// Gracefully return when this happens. Proper checks for these template parts happen in OnApplyTemplate.
if (_marqueeContainer is null ||
_marqueeTransform is null ||
_segment1 is null ||
@ -160,6 +167,8 @@ public partial class MarqueeText : Control
return false;
}
// The marquee is stopped.
// Update the animation to the stopped position.
if (!_isActive)
{
VisualStateManager.GoToState(this, MarqueeStoppedState, false);
@ -167,48 +176,59 @@ public partial class MarqueeText : Control
return false;
}
// Get the size (width horizontal, height if vertical) of the
// contain and segment.
// Also track the property to adjust based on the orientation.
// Get the size of the container and segment, based on the orientation.
// Also track the property to adjust, also based on the orientation.
double containerSize;
double segmentSize;
double value;
string property;
string targetProperty;
if (IsDirectionHorizontal)
{
// The direction is horizontal, so the sizes, value, and properties
// are defined by width and X coordinates.
containerSize = _marqueeContainer.ActualWidth;
segmentSize = _segment1.ActualWidth;
value = _marqueeTransform.X;
property = "(TranslateTransform.X)";
targetProperty = "(TranslateTransform.X)";
}
else
{
// The direction is vertical, so the sizes, value, and properties
// are defined by height and Y coordinates.
containerSize = _marqueeContainer.ActualHeight;
segmentSize = _segment1.ActualHeight;
value = _marqueeTransform.Y;
property = "(TranslateTransform.Y)";
targetProperty = "(TranslateTransform.Y)";
}
if (IsLooping && segmentSize < containerSize)
{
// If the text segment is smaller than the area provided,
// it does not need to run in looping mode.
// If the marquee is in looping mode and the segment is smaller
// than the container, then the animation does not not need to play.
// NOTE: Use resume as initial because _isActive is updated before
// calling update animation. If _isActive were passed, it would allow for
// MarqueeStopped to be invoked when the marquee was already stopped.
StopMarquee(resume);
_segment2.Visibility = Visibility.Collapsed;
return false;
}
// The start position is offset 100% if ticker
// The start position is offset 100% if in ticker mode
// Otherwise it's 0
double start = IsTicker ? containerSize : 0;
// The end is when the end of the text reaches the border if bounding
// The end is when the end of the text reaches the border if in bouncing mode
// Otherwise it is when the first set of text is 100% out of view
double end = IsBouncing ? containerSize - segmentSize : -segmentSize;
// The distance is used for calculating the duration and the progress if resuming
// The distance is used for calculating the duration and the previous
// animation progress if resuming
double distance = Math.Abs(start - end);
// If the distance is zero, don't play an animation
if (distance is 0)
{
return false;
@ -220,17 +240,42 @@ public partial class MarqueeText : Control
(start, end) = (end, start);
}
// The second segment of text should be hidden if the marquee is not in looping mode.
// The second segment of text should be hidden if the marquee is not in looping mode
_segment2.Visibility = IsLooping ? Visibility.Visible : Visibility.Collapsed;
// Calculate the animation duration by dividing the distance by the speed
TimeSpan duration = TimeSpan.FromSeconds(distance / Speed);
// Unbind events from the old storyboard
if (_marqueeStoryboard is not null)
{
_marqueeStoryboard.Completed -= StoryBoard_Completed;
}
_marqueeStoryboard = new Storyboard
// Create new storyboard and animation
_marqueeStoryboard = CreateMarqueeStoryboardAnimation(start, end, duration, targetProperty);
// Bind the storyboard completed event
_marqueeStoryboard.Completed += StoryBoard_Completed;
// Set the visual state to active and begin the animation
VisualStateManager.GoToState(this, MarqueeActiveState, true);
_marqueeStoryboard.Begin();
// If resuming, seek the animation so the text resumes from its current position.
if (resume)
{
double progress = Math.Abs(start - value) / distance;
_marqueeStoryboard.Seek(TimeSpan.FromTicks((long)(duration.Ticks * progress)));
}
return true;
}
private Storyboard CreateMarqueeStoryboardAnimation(double start, double end, TimeSpan duration, string targetProperty)
{
// Initialize the new storyboard
var marqueeStoryboard = new Storyboard
{
Duration = duration,
RepeatBehavior = RepeatBehavior,
@ -238,9 +283,8 @@ public partial class MarqueeText : Control
AutoReverse = IsBouncing,
#endif
};
_marqueeStoryboard.Completed += StoryBoard_Completed;
// Create a new double animation, moving from [start] to [end] positions in [duration] time.
var animation = new DoubleAnimationUsingKeyFrames
{
Duration = duration,
@ -249,6 +293,8 @@ public partial class MarqueeText : Control
AutoReverse = IsBouncing,
#endif
};
// Create the key frames
var frame1 = new DiscreteDoubleKeyFrame
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.Zero),
@ -260,23 +306,18 @@ public partial class MarqueeText : Control
Value = end,
};
// Add the key frames to the animation
animation.KeyFrames.Add(frame1);
animation.KeyFrames.Add(frame2);
_marqueeStoryboard.Children.Add(animation);
// Add the double animation to the storyboard
marqueeStoryboard.Children.Add(animation);
// Set the storyboard target and target property
Storyboard.SetTarget(animation, _marqueeTransform);
Storyboard.SetTargetProperty(animation, property);
Storyboard.SetTargetProperty(animation, targetProperty);
VisualStateManager.GoToState(this, MarqueeActiveState, true);
_marqueeStoryboard.Begin();
if (resume)
{
// Seek the animation so the text is in the same position.
double progress = Math.Abs(start - value) / distance;
_marqueeStoryboard.Seek(TimeSpan.FromTicks((long)(duration.Ticks * progress)));
}
return true;
return marqueeStoryboard;
}
}

Просмотреть файл

@ -76,24 +76,24 @@
</StackPanel.RenderTransform>
<TextBlock x:Name="Segment1"
win:FontStretch="{TemplateBinding FontStretch}"
win:TextDecorations="{TemplateBinding TextDecorations}"
CharacterSpacing="{TemplateBinding CharacterSpacing}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Text}"
TextDecorations="{TemplateBinding TextDecorations}" />
Text="{TemplateBinding Text}" />
<TextBlock x:Name="Segment2"
win:FontStretch="{TemplateBinding FontStretch}"
win:TextDecorations="{TemplateBinding TextDecorations}"
CharacterSpacing="{TemplateBinding CharacterSpacing}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontStyle="{TemplateBinding FontStyle}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
Text="{TemplateBinding Text}"
TextDecorations="{TemplateBinding TextDecorations}" />
Text="{TemplateBinding Text}" />
</StackPanel>
</Grid>
</Grid>

Просмотреть файл

@ -1,3 +0,0 @@
@ECHO OFF
powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.8 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.8 KiB

Просмотреть файл

@ -1,42 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SettingsControlsExperiment.Samples.ClickableSettingsCardSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Spacing="3">
<labs:SettingsCard x:Name="settingsCard"
Description="A SettingsCard can be made clickable and you can leverage the Command property or Click event."
Header="A clickable SettingsCard"
IsClickEnabled="True"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE799;" />
</labs:SettingsCard.HeaderIcon>
</labs:SettingsCard>
<labs:SettingsCard ActionIconToolTip="Open in new window"
Description="You can customize the ActionIcon and ActionIconToolTip."
Header="Customizing the ActionIcon"
IsClickEnabled="True"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE774;" />
</labs:SettingsCard.HeaderIcon>
<labs:SettingsCard.ActionIcon>
<FontIcon Glyph="&#xE8A7;" />
</labs:SettingsCard.ActionIcon>
</labs:SettingsCard>
<labs:SettingsCard Header="Hiding the ActionIcon"
IsActionIconVisible="False"
IsClickEnabled="True"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE72E;" />
</labs:SettingsCard.HeaderIcon>
</labs:SettingsCard>
</StackPanel>
</Page>

Просмотреть файл

@ -1,23 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.ComponentModel;
namespace SettingsControlsExperiment.Samples;
[ToolkitSampleBoolOption("IsCardEnabled", true, Title = "Is Enabled")]
[ToolkitSample(id: nameof(ClickableSettingsCardSample), "ClickableSettingsCardSample", description: "A sample for showing how SettingsCard can be static or clickable.")]
public sealed partial class ClickableSettingsCardSample : Page
{
public ClickableSettingsCardSample()
{
this.InitializeComponent();
}
private async void OnCardClicked(object sender, RoutedEventArgs e)
{
await Windows.System.Launcher.LaunchUriAsync(new Uri("https://www.microsoft.com"));
}
}

Просмотреть файл

@ -1,31 +0,0 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>
<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>
<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>
<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>

Просмотреть файл

@ -1,22 +0,0 @@
---
title: SettingsCard
author: niels9001
description: A card control that can be used to create Windows 11 style settings experiences.
keywords: SettingsCard, Control, Layout, Settings
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 129
issue-id: 216
icon: Assets/SettingsCard.png
---
SettingsCard is a control that can be used to display settings in your experience. It uses the default styling found in Windows 11 and is easy to use, meets all accesibility standards and will make your settings page look great!
You can set the `Header`, `Description`, `HeaderIcon` and `Content` properties to create an easy to use experience, like so:
> [!SAMPLE SettingsCardSample]
SettingsCard can also be turned into a button, by setting the `IsClickEnabled` property. This can be useful whenever you want your settings component to navigate to a detail page or open an external link. You can set a custom icon by setting the `ActionIcon`, or hiding it completely by setting the `IsActionIconVisible` to `false`.
> [!SAMPLE ClickableSettingsCardSample]

Просмотреть файл

@ -1,57 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SettingsControlsExperiment.Samples.SettingsCardSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Spacing="3">
<labs:SettingsCard x:Name="settingsCard"
Description="This is a default card, with the Header, HeaderIcon, Description and Content set."
Header="This is the Header"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE799;" />
</labs:SettingsCard.HeaderIcon>
<ComboBox SelectedIndex="0">
<ComboBoxItem>Option 1</ComboBoxItem>
<ComboBoxItem>Option 2</ComboBoxItem>
<ComboBoxItem>Option 3</ComboBoxItem>
</ComboBox>
</labs:SettingsCard>
<labs:SettingsCard Description="You can use a FontIcon, SymbolIcon or BitmapIcon to set the cards HeaderIcon."
Header="Icon options"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.HeaderIcon>
<BitmapIcon ShowAsMonochrome="False"
UriSource="ms-appx:///Assets/AppTitleBar.scale-200.png" />
</labs:SettingsCard.HeaderIcon>
<ToggleSwitch />
</labs:SettingsCard>
<labs:SettingsCard Header="A card with custom objects as its Description"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.Description>
<HyperlinkButton Content="Learn more about Phone Link" />
</labs:SettingsCard.Description>
<Button Content="Open Phone Link"
Style="{StaticResource AccentButtonStyle}" />
</labs:SettingsCard>
<labs:SettingsCard Description="When resizing a SettingsCard, the Content will wrap vertically. You can override this breakpoint by setting the SettingsCardWrapThreshold resource. For edge cases, you can also hide the icon by setting SettingsCardWrapNoIconThreshold."
Header="Adaptive layouts"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE745;" />
</labs:SettingsCard.HeaderIcon>
<labs:SettingsCard.Resources>
<x:Double x:Key="SettingsCardWrapThreshold">800</x:Double>
<x:Double x:Key="SettingsCardWrapNoIconThreshold">600</x:Double>
</labs:SettingsCard.Resources>
<Button Content="This control will wrap vertically!"
Style="{StaticResource AccentButtonStyle}" />
</labs:SettingsCard>
</StackPanel>
</Page>

Просмотреть файл

@ -1,16 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SettingsControlsExperiment.Samples;
[ToolkitSampleBoolOption("IsCardEnabled", true, Title = "Is Enabled")]
[ToolkitSample(id: nameof(SettingsCardSample), "SettingsCard", description: "A sample for showing how SettingsCard can be static or clickable.")]
public sealed partial class SettingsCardSample : Page
{
public SettingsCardSample()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,9 +0,0 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>SettingsControls</ToolkitComponentName>
<LangVersion>10.0</LangVersion>
</PropertyGroup>
<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
</Project>

Просмотреть файл

@ -1,27 +0,0 @@
---
title: SettingsExpander
author: niels9001
description: An expander control that can be used to create Windows 11 style settings experiences.
keywords: SettingsCard, SettingsExpander, Expander, Control, Layout, Settings
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 129
issue-id: 216
icon: Assets/SettingsExpander.png
---
The `SettingsExpander` can be used to group multiple `SettingsCard`s into a single collapsable group.
A `SettingsExpander` can have it's own content to display a setting on the right, just like a `SettingsCard`, but in addition can have any number of extra `Items` to include as additional settings. These items are `SettingsCard`s themselves, which means you can easily move a setting into or out of Expanders just by cutting and pasting their XAML!
> [!SAMPLE SettingsExpanderSample]
You can easily override certain properties to create custom experiences. For instance, you can customize the `ContentAlignment` of a `SettingsCard`, to align your content to the Right (default), Left (hiding the `HeaderIcon`, `Header` and `Description`) or Vertically (usually best paired with changing the `HorizontalContentAlignment` to `Stretch`).
`SettingsExpander` is also an `ItemsControl`, so its items can be driven by a collection and the `ItemsSource` property. You can use the `ItemTemplate` to define how your data object is represented as a `SettingsCard`, as shown below. The `ItemsHeader` and `ItemsFooter` property can be used to host custom content at the start or end of the items list.
> [!SAMPLE SettingsExpanderItemsSourceSample]
NOTE: Due to [a bug](https://github.com/microsoft/microsoft-ui-xaml/issues/3842) related to the `ItemsRepeater` used in `SettingsExpander`, there might be visual glitches whenever the `SettingsExpander` expands and a `MaxWidth` is set on a parent `StackPanel`. As a workaround, the `StackPanel` (that has the `MaxWidth` set) can be wrapped in a `Grid` to overcome this issue. See the `SettingsPageExample` for snippet.

Просмотреть файл

@ -1,92 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SettingsControlsExperiment.Samples.SettingsExpanderItemsSourceSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:local="using:SettingsControlsExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.Labs.WinUI.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
<StackPanel Spacing="3">
<labs:SettingsExpander Description="The SettingsExpander can use ItemsSource to define its Items."
Header="Settings Expander with ItemsSource"
ItemsSource="{x:Bind MyDataSet}">
<labs:SettingsExpander.HeaderIcon>
<FontIcon Glyph="&#xEA37;" />
</labs:SettingsExpander.HeaderIcon>
<labs:SettingsExpander.ItemTemplate>
<DataTemplate x:DataType="local:MyDataModel">
<labs:SettingsCard Description="{x:Bind Info}"
Header="{x:Bind Name}">
<HyperlinkButton Content="{x:Bind LinkDescription}"
NavigateUri="{x:Bind Url}" />
</labs:SettingsCard>
</DataTemplate>
</labs:SettingsExpander.ItemTemplate>
<labs:SettingsExpander.ItemsHeader>
<muxc:InfoBar Title="This is the ItemsHeader"
BorderThickness="0"
CornerRadius="0"
IsIconVisible="False"
IsOpen="True"
Severity="Success">
<muxc:InfoBar.ActionButton>
<HyperlinkButton Content="It can host custom content" />
</muxc:InfoBar.ActionButton>
</muxc:InfoBar>
</labs:SettingsExpander.ItemsHeader>
<labs:SettingsExpander.ItemsFooter>
<labs:SettingsCard Header="This is the ItemsFooter"
Style="{StaticResource DefaultSettingsExpanderItemStyle}">
<Button Content="Add a device" />
</labs:SettingsCard>
</labs:SettingsExpander.ItemsFooter>
</labs:SettingsExpander>
<labs:SettingsExpander Description="SettingsExpander can use a DataTemplate, DataTemplateSelector, or IElementFactory for its ItemTemplate."
Header="Settings Expander with a custom ItemTemplate"
ItemsSource="{x:Bind MyDataSet}">
<labs:SettingsExpander.HeaderIcon>
<FontIcon Glyph="&#xEA37;" />
</labs:SettingsExpander.HeaderIcon>
<labs:SettingsExpander.ItemTemplate>
<local:MyDataModelTemplateSelector>
<local:MyDataModelTemplateSelector.ButtonTemplate>
<DataTemplate x:DataType="local:MyDataModel">
<labs:SettingsCard Description="{x:Bind ItemType}"
Header="{x:Bind Name}">
<Button Click="Button_Click"
Content="{x:Bind LinkDescription}" />
</labs:SettingsCard>
</DataTemplate>
</local:MyDataModelTemplateSelector.ButtonTemplate>
<local:MyDataModelTemplateSelector.LinkButtonTemplate>
<DataTemplate x:DataType="local:MyDataModel">
<labs:SettingsCard Description="{x:Bind ItemType}"
Header="{x:Bind Name}">
<HyperlinkButton Content="{x:Bind LinkDescription}"
NavigateUri="{x:Bind Url}" />
</labs:SettingsCard>
</DataTemplate>
</local:MyDataModelTemplateSelector.LinkButtonTemplate>
<local:MyDataModelTemplateSelector.NoButtonTemplate>
<DataTemplate x:DataType="local:MyDataModel">
<labs:SettingsCard Description="{x:Bind ItemType}"
Header="{x:Bind Name}" />
</DataTemplate>
</local:MyDataModelTemplateSelector.NoButtonTemplate>
</local:MyDataModelTemplateSelector>
</labs:SettingsExpander.ItemTemplate>
</labs:SettingsExpander>
</StackPanel>
</Page>

Просмотреть файл

@ -1,86 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.System;
namespace SettingsControlsExperiment.Samples;
[ToolkitSample(id: nameof(SettingsExpanderItemsSourceSample), "SettingsExpanderItemsSource", description: "The SettingsExpander can also be filled with items based on a collection.")]
public sealed partial class SettingsExpanderItemsSourceSample : Page
{
public ObservableCollection<MyDataModel> MyDataSet = new() {
new()
{
Name = "First Item",
Info = "More about first item.",
ItemType = "Item type: Button",
LinkDescription = "Click here for more on first item.",
Url = "https://microsoft.com/",
},
new()
{
Name = "Second Item",
Info = "More about second item.",
ItemType = "Item type: Link button",
LinkDescription = "Click here for more on second item.",
Url = "https://xbox.com/",
},
new()
{
Name = "Third Item",
Info = "More about third item.",
ItemType = "Item type: No button",
LinkDescription = "Click here for more on third item.",
Url = "https://toolkitlabs.dev/",
},
};
public SettingsExpanderItemsSourceSample()
{
this.InitializeComponent();
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
_ = await Launcher.LaunchUriAsync(new("https://microsoft.com/"));
}
}
public class MyDataModel
{
public string? Name { get; set; }
public string? Info { get; set; }
public string? ItemType { get; set; }
public string? LinkDescription { get; set; }
public string? Url { get; set; }
}
public class MyDataModelTemplateSelector : DataTemplateSelector
{
public DataTemplate? ButtonTemplate { get; set; }
public DataTemplate? LinkButtonTemplate { get; set; }
public DataTemplate? NoButtonTemplate { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
var itm = (MyDataModel)item;
if (itm.ItemType?.EndsWith("Button") == true)
{
return ButtonTemplate!;
}
else if (itm.ItemType?.EndsWith("Link button") == true)
{
return LinkButtonTemplate!;
}
else
{
return NoButtonTemplate!;
}
}
}

Просмотреть файл

@ -1,76 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SettingsControlsExperiment.Samples.SettingsExpanderSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<labs:SettingsExpander x:Name="settingsCard"
Description="The SettingsExpander has the same properties as a Card, and you can set SettingsCard as part of the Items collection."
Header="SettingsExpander"
IsEnabled="{x:Bind IsCardEnabled, Mode=OneWay}"
IsExpanded="{x:Bind IsCardExpanded, Mode=OneWay}">
<!-- TODO: This should be TwoWay bound but throws compile error in Uno. -->
<labs:SettingsExpander.HeaderIcon>
<FontIcon Glyph="&#xE91B;" />
</labs:SettingsExpander.HeaderIcon>
<ComboBox SelectedIndex="0">
<ComboBoxItem>Option 1</ComboBoxItem>
<ComboBoxItem>Option 2</ComboBoxItem>
<ComboBoxItem>Option 3</ComboBoxItem>
</ComboBox>
<labs:SettingsExpander.Items>
<labs:SettingsCard Header="A basic SettingsCard within an SettingsExpander">
<Button Content="Button" />
</labs:SettingsCard>
<labs:SettingsCard Description="SettingsCard within an Expander can be made clickable too!"
Header="This item can be clicked"
IsClickEnabled="True" />
<labs:SettingsCard ContentAlignment="Left">
<CheckBox Content="Here the ContentAlignment is set to Left. This is great for e.g. CheckBoxes or RadioButtons." />
</labs:SettingsCard>
<labs:SettingsCard HorizontalContentAlignment="Left"
ContentAlignment="Vertical"
Description="You can also align your content vertically. Make sure to set the HorizontalAlignment to Left when you do!"
Header="Vertically aligned">
<GridView SelectedIndex="1">
<GridViewItem>
<Border Width="64"
Height="64"
Background="#0078D4"
CornerRadius="4" />
</GridViewItem>
<GridViewItem>
<Border Width="64"
Height="64"
Background="#005EB7"
CornerRadius="4" />
</GridViewItem>
<GridViewItem>
<Border Width="64"
Height="64"
Background="#003D92"
CornerRadius="4" />
</GridViewItem>
<GridViewItem>
<Border Width="64"
Height="64"
Background="#001968"
CornerRadius="4" />
</GridViewItem>
</GridView>
</labs:SettingsCard>
<labs:SettingsCard Description="You can override the Left indention of a SettingsCard by overriding the SettingsCardLeftIndention"
Header="Customization">
<labs:SettingsCard.Resources>
<x:Double x:Key="SettingsCardLeftIndention">40</x:Double>
</labs:SettingsCard.Resources>
</labs:SettingsCard>
</labs:SettingsExpander.Items>
</labs:SettingsExpander>
</Page>

Просмотреть файл

@ -1,16 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SettingsControlsExperiment.Samples;
[ToolkitSampleBoolOption("IsCardExpanded", false, Title = "Is Expanded")]
[ToolkitSampleBoolOption("IsCardEnabled", true, Title = "Is Enabled")]
[ToolkitSample(id: nameof(SettingsExpanderSample), "SettingsExpander", description: "The SettingsExpander can be used to group settings. SettingsCards can be customized in terms of alignment and content.")]
public sealed partial class SettingsExpanderSample : Page
{
public SettingsExpanderSample()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,15 +0,0 @@
---
title: Settings Page Example
author: niels9001
description: A full example of building a Windows 11 style settings experience with SettingsCard and SettingsExpander.
keywords: SettingsCard, SettingsExpander, Example, Control, Layout, Settings
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 129
issue-id: 216
icon: Assets/SettingsExpander.png
---
> [!SAMPLE SettingsPageExample]

Просмотреть файл

@ -1,119 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SettingsControlsExperiment.Samples.SettingsPageExample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d">
<Page.Resources>
<!-- These styles can be referenced to create a consistent SettingsPage layout -->
<!-- Spacing between cards -->
<x:Double x:Key="SettingsCardSpacing">3</x:Double>
<!-- Style (inc. the correct spacing) of a section header -->
<Style x:Key="SettingsSectionHeaderTextBlockStyle"
BasedOn="{StaticResource BodyStrongTextBlockStyle}"
TargetType="TextBlock">
<Style.Setters>
<Setter Property="Margin" Value="1,29,0,5" />
</Style.Setters>
</Style>
</Page.Resources>
<ScrollViewer>
<Grid>
<StackPanel MaxWidth="1000"
HorizontalAlignment="Stretch"
Spacing="{StaticResource SettingsCardSpacing}">
<win:StackPanel.ChildrenTransitions>
<win:EntranceThemeTransition FromVerticalOffset="50" />
<win:RepositionThemeTransition IsStaggeringEnabled="False" />
</win:StackPanel.ChildrenTransitions>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="Section 1" />
<labs:SettingsCard Description="This is a default card, with the Header, HeaderIcon, Description and Content set"
Header="This is the Header">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE716;" />
</labs:SettingsCard.HeaderIcon>
<ToggleSwitch IsOn="True" />
</labs:SettingsCard>
<labs:SettingsExpander Description="The SettingsExpander has the same properties as a SettingsCard"
Header="SettingsExpander">
<labs:SettingsExpander.HeaderIcon>
<FontIcon Glyph="&#xE91B;" />
</labs:SettingsExpander.HeaderIcon>
<Button Content="Content"
Style="{StaticResource AccentButtonStyle}" />
<labs:SettingsExpander.Items>
<labs:SettingsCard Header="A basic SettingsCard within an SettingsExpander">
<Button Content="Button" />
</labs:SettingsCard>
<labs:SettingsCard Description="SettingsCard within an Expander can be made clickable too!"
Header="This item can be clicked"
IsClickEnabled="True" />
<labs:SettingsCard ContentAlignment="Left">
<CheckBox Content="Here the ContentAlignment is set to Left. This is great for e.g. CheckBoxes or RadioButtons" />
</labs:SettingsCard>
</labs:SettingsExpander.Items>
</labs:SettingsExpander>
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="Section 2" />
<labs:SettingsCard Description="Another card to show grouping of cards"
Header="Another SettingsCard">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE799;" />
</labs:SettingsCard.HeaderIcon>
<ComboBox SelectedIndex="0">
<ComboBoxItem>Option 1</ComboBoxItem>
<ComboBoxItem>Option 2</ComboBoxItem>
<ComboBoxItem>Option 3</ComboBoxItem>
</ComboBox>
</labs:SettingsCard>
<labs:SettingsCard Description="Another card to show grouping of cards"
Header="Yet another SettingsCard">
<labs:SettingsCard.HeaderIcon>
<FontIcon Glyph="&#xE768;" />
</labs:SettingsCard.HeaderIcon>
<Button Content="Content" />
</labs:SettingsCard>
<!-- Example 'About' section -->
<TextBlock Style="{StaticResource SettingsSectionHeaderTextBlockStyle}"
Text="About" />
<labs:SettingsExpander Description="© 2023. All rights reserved."
Header="Community Toolkit Gallery">
<labs:SettingsExpander.HeaderIcon>
<BitmapIcon ShowAsMonochrome="False"
UriSource="ms-appx:///Assets/AppTitleBar.scale-200.png" />
</labs:SettingsExpander.HeaderIcon>
<TextBlock win:IsTextSelectionEnabled="True"
Foreground="{ThemeResource TextFillColorSecondaryBrush}"
Style="{StaticResource CaptionTextBlockStyle}"
Text="Version 1.0.0.0" />
<labs:SettingsExpander.Items>
<labs:SettingsCard HorizontalContentAlignment="Left"
ContentAlignment="Left">
<StackPanel Margin="-12,0,0,0"
Orientation="Vertical">
<HyperlinkButton Content="Link 1" />
<HyperlinkButton Content="Link 2" />
<HyperlinkButton Content="Link 3" />
</StackPanel>
</labs:SettingsCard>
</labs:SettingsExpander.Items>
</labs:SettingsExpander>
<HyperlinkButton Margin="0,8,0,0"
Content="Send feedback" />
</StackPanel>
</Grid>
</ScrollViewer>
</Page>

Просмотреть файл

@ -1,14 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SettingsControlsExperiment.Samples;
[ToolkitSample(id: nameof(SettingsPageExample), "Settings Page Example", description: "A complete settings page example.")]
public sealed partial class SettingsPageExample : Page
{
public SettingsPageExample()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,13 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
// These `InternalsVisibleTo` calls are intended to make it easier for
// for any internal code to be testable in all the different test projects
// used with the Labs infrastructure.
[assembly: InternalsVisibleTo("SettingsControls.Tests.Uwp")]
[assembly: InternalsVisibleTo("SettingsControls.Tests.WinAppSdk")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.Uwp")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.WinAppSdk")]

Просмотреть файл

@ -1,20 +0,0 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>SettingsControls</ToolkitComponentName>
<Description>This package contains the SettingsCard and SettingsExpander controls.</Description>
<Version>0.0.18</Version>
<LangVersion>10.0</LangVersion>
<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.Labs.WinUI.SettingsControlsRns</RootNamespace>
</PropertyGroup>
<ItemGroup>
<None Update="SettingsExpander\SettingsExpander.xaml">
<Generator>MSBuild:Compile</Generator>
</None>
</ItemGroup>
<!-- Sets this up as a toolkit component's source project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" />
</Project>

Просмотреть файл

@ -1,31 +0,0 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<PackageReference Include="CommunityToolkit.Uwp.Triggers" Version="8.0.0-beta.1"/>
</ItemGroup>
<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<PackageReference Include="CommunityToolkit.Uwp.Triggers" Version="8.0.0-beta.1"/>
</ItemGroup>
<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<PackageReference Include="CommunityToolkit.WinUI.Triggers" Version="8.0.0-beta.1"/>
</ItemGroup>
<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<PackageReference Include="CommunityToolkit.WinUI.Triggers" Version="8.0.0-beta.1"/>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,9 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
internal static partial class ControlHelpers
{
internal static bool IsXamlRootAvailable { get; } = Windows.Foundation.Metadata.ApiInformation.IsPropertyPresent("Windows.UI.Xaml.UIElement", "XamlRoot");
}

Просмотреть файл

@ -1,59 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
// Adapted from https://github.com/rudyhuyn/XamlPlus
internal static class ResourceDictionaryExtensions
{
/// <summary>
/// Copies the <see cref="ResourceDictionary"/> provided as a parameter into the calling dictionary, includes overwriting the source location, theme dictionaries, and merged dictionaries.
/// </summary>
/// <param name="destination">ResourceDictionary to copy values to.</param>
/// <param name="source">ResourceDictionary to copy values from.</param>
internal static void CopyFrom(this ResourceDictionary destination, ResourceDictionary source)
{
if (source.Source != null)
{
destination.Source = source.Source;
}
else
{
// Clone theme dictionaries
if (source.ThemeDictionaries != null)
{
foreach (var theme in source.ThemeDictionaries)
{
if (theme.Value is ResourceDictionary themedResource)
{
var themeDictionary = new ResourceDictionary();
themeDictionary.CopyFrom(themedResource);
destination.ThemeDictionaries[theme.Key] = themeDictionary;
}
else
{
destination.ThemeDictionaries[theme.Key] = theme.Value;
}
}
}
// Clone merged dictionaries
if (source.MergedDictionaries != null)
{
foreach (var mergedResource in source.MergedDictionaries)
{
var themeDictionary = new ResourceDictionary();
themeDictionary.CopyFrom(mergedResource);
destination.MergedDictionaries.Add(themeDictionary);
}
}
// Clone all contents
foreach (var item in source)
{
destination[item.Key] = item.Value;
}
}
}
}

Просмотреть файл

@ -1,73 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
// Adapted from https://github.com/rudyhuyn/XamlPlus
public static partial class StyleExtensions
{
// Used to distinct normal ResourceDictionary and the one we add.
private sealed class StyleExtensionResourceDictionary : ResourceDictionary
{
}
public static ResourceDictionary GetResources(Style obj)
{
return (ResourceDictionary)obj.GetValue(ResourcesProperty);
}
public static void SetResources(Style obj, ResourceDictionary value)
{
obj.SetValue(ResourcesProperty, value);
}
public static readonly DependencyProperty ResourcesProperty =
DependencyProperty.RegisterAttached("Resources", typeof(ResourceDictionary), typeof(StyleExtensions), new PropertyMetadata(null, ResourcesChanged));
private static void ResourcesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (!(sender is FrameworkElement frameworkElement))
{
return;
}
var mergedDictionaries = frameworkElement.Resources?.MergedDictionaries;
if (mergedDictionaries == null)
{
return;
}
var existingResourceDictionary =
mergedDictionaries.FirstOrDefault(c => c is StyleExtensionResourceDictionary);
if (existingResourceDictionary != null)
{
// Remove the existing resource dictionary
mergedDictionaries.Remove(existingResourceDictionary);
}
if (e.NewValue is ResourceDictionary resource)
{
var clonedResources = new StyleExtensionResourceDictionary();
clonedResources.CopyFrom(resource);
mergedDictionaries.Add(clonedResources);
}
if (frameworkElement.IsLoaded)
{
// Only force if the style was applied after the control was loaded
ForceControlToReloadThemeResources(frameworkElement);
}
}
private static void ForceControlToReloadThemeResources(FrameworkElement frameworkElement)
{
// To force the refresh of all resource references.
// Note: Doesn't work when in high-contrast.
var currentRequestedTheme = frameworkElement.RequestedTheme;
frameworkElement.RequestedTheme = currentRequestedTheme == ElementTheme.Dark
? ElementTheme.Light
: ElementTheme.Dark;
frameworkElement.RequestedTheme = currentRequestedTheme;
}
}

Просмотреть файл

@ -1,193 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
public partial class SettingsCard : ButtonBase
{
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Header"/> property.
/// </summary>
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
nameof(Header),
typeof(object),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: null, (d, e) => ((SettingsCard)d).OnHeaderPropertyChanged((object)e.OldValue, (object)e.NewValue)));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Description"/> property.
/// </summary>
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
nameof(Description),
typeof(object),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: null, (d, e) => ((SettingsCard)d).OnDescriptionPropertyChanged((object)e.OldValue, (object)e.NewValue)));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="HeaderIcon"/> property.
/// </summary>
public static readonly DependencyProperty HeaderIconProperty = DependencyProperty.Register(
nameof(HeaderIcon),
typeof(IconElement),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: null, (d, e) => ((SettingsCard)d).OnHeaderIconPropertyChanged((IconElement)e.OldValue, (IconElement)e.NewValue)));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="ActionIcon"/> property.
/// </summary>
public static readonly DependencyProperty ActionIconProperty = DependencyProperty.Register(
nameof(ActionIcon),
typeof(IconElement),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: "\ue974"));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="ActionIconToolTip"/> property.
/// </summary>
public static readonly DependencyProperty ActionIconToolTipProperty = DependencyProperty.Register(
nameof(ActionIconToolTip),
typeof(string),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: "More"));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="IsClickEnabled"/> property.
/// </summary>
public static readonly DependencyProperty IsClickEnabledProperty = DependencyProperty.Register(
nameof(IsClickEnabled),
typeof(bool),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: false, (d, e) => ((SettingsCard)d).OnIsClickEnabledPropertyChanged((bool)e.OldValue, (bool)e.NewValue)));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="ContentAlignment"/> property.
/// </summary>
public static readonly DependencyProperty ContentAlignmentProperty = DependencyProperty.Register(
nameof(ContentAlignment),
typeof(ContentAlignment),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: ContentAlignment.Right));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="IsActionIconVisible"/> property.
/// </summary>
public static readonly DependencyProperty IsActionIconVisibleProperty = DependencyProperty.Register(
nameof(IsActionIconVisible),
typeof(bool),
typeof(SettingsCard),
new PropertyMetadata(defaultValue: true, (d, e) => ((SettingsCard)d).OnIsActionIconVisiblePropertyChanged((bool)e.OldValue, (bool)e.NewValue)));
/// <summary>
/// Gets or sets the Header.
/// </summary>
public object Header
{
get => (object)GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
/// <summary>
/// Gets or sets the description.
/// </summary>
#pragma warning disable CS0109 // Member does not hide an inherited member; new keyword is not required
public new object Description
#pragma warning restore CS0109 // Member does not hide an inherited member; new keyword is not required
{
get => (object)GetValue(DescriptionProperty);
set => SetValue(DescriptionProperty, value);
}
/// <summary>
/// Gets or sets the icon on the left.
/// </summary>
public IconElement HeaderIcon
{
get => (IconElement)GetValue(HeaderIconProperty);
set => SetValue(HeaderIconProperty, value);
}
/// <summary>
/// Gets or sets the icon that is shown when IsClickEnabled is set to true.
/// </summary>
public IconElement ActionIcon
{
get => (IconElement)GetValue(ActionIconProperty);
set => SetValue(ActionIconProperty, value);
}
/// <summary>
/// Gets or sets the tooltip of the ActionIcon.
/// </summary>
public string ActionIconToolTip
{
get => (string)GetValue(ActionIconToolTipProperty);
set => SetValue(ActionIconToolTipProperty, value);
}
/// <summary>
/// Gets or sets if the card can be clicked.
/// </summary>
public bool IsClickEnabled
{
get => (bool)GetValue(IsClickEnabledProperty);
set => SetValue(IsClickEnabledProperty, value);
}
/// <summary>
/// Gets or sets the alignment of the Content
/// </summary>
public ContentAlignment ContentAlignment
{
get => (ContentAlignment)GetValue(ContentAlignmentProperty);
set => SetValue(ContentAlignmentProperty, value);
}
/// <summary>
/// Gets or sets if the ActionIcon is shown.
/// </summary>
public bool IsActionIconVisible
{
get => (bool)GetValue(IsActionIconVisibleProperty);
set => SetValue(IsActionIconVisibleProperty, value);
}
protected virtual void OnIsClickEnabledPropertyChanged(bool oldValue, bool newValue)
{
OnIsClickEnabledChanged();
}
protected virtual void OnHeaderIconPropertyChanged(IconElement oldValue, IconElement newValue)
{
OnHeaderIconChanged();
}
protected virtual void OnHeaderPropertyChanged(object oldValue, object newValue)
{
OnHeaderChanged();
}
protected virtual void OnDescriptionPropertyChanged(object oldValue, object newValue)
{
OnDescriptionChanged();
}
protected virtual void OnIsActionIconVisiblePropertyChanged(bool oldValue, bool newValue)
{
OnActionIconChanged();
}
}
public enum ContentAlignment
{
/// <summary>
/// The Content is aligned to the right. Default state.
/// </summary>
Right,
/// <summary>
/// The Content is left-aligned while the Header, HeaderIcon and Description are collapsed. This is commonly used for Content types such as CheckBoxes, RadioButtons and custom layouts.
/// </summary>
Left,
/// <summary>
/// The Content is vertically aligned.
/// </summary>
Vertical
}

Просмотреть файл

@ -1,233 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// This is the base control to create consistent settings experiences, inline with the Windows 11 design language.
/// A SettingsCard can also be hosted within a SettingsExpander.
/// </summary>
[TemplatePart(Name = ActionIconPresenterHolder, Type = typeof(Viewbox))]
[TemplatePart(Name = HeaderPresenter, Type = typeof(ContentPresenter))]
[TemplatePart(Name = DescriptionPresenter, Type = typeof(ContentPresenter))]
[TemplatePart(Name = HeaderIconPresenterHolder, Type = typeof(Viewbox))]
public partial class SettingsCard : ButtonBase
{
internal const string NormalState = "Normal";
internal const string PointerOverState = "PointerOver";
internal const string PressedState = "Pressed";
internal const string DisabledState = "Disabled";
internal const string ActionIconPresenterHolder = "PART_ActionIconPresenterHolder";
internal const string HeaderPresenter = "PART_HeaderPresenter";
internal const string DescriptionPresenter = "PART_DescriptionPresenter";
internal const string HeaderIconPresenterHolder = "PART_HeaderIconPresenterHolder";
/// <summary>
/// Creates a new instance of the <see cref="SettingsCard"/> class.
/// </summary>
public SettingsCard()
{
this.DefaultStyleKey = typeof(SettingsCard);
}
/// <inheritdoc />
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
IsEnabledChanged -= OnIsEnabledChanged;
OnActionIconChanged();
OnHeaderChanged();
OnHeaderIconChanged();
OnDescriptionChanged();
OnIsClickEnabledChanged();
VisualStateManager.GoToState(this, IsEnabled ? NormalState : DisabledState, true);
RegisterAutomation();
IsEnabledChanged += OnIsEnabledChanged;
}
private void RegisterAutomation()
{
if (Header is string headerString && headerString != string.Empty)
{
AutomationProperties.SetName(this, headerString);
// We don't want to override an AutomationProperties.Name that is manually set, or if the Content basetype is of type ButtonBase (the ButtonBase.Content will be used then)
if (Content is UIElement element && string.IsNullOrEmpty(AutomationProperties.GetName(element)) && element.GetType().BaseType != typeof(ButtonBase) && element.GetType() != typeof(TextBlock))
{
AutomationProperties.SetName(element, headerString);
}
}
}
private void EnableButtonInteraction()
{
DisableButtonInteraction();
IsTabStop = true;
PointerEntered += Control_PointerEntered;
PointerExited += Control_PointerExited;
PointerCaptureLost += Control_PointerCaptureLost;
PointerCanceled += Control_PointerCanceled;
PreviewKeyDown += Control_PreviewKeyDown;
PreviewKeyUp += Control_PreviewKeyUp;
}
private void DisableButtonInteraction()
{
IsTabStop = false;
PointerEntered -= Control_PointerEntered;
PointerExited -= Control_PointerExited;
PointerCaptureLost -= Control_PointerCaptureLost;
PointerCanceled -= Control_PointerCanceled;
PreviewKeyDown -= Control_PreviewKeyDown;
PreviewKeyUp -= Control_PreviewKeyUp;
}
private void Control_PreviewKeyUp(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter || e.Key == Windows.System.VirtualKey.Space || e.Key == Windows.System.VirtualKey.GamepadA)
{
VisualStateManager.GoToState(this, NormalState, true);
}
}
private void Control_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter || e.Key == Windows.System.VirtualKey.Space || e.Key == Windows.System.VirtualKey.GamepadA)
{
// Check if the active focus is on the card itself - only then we show the pressed state.
if (GetFocusedElement() is SettingsCard)
{
VisualStateManager.GoToState(this, PressedState, true);
}
}
}
public void Control_PointerEntered(object sender, PointerRoutedEventArgs e)
{
base.OnPointerEntered(e);
VisualStateManager.GoToState(this, PointerOverState, true);
}
public void Control_PointerExited(object sender, PointerRoutedEventArgs e)
{
base.OnPointerExited(e);
VisualStateManager.GoToState(this, NormalState, true);
}
private void Control_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
{
base.OnPointerCaptureLost(e);
VisualStateManager.GoToState(this, NormalState, true);
}
private void Control_PointerCanceled(object sender, PointerRoutedEventArgs e)
{
base.OnPointerCanceled(e);
VisualStateManager.GoToState(this, NormalState, true);
}
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
// e.Handled = true;
if (IsClickEnabled)
{
base.OnPointerPressed(e);
VisualStateManager.GoToState(this, PressedState, true);
}
}
protected override void OnPointerReleased(PointerRoutedEventArgs e)
{
if (IsClickEnabled)
{
base.OnPointerReleased(e);
VisualStateManager.GoToState(this, NormalState, true);
}
}
/// <summary>
/// Creates AutomationPeer
/// </summary>
/// <returns>An automation peer for <see cref="SettingsCard"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new SettingsCardAutomationPeer(this);
}
private void OnIsClickEnabledChanged()
{
OnActionIconChanged();
if (IsClickEnabled)
{
EnableButtonInteraction();
}
else
{
DisableButtonInteraction();
}
}
private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
VisualStateManager.GoToState(this, IsEnabled ? NormalState : DisabledState, true);
}
private void OnActionIconChanged()
{
if (GetTemplateChild(ActionIconPresenterHolder) is FrameworkElement actionIconPresenter)
{
if (IsClickEnabled && IsActionIconVisible)
{
actionIconPresenter.Visibility = Visibility.Visible;
}
else
{
actionIconPresenter.Visibility =Visibility.Collapsed;
}
}
}
private void OnHeaderIconChanged()
{
if (GetTemplateChild(HeaderIconPresenterHolder) is FrameworkElement headerIconPresenter)
{
headerIconPresenter.Visibility = HeaderIcon != null
? Visibility.Visible
: Visibility.Collapsed;
}
}
private void OnDescriptionChanged()
{
if (GetTemplateChild(DescriptionPresenter) is FrameworkElement descriptionPresenter)
{
descriptionPresenter.Visibility = Description != null
? Visibility.Visible
: Visibility.Collapsed;
}
}
private void OnHeaderChanged()
{
if (GetTemplateChild(HeaderPresenter) is FrameworkElement headerPresenter)
{
headerPresenter.Visibility = Header != null
? Visibility.Visible
: Visibility.Collapsed;
}
}
private FrameworkElement? GetFocusedElement()
{
if (ControlHelpers.IsXamlRootAvailable && XamlRoot != null)
{
return FocusManager.GetFocusedElement(XamlRoot) as FrameworkElement;
}
else
{
return FocusManager.GetFocusedElement() as FrameworkElement;
}
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,47 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Text;
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// AutomationPeer for SettingsCard
/// </summary>
public class SettingsCardAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="SettingsCard"/> class.
/// </summary>
/// <param name="owner">SettingsCard</param>
public SettingsCardAutomationPeer(SettingsCard owner)
: base(owner)
{
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Group;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("SettingsCardAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
}

Просмотреть файл

@ -1,17 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
public partial class SettingsExpander
{
/// <summary>
/// Fires when the SettingsExpander is opened
/// </summary>
public event EventHandler? Expanded;
/// <summary>
/// Fires when the expander is closed
/// </summary>
public event EventHandler? Collapsed;
}

Просмотреть файл

@ -1,70 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
//// Implement properties for ItemsControl like behavior.
public partial class SettingsExpander
{
public IList<object> Items
{
get { return (IList<object>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register(nameof(Items), typeof(IList<object>), typeof(SettingsExpander), new PropertyMetadata(null, OnItemsConnectedPropertyChanged));
public object ItemsSource
{
get { return (object)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(SettingsExpander), new PropertyMetadata(null, OnItemsConnectedPropertyChanged));
public object ItemTemplate
{
get { return (object)GetValue(ItemTemplateProperty); }
set { SetValue(ItemTemplateProperty, value); }
}
public static readonly DependencyProperty ItemTemplateProperty =
DependencyProperty.Register(nameof(ItemTemplate), typeof(object), typeof(SettingsExpander), new PropertyMetadata(null));
public StyleSelector ItemContainerStyleSelector
{
get { return (StyleSelector)GetValue(ItemContainerStyleSelectorProperty); }
set { SetValue(ItemContainerStyleSelectorProperty, value); }
}
public static readonly DependencyProperty ItemContainerStyleSelectorProperty =
DependencyProperty.Register(nameof(ItemContainerStyleSelector), typeof(StyleSelector), typeof(SettingsExpander), new PropertyMetadata(null));
private static void OnItemsConnectedPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
if (dependencyObject is SettingsExpander expander && expander._itemsRepeater is not null)
{
var datasource = expander.ItemsSource;
if (datasource is null)
{
datasource = expander.Items;
}
expander._itemsRepeater.ItemsSource = datasource;
}
}
private void ItemsRepeater_ElementPrepared(MUXC.ItemsRepeater sender, MUXC.ItemsRepeaterElementPreparedEventArgs args)
{
if (ItemContainerStyleSelector != null &&
args.Element is FrameworkElement element &&
element.ReadLocalValue(FrameworkElement.StyleProperty) == DependencyProperty.UnsetValue)
{
// TODO: Get item from args.Index?
element.Style = ItemContainerStyleSelector.SelectStyle(null, element);
}
}
}

Просмотреть файл

@ -1,153 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
[ContentProperty(Name = nameof(Content))]
public partial class SettingsExpander
{
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Header"/> property.
/// </summary>
public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
nameof(Header),
typeof(object),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: null));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Description"/> property.
/// </summary>
public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register(
nameof(Description),
typeof(object),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: null));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="HeaderIcon"/> property.
/// </summary>
public static readonly DependencyProperty HeaderIconProperty = DependencyProperty.Register(
nameof(HeaderIcon),
typeof(IconElement),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: null));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Content"/> property.
/// </summary>
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register(
nameof(Content),
typeof(object),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: null));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Content"/> property.
/// </summary>
public static readonly DependencyProperty ItemsHeaderProperty = DependencyProperty.Register(
nameof(ItemsHeader),
typeof(UIElement),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: null));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="Content"/> property.
/// </summary>
public static readonly DependencyProperty ItemsFooterProperty = DependencyProperty.Register(
nameof(ItemsFooter),
typeof(UIElement),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: null));
/// <summary>
/// The backing <see cref="DependencyProperty"/> for the <see cref="IsExpanded"/> property.
/// </summary>
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(
nameof(IsExpanded),
typeof(bool),
typeof(SettingsExpander),
new PropertyMetadata(defaultValue: false, (d, e) => ((SettingsExpander)d).OnIsExpandedPropertyChanged((bool)e.OldValue, (bool)e.NewValue)));
/// <summary>
///
/// <summary>
/// Gets or sets the Header.
/// </summary>
public object Header
{
get => (object)GetValue(HeaderProperty);
set => SetValue(HeaderProperty, value);
}
/// <summary>
/// Gets or sets the Description.
/// </summary>
#pragma warning disable CS0109 // Member does not hide an inherited member; new keyword is not required
public new object Description
#pragma warning restore CS0109 // Member does not hide an inherited member; new keyword is not required
{
get => (object)GetValue(DescriptionProperty);
set => SetValue(DescriptionProperty, value);
}
/// <summary>
/// Gets or sets the HeaderIcon.
/// </summary>
public IconElement HeaderIcon
{
get => (IconElement)GetValue(HeaderIconProperty);
set => SetValue(HeaderIconProperty, value);
}
/// <summary>
/// Gets or sets the Content.
/// </summary>
public object Content
{
get => (object)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
/// <summary>
/// Gets or sets the ItemsFooter.
/// </summary>
public UIElement ItemsHeader
{
get => (UIElement)GetValue(ItemsHeaderProperty);
set => SetValue(ItemsHeaderProperty, value);
}
/// <summary>
/// Gets or sets the ItemsFooter.
/// </summary>
public UIElement ItemsFooter
{
get => (UIElement)GetValue(ItemsFooterProperty);
set => SetValue(ItemsFooterProperty, value);
}
/// <summary>
/// Gets or sets the IsExpanded state.
/// </summary>
public bool IsExpanded
{
get => (bool)GetValue(IsExpandedProperty);
set => SetValue(IsExpandedProperty, value);
}
protected virtual void OnIsExpandedPropertyChanged(bool oldValue, bool newValue)
{
OnIsExpandedChanged(oldValue, newValue);
if (newValue)
{
Expanded?.Invoke(this, EventArgs.Empty);
}
else
{
Collapsed?.Invoke(this, EventArgs.Empty);
}
}
}

Просмотреть файл

@ -1,71 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
//// Note: ItemsRepeater will request all the available horizontal space: https://github.com/microsoft/microsoft-ui-xaml/issues/3842
[TemplatePart(Name = PART_ItemsRepeater, Type = typeof(MUXC.ItemsRepeater))]
public partial class SettingsExpander : Control
{
private const string PART_ItemsRepeater = "PART_ItemsRepeater";
private MUXC.ItemsRepeater? _itemsRepeater;
/// <summary>
/// The SettingsExpander is a collapsable control to host multiple SettingsCards.
/// </summary>
public SettingsExpander()
{
this.DefaultStyleKey = typeof(SettingsExpander);
Items = new List<object>();
}
/// <inheritdoc />
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
RegisterAutomation();
if (_itemsRepeater != null)
{
_itemsRepeater.ElementPrepared -= this.ItemsRepeater_ElementPrepared;
}
_itemsRepeater = GetTemplateChild(PART_ItemsRepeater) as MUXC.ItemsRepeater;
if (_itemsRepeater != null)
{
_itemsRepeater.ElementPrepared += this.ItemsRepeater_ElementPrepared;
// Update it's source based on our current items properties.
OnItemsConnectedPropertyChanged(this, null!); // Can't get it to accept type here? (DependencyPropertyChangedEventArgs)EventArgs.Empty
}
}
private void RegisterAutomation()
{
if (Header is string headerString && headerString != string.Empty)
{
if (!string.IsNullOrEmpty(headerString) && string.IsNullOrEmpty(AutomationProperties.GetName(this)))
{
AutomationProperties.SetName(this, headerString);
}
}
}
/// <summary>
/// Creates AutomationPeer
/// </summary>
/// <returns>An automation peer for <see cref="SettingsExpander"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new SettingsExpanderAutomationPeer(this);
}
private void OnIsExpandedChanged(bool oldValue, bool newValue)
{
var peer = FrameworkElementAutomationPeer.FromElement(this) as SettingsExpanderAutomationPeer;
peer?.RaiseExpandedChangedEvent(newValue);
}
}

Просмотреть файл

@ -1,578 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:animatedvisuals="using:Microsoft.UI.Xaml.Controls.AnimatedVisuals"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.Labs.WinUI.SettingsControls/SettingsCard/SettingsCard.xaml" />
</ResourceDictionary.MergedDictionaries>
<x:String x:Key="SettingsExpanderChevronToolTip">Show all settings</x:String>
<Thickness x:Key="SettingsExpanderHeaderPadding">16,16,4,16</Thickness>
<Thickness x:Key="SettingsExpanderItemPadding">58,8,44,8</Thickness>
<Thickness x:Key="SettingsExpanderItemBorderThickness">0,1,0,0</Thickness>
<Thickness x:Key="ClickableSettingsExpanderItemPadding">58,8,16,8</Thickness>
<x:Double x:Key="SettingsExpanderContentMinHeight">16</x:Double>
<x:Double x:Key="SettingsExpanderChevronButtonWidth">32</x:Double>
<x:Double x:Key="SettingsExpanderChevronButtonHeight">32</x:Double>
<Style x:Key="DefaultSettingsExpanderItemStyle"
BasedOn="{StaticResource DefaultSettingsCardStyle}"
TargetType="labs:SettingsCard">
<Style.Setters>
<Setter Property="BorderThickness" Value="{ThemeResource SettingsExpanderItemBorderThickness}" />
<Setter Property="MinHeight" Value="52" />
<Setter Property="Padding" Value="{ThemeResource SettingsExpanderItemPadding}" />
<Setter Property="CornerRadius" Value="0" />
</Style.Setters>
</Style>
<Style x:Key="ClickableSettingsExpanderItemStyle"
BasedOn="{StaticResource DefaultSettingsExpanderItemStyle}"
TargetType="labs:SettingsCard">
<Style.Setters>
<Setter Property="Padding" Value="{ThemeResource ClickableSettingsExpanderItemPadding}" />
</Style.Setters>
</Style>
<labs:SettingsExpanderItemStyleSelector x:Key="SettingsExpanderItemStyleSelector"
ClickableStyle="{StaticResource ClickableSettingsExpanderItemStyle}"
DefaultStyle="{StaticResource DefaultSettingsExpanderItemStyle}" />
<!-- Implicitly applied default style -->
<Style BasedOn="{StaticResource DefaultSettingsExpanderStyle}"
TargetType="labs:SettingsExpander" />
<Style x:Key="DefaultSettingsExpanderStyle"
TargetType="labs:SettingsExpander">
<Style.Setters>
<Setter Property="Background" Value="{ThemeResource SettingsCardBackground}" />
<Setter Property="Foreground" Value="{ThemeResource SettingsCardForeground}" />
<Setter Property="BorderBrush" Value="{ThemeResource SettingsCardBorderBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource SettingsCardBorderThickness}" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="MinHeight" Value="{ThemeResource SettingsCardMinHeight}" />
<Setter Property="MinWidth" Value="{ThemeResource SettingsCardMinWidth}" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Padding" Value="{ThemeResource SettingsExpanderHeaderPadding}" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="UseSystemFocusVisuals" Value="{StaticResource UseSystemFocusVisuals}" />
<Setter Property="ItemContainerStyleSelector" Value="{StaticResource SettingsExpanderItemStyleSelector}" />
<Setter Property="FocusVisualMargin" Value="-3" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="labs:SettingsExpander">
<muxc:Expander MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
win:AutomationProperties.HelpText="{TemplateBinding AutomationProperties.HelpText}"
win:AutomationProperties.Name="{TemplateBinding AutomationProperties.Name}"
IsExpanded="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Style="{StaticResource SettingsExpanderExpanderStyle}">
<muxc:Expander.Header>
<labs:SettingsCard Padding="{StaticResource SettingsExpanderHeaderPadding}"
VerticalAlignment="Center"
Background="Transparent"
BorderThickness="0"
Content="{TemplateBinding Content}"
Description="{TemplateBinding Description}"
Header="{TemplateBinding Header}"
HeaderIcon="{TemplateBinding HeaderIcon}"
IsClickEnabled="False" />
</muxc:Expander.Header>
<muxc:Expander.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentPresenter Content="{TemplateBinding ItemsHeader}" />
<muxc:ItemsRepeater x:Name="PART_ItemsRepeater"
Grid.Row="1"
ItemTemplate="{Binding ItemTemplate, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
TabFocusNavigation="Local">
<muxc:ItemsRepeater.Layout>
<muxc:StackLayout Orientation="Vertical" />
</muxc:ItemsRepeater.Layout>
</muxc:ItemsRepeater>
<ContentPresenter Grid.Row="2"
Content="{TemplateBinding ItemsFooter}" />
</Grid>
</muxc:Expander.Content>
</muxc:Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
<Style x:Key="SettingsExpanderExpanderStyle"
TargetType="muxc:Expander">
<Setter Property="Background" Value="{ThemeResource ExpanderContentBackground}" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="MinWidth" Value="{ThemeResource FlyoutThemeMinWidth}" />
<Setter Property="MinHeight" Value="{StaticResource ExpanderMinHeight}" />
<Setter Property="BorderThickness" Value="{ThemeResource ExpanderContentDownBorderThickness}" />
<Setter Property="BorderBrush" Value="{ThemeResource ExpanderContentBorderBrush}" />
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="CornerRadius" Value="{ThemeResource ControlCornerRadius}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="muxc:Expander">
<Grid MinWidth="{TemplateBinding MinWidth}"
MaxWidth="{TemplateBinding MaxWidth}">
<Grid.RowDefinitions>
<RowDefinition x:Name="Row0"
Height="Auto" />
<RowDefinition x:Name="Row1"
Height="*" />
</Grid.RowDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="ExpandStates">
<VisualState x:Name="ExpandUp">
<VisualState.Setters>
<Setter Target="ExpanderHeader.CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomCornerRadiusFilterConverter}}" />
</VisualState.Setters>
<VisualState.Storyboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0"
Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ContentHeight}" />
<SplineDoubleKeyFrame KeySpline="0.0, 0.0, 0.0, 1.0"
KeyTime="0:0:0.333"
Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState.Storyboard>
</VisualState>
<VisualState x:Name="CollapseDown">
<VisualState.Storyboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.2"
Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="0" />
<SplineDoubleKeyFrame KeySpline="1.0, 1.0, 0.0, 1.0"
KeyTime="0:0:0.167"
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.ContentHeight}" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState.Storyboard>
</VisualState>
<VisualState x:Name="ExpandDown">
<VisualState.Setters>
<Setter Target="ExpanderHeader.CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopCornerRadiusFilterConverter}}" />
</VisualState.Setters>
<VisualState.Storyboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0"
Value="Visible" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.NegativeContentHeight}" />
<SplineDoubleKeyFrame KeySpline="0.0, 0.0, 0.0, 1.0"
KeyTime="0:0:0.333"
Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState.Storyboard>
</VisualState>
<VisualState x:Name="CollapseUp">
<VisualState.Storyboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="Visibility">
<DiscreteObjectKeyFrame KeyTime="0:0:0.167"
Value="Collapsed" />
</ObjectAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="ExpanderContent"
Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)">
<DiscreteDoubleKeyFrame KeyTime="0"
Value="0" />
<SplineDoubleKeyFrame KeySpline="1.0, 1.0, 0.0, 1.0"
KeyTime="0:0:0.167"
Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.NegativeContentHeight}" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState.Storyboard>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ExpandDirectionStates">
<VisualState x:Name="Down" />
<VisualState x:Name="Up">
<VisualState.Setters>
<Setter Target="ExpanderHeader.Style" Value="{StaticResource ExpanderHeaderUpStyle}" />
<Setter Target="ExpanderContent.BorderThickness" Value="{StaticResource ExpanderContentUpBorderThickness}" />
<Setter Target="ExpanderContent.CornerRadius" Value="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource TopCornerRadiusFilterConverter}}" />
<Setter Target="ExpanderHeader.(Grid.Row)" Value="1" />
<Setter Target="ExpanderContentClip.(Grid.Row)" Value="0" />
<Setter Target="Row0.Height" Value="*" />
<Setter Target="Row1.Height" Value="Auto" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ToggleButton x:Name="ExpanderHeader"
MinHeight="{TemplateBinding MinHeight}"
Padding="{StaticResource ExpanderHeaderPadding}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="{StaticResource ExpanderHeaderHorizontalContentAlignment}"
VerticalContentAlignment="{StaticResource ExpanderHeaderVerticalContentAlignment}"
win:AutomationProperties.AutomationId="ExpanderToggleButton"
win:AutomationProperties.Name="{TemplateBinding AutomationProperties.Name}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{ThemeResource ExpanderHeaderBorderBrush}"
BorderThickness="{ThemeResource ExpanderHeaderBorderThickness}"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}"
CornerRadius="{TemplateBinding CornerRadius}"
IsChecked="{Binding Path=IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
IsEnabled="{TemplateBinding IsEnabled}"
IsTabStop="True"
Style="{StaticResource SettingsExpanderHeaderDownStyle}" />
<!-- The clip is a composition clip applied in code -->
<Border x:Name="ExpanderContentClip"
Grid.Row="1">
<Border x:Name="ExpanderContent"
MinHeight="{ThemeResource SettingsExpanderContentMinHeight}"
Padding="{TemplateBinding Padding}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{StaticResource ExpanderContentDownBorderThickness}"
CornerRadius="{Binding CornerRadius, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource BottomCornerRadiusFilterConverter}}"
Visibility="Collapsed">
<ContentPresenter Margin="0,-2,0,0"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" />
<Border.RenderTransform>
<CompositeTransform />
</Border.RenderTransform>
</Border>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SettingsExpanderHeaderDownStyle"
TargetType="ToggleButton">
<Setter Property="Padding" Value="0" />
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="BackgroundSizing" Value="InnerBorderEdge" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid x:Name="ToggleButtonGrid"
Width="{TemplateBinding Width}"
MinWidth="{TemplateBinding MinWidth}"
MinHeight="{TemplateBinding MinHeight}"
MaxWidth="{TemplateBinding MaxWidth}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
Background="{TemplateBinding Background}"
BackgroundSizing="{TemplateBinding BackgroundSizing}"
BorderBrush="{ThemeResource ExpanderHeaderBorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackground}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="PointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronPointerOverForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ExpandCollapseChevron.(muxc:AnimatedIcon.State)" Value="PointerOverOff" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronPressedForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ExpandCollapseChevron.(muxc:AnimatedIcon.State)" Value="PressedOff" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderDisabledForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderDisabledForeground}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="Checked">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevronBorder"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronBorderBrush}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevronBorder"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronBackground}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ExpandCollapseChevron.(muxc:AnimatedIcon.State)" Value="NormalOn" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="CheckedPointerOver">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderForegroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronPointerOverForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushPointerOver}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackgroundPointerOver}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ExpandCollapseChevron.(muxc:AnimatedIcon.State)" Value="PointerOverOn" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="CheckedPressed">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderForegroundPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderChevronPressedForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushPressed}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBackgroundPressed}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ExpandCollapseChevron.(muxc:AnimatedIcon.State)" Value="PressedOn" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="CheckedDisabled">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderDisabledForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ExpandCollapseChevron"
Storyboard.TargetProperty="Foreground">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource ExpanderHeaderDisabledForeground}" />
</ObjectAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ToggleButtonGrid"
Storyboard.TargetProperty="BorderBrush">
<DiscreteObjectKeyFrame KeyTime="0"
Value="{ThemeResource SettingsCardBorderBrushDisabled}" />
</ObjectAnimationUsingKeyFrames>
</Storyboard>
<VisualState.Setters>
<Setter Target="ExpandCollapseChevron.(muxc:AnimatedIcon.State)" Value="NormalOn" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Indeterminate" />
<VisualState x:Name="IndeterminatePointerOver" />
<VisualState x:Name="IndeterminatePressed" />
<VisualState x:Name="IndeterminateDisabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ContentPresenter x:Name="ContentPresenter"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
win:AutomationProperties.AccessibilityView="Raw"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}"
Foreground="{TemplateBinding Foreground}" />
<ContentControl x:Name="ExpandCollapseChevronBorder"
Grid.Column="1"
Width="{StaticResource SettingsExpanderChevronButtonWidth}"
Height="{StaticResource SettingsExpanderChevronButtonHeight}"
Margin="0,0,8,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Background="{ThemeResource ExpanderChevronBackground}"
BorderBrush="{ThemeResource ExpanderChevronBorderBrush}"
BorderThickness="{ThemeResource ExpanderChevronBorderThickness}"
CornerRadius="{ThemeResource ControlCornerRadius}"
FocusVisualMargin="-3"
IsTabStop="False"
ToolTipService.ToolTip="{StaticResource SettingsExpanderChevronToolTip}"
UseSystemFocusVisuals="True">
<muxc:AnimatedIcon x:Name="ExpandCollapseChevron"
Width="16"
Height="16"
HorizontalAlignment="Center"
VerticalAlignment="Center"
muxc:AnimatedIcon.State="NormalOff"
win:AutomationProperties.AccessibilityView="Raw"
Foreground="{ThemeResource ExpanderChevronForeground}"
RenderTransformOrigin="0.5, 0.5">
<animatedvisuals:AnimatedChevronUpDownSmallVisualSource />
<muxc:AnimatedIcon.FallbackIconSource>
<muxc:FontIconSource FontFamily="{StaticResource SymbolThemeFontFamily}"
FontSize="16"
Glyph="{StaticResource ExpanderChevronDownGlyph}"
IsTextScaleFactorEnabled="False" />
</muxc:AnimatedIcon.FallbackIconSource>
</muxc:AnimatedIcon>
</ContentControl>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -1,67 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Text;
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// AutomationPeer for SettingsExpander
/// </summary>
public class SettingsExpanderAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="SettingsExpander"/> class.
/// </summary>
/// <param name="owner">SettingsExpander</param>
public SettingsExpanderAutomationPeer(SettingsExpander owner)
: base(owner)
{
}
/// <summary>
/// Gets the control type for the element that is associated with the UI Automation peer.
/// </summary>
/// <returns>The control type.</returns>
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Group;
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
string classNameCore = Owner.GetType().Name;
#if DEBUG_AUTOMATION
System.Diagnostics.Debug.WriteLine("SettingsCardAutomationPeer.GetClassNameCore returns " + classNameCore);
#endif
return classNameCore;
}
/// <summary>
/// Raises the property changed event for this AutomationPeer for the provided identifier.
/// Narrator does not announce this due to: https://github.com/microsoft/microsoft-ui-xaml/issues/3469
/// </summary>
/// <param name="newValue">New Expanded state</param>
public void RaiseExpandedChangedEvent(bool newValue)
{
ExpandCollapseState newState = (newValue == true) ?
ExpandCollapseState.Expanded :
ExpandCollapseState.Collapsed;
ExpandCollapseState oldState = (newState == ExpandCollapseState.Expanded) ?
ExpandCollapseState.Collapsed :
ExpandCollapseState.Expanded;
#if !HAS_UNO
RaisePropertyChangedEvent(ExpandCollapsePatternIdentifiers.ExpandCollapseStateProperty, oldState, newState);
#endif
}
}

Просмотреть файл

@ -1,43 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// <see cref="StyleSelector"/> used by <see cref="SettingsExpander"/> to choose the proper <see cref="SettingsCard"/> container style (clickable or not).
/// </summary>
public class SettingsExpanderItemStyleSelector : StyleSelector
{
/// <summary>
/// Gets or sets the default <see cref="Style"/>.
/// </summary>
public Style DefaultStyle { get; set; }
/// <summary>
/// Gets or sets the <see cref="Style"/> when clickable.
/// </summary>
public Style ClickableStyle { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="SettingsExpanderItemStyleSelector"/> class.
/// </summary>
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
public SettingsExpanderItemStyleSelector()
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
}
/// <inheritdoc/>
protected override Style SelectStyleCore(object item, DependencyObject container)
{
if (container is SettingsCard card && card.IsClickEnabled)
{
return ClickableStyle;
}
else
{
return DefaultStyle;
}
}
}

Просмотреть файл

@ -1,9 +0,0 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:labs="using:CommunityToolkit.Labs.WinUI">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.Labs.WinUI.SettingsControls/SettingsCard/SettingsCard.xaml" />
<ResourceDictionary Source="ms-appx:///CommunityToolkit.Labs.WinUI.SettingsControls/SettingsExpander/SettingsExpander.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

Просмотреть файл

@ -1,133 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Labs.WinUI;
using CommunityToolkit.Tooling.TestGen;
using CommunityToolkit.Tests;
namespace SettingsControlsExperiment.Tests;
[TestClass]
public partial class ExampleSettingsControlsTestClass : VisualUITestBase
{
// If you don't need access to UI objects directly or async code, use this pattern.
[TestMethod]
public void SimpleSynchronousExampleTest()
{
var assembly = typeof(SettingsCard).Assembly;
var type = assembly.GetType(typeof(SettingsCard).FullName ?? string.Empty);
Assert.IsNotNull(type, "Could not find SettingsCard type.");
Assert.AreEqual(typeof(SettingsCard), type, "Type of SettingsCard does not match expected type.");
}
// If you don't need access to UI objects directly, use this pattern.
[TestMethod]
public async Task SimpleAsyncExampleTest()
{
await Task.Delay(250);
Assert.IsTrue(true);
}
// Example that shows how to check for exception throwing.
[TestMethod]
public void SimpleExceptionCheckTest()
{
// If you need to check exceptions occur for invalid inputs, etc...
// Use Assert.ThrowsException to limit the scope to where you expect the error to occur.
// Otherwise, using the ExpectedException attribute could swallow or
// catch other issues in setup code.
Assert.ThrowsException<NotImplementedException>(() => throw new NotImplementedException());
}
// The UIThreadTestMethod automatically dispatches to the UI for us to work with UI objects.
[UIThreadTestMethod]
public void SimpleUIAttributeExampleTest()
{
var component = new SettingsCard();
Assert.IsNotNull(component);
}
// The UIThreadTestMethod can also easily grab a XAML Page for us by passing its type as a parameter.
// This lets us actually test a control as it would behave within an actual application.
// The page will already be loaded by the time your test is called.
[UIThreadTestMethod]
public void SimpleUIExamplePageTest(ExampleSettingsControlsTestPage page)
{
// You can use the Toolkit Visual Tree helpers here to find the component by type or name:
//var component = page.FindDescendant<SettingsCard>();
//Assert.IsNotNull(component);
var componentByName = page.FindDescendant("SettingsControlsControl");
Assert.IsNotNull(componentByName);
}
// You can still do async work with a UIThreadTestMethod as well.
[UIThreadTestMethod]
public async Task SimpleAsyncUIExamplePageTest(ExampleSettingsControlsTestPage page)
{
// This helper can be used to wait for a rendering pass to complete.
await CompositionTargetHelper.ExecuteAfterCompositionRenderingAsync(() => { });
var component = page.FindDescendant<SettingsCard>();
Assert.IsNotNull(component);
}
//// ----------------------------- ADVANCED TEST SCENARIOS -----------------------------
// If you need to use DataRow, you can use this pattern with the UI dispatch still.
// Otherwise, checkout the UIThreadTestMethod attribute above.
// See https://github.com/CommunityToolkit/Labs-Windows/issues/186
[TestMethod]
public async Task ComplexAsyncUIExampleTest()
{
await EnqueueAsync(() =>
{
var component = new SettingsCard();
Assert.IsNotNull(component);
});
}
// If you want to load other content not within a XAML page using the UIThreadTestMethod above.
// Then you can do that using the Load/UnloadTestContentAsync methods.
[TestMethod]
public async Task ComplexAsyncLoadUIExampleTest()
{
await EnqueueAsync(async () =>
{
var component = new SettingsCard();
Assert.IsNotNull(component);
Assert.IsFalse(component.IsLoaded);
await LoadTestContentAsync(component);
Assert.IsTrue(component.IsLoaded);
await UnloadTestContentAsync(component);
Assert.IsFalse(component.IsLoaded);
});
}
// You can still use the UIThreadTestMethod to remove the extra layer for the dispatcher as well:
[UIThreadTestMethod]
public async Task ComplexAsyncLoadUIExampleWithoutDispatcherTest()
{
var component = new SettingsCard();
Assert.IsNotNull(component);
Assert.IsFalse(component.IsLoaded);
await LoadTestContentAsync(component);
Assert.IsTrue(component.IsLoaded);
await UnloadTestContentAsync(component);
Assert.IsFalse(component.IsLoaded);
}
}

Просмотреть файл

@ -1,14 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SettingsControlsExperiment.Tests.ExampleSettingsControlsTestPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:labs="using:CommunityToolkit.Labs.WinUI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
mc:Ignorable="d">
<Grid>
<labs:SettingsCard x:Name="SettingsControlsControl" />
</Grid>
</Page>

Просмотреть файл

@ -1,16 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SettingsControlsExperiment.Tests;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class ExampleSettingsControlsTestPage : Page
{
public ExampleSettingsControlsTestPage()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>D5E2CD55-53B4-49F8-8C2C-0CE2D0DF8457</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>SettingsControlsExperiment.Tests</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)ExampleSettingsControlsTestClass.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ExampleSettingsControlsTestPage.xaml.cs">
<DependentUpon>ExampleSettingsControlsTestPage.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="$(MSBuildThisFileDirectory)ExampleSettingsControlsTestPage.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>D5E2CD55-53B4-49F8-8C2C-0CE2D0DF8457</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="SettingsControls.Tests.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>

Просмотреть файл

@ -1,3 +0,0 @@
@ECHO OFF
powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.6 KiB

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 1.9 KiB

Двоичные данные
components/SizerBase/samples/Assets/Sizers.png

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 2.9 KiB

Просмотреть файл

@ -1,25 +0,0 @@
---
title: ContentSizer
author: mhawker
description: The ContentSizer is a control which can be used to resize any element, usually its parent.
keywords: ContentSizer, SizerBase, Control, Layout, Expander, Splitter
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 96
issue-id: 101
icon: Assets/ContentSizer.png
---
**If you are using a `Grid`, use [GridSplitter](GridSplitter.md) instead.**
The main use-case for a ContentSizer is to create an expandable shelf for your application. This allows the `Expander` itself to remember its opening/closing sizes.
A GridSplitter would be insufficient as it would force the grid to remember the row size and maintain its position when the `Expander` collapses.
> [!SAMPLE ContentSizerTopShelfPage]
The following example shows how to use the ContentSizer to create a left-side shelf; however, this scenario can also be accomplished with a `GridSplitter`.
> [!SAMPLE ContentSizerLeftShelfPage]

Просмотреть файл

@ -1,32 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SizerBaseExperiment.Samples.ContentSizerLeftShelfPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid MinWidth="400"
MinHeight="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- Left-side 'Shelf', In this case you could also use a GridSplitter -->
<Border x:Name="SideContent"
MinWidth="200"
MaxWidth="600"
Background="{ThemeResource AccentFillColorDefaultBrush}">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}"
Style="{ThemeResource BodyStrongTextBlockStyle}"
Text="Side Content" />
</Border>
<controls:ContentSizer Grid.Column="1"
TargetControl="{x:Bind SideContent}" />
</Grid>
</Page>

Просмотреть файл

@ -1,14 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SizerBaseExperiment.Samples;
[ToolkitSample(id: nameof(ContentSizerLeftShelfPage), "Left-side Shelf", description: "Shows how to create an expandable shelf on the left-side of your app.")]
public sealed partial class ContentSizerLeftShelfPage : Page
{
public ContentSizerLeftShelfPage()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,43 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SizerBaseExperiment.Samples.ContentSizerTopShelfPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<Grid MinHeight="300">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- Bottom 'Shelf', In this case you cannot use GridSplitter as row would maintain its size when Expander gets collapsed -->
<muxc:Expander x:Name="TopExpander"
VerticalAlignment="Top"
HorizontalContentAlignment="Stretch"
ExpandDirection="Up"
Header="This is some Shelf"
IsExpanded="True">
<Grid x:Name="ExpandContent"
Height="128"
MinHeight="32"
MaxHeight="256">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="This is the expanded content"
TextWrapping="Wrap" />
</Grid>
</muxc:Expander>
<!-- We expand the inner content size here so that Expander maintains it's size properly. -->
<controls:ContentSizer Grid.Row="1"
Height="16"
VerticalAlignment="Top"
Orientation="Horizontal"
TargetControl="{x:Bind ExpandContent}"
Visibility="{x:Bind TopExpander.IsExpanded, Mode=OneWay}" />
</Grid>
</Page>

Просмотреть файл

@ -1,14 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SizerBaseExperiment.Samples;
[ToolkitSample(id: nameof(ContentSizerTopShelfPage), "Top Shelf", description: "Shows how to create an expandable shelf on the top of your app.")]
public sealed partial class ContentSizerTopShelfPage : Page
{
public ContentSizerTopShelfPage()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,31 +0,0 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>
<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>
<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>
<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>

Просмотреть файл

@ -1,20 +0,0 @@
---
title: GridSplitter
author: mhawker
description: The GridSplitter control provides an easy-to-use Splitter that redistributes space between columns or rows of a Grid Control.
keywords: ContentSizer, SizerBase, Control, Layout, Expander
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 96
issue-id: 101
icon: Assets/GridSplitter.png
---
The control automatically detects the targeted columns/rows to resize, while dragging the control it starts to resize the columns/rows and redistributes space between columns/rows,
you can manually specify the `ResizeDirection` (`Auto` / `Column` / `Row`) and the `ResizeBehavior` to select which columns/rows to resize.
`GridSplitter` control will resize the targeted rows or columns
> [!SAMPLE GridSplitterPage]

Просмотреть файл

@ -1,106 +0,0 @@
<Page x:Class="SizerBaseExperiment.Samples.GridSplitterPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<Style TargetType="Border">
<Setter Property="BorderThickness" Value="1,1,0,0" />
<Setter Property="Padding" Value="16" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlHighlightChromeHighBrush}" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Page.Resources>
<Grid x:Name="RootGrid"
Height="300"
VerticalAlignment="Top"
BorderBrush="{ThemeResource SystemControlHighlightChromeHighBrush}"
BorderThickness="0,0,1,1">
<Grid.RowDefinitions>
<RowDefinition MinHeight="100"
MaxHeight="300" />
<RowDefinition Height="200" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="100"
MaxWidth="300" />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup>
<VisualState x:Name="Full">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="600" />
</VisualState.StateTriggers>
</VisualState>
<VisualState x:Name="Small">
<VisualState.StateTriggers>
<AdaptiveTrigger MinWindowWidth="0" />
</VisualState.StateTriggers>
<VisualState.Setters>
<Setter Target="RootGrid.Padding" Value="12" />
<Setter Target="RootGrid.FontSize" Value="12" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Grid.Row="0"
Grid.Column="0">
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect RowDefinition MinHeight='100'" />
</Border>
<Border Grid.Row="0"
Grid.Column="1">
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
</Border>
<Border Grid.Row="0"
Grid.Column="2">
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
</Border>
<Border Grid.Row="1"
Grid.Column="0">
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
</Border>
<Border Grid.Row="1"
Grid.Column="1">
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
</Border>
<Border Grid.Row="1"
Grid.Column="2">
<TextBlock Text="This text to simulate the resizing feature of the Grid Splitter Control, try to move the splitter to see the effect" />
</Border>
<!-- Column Grid Splitter -->
<controls:GridSplitter Grid.Column="1"
Width="16"
HorizontalAlignment="Left"
ResizeBehavior="BasedOnAlignment"
ResizeDirection="Auto">
<controls:GridSplitter.RenderTransform>
<TranslateTransform X="-8" />
</controls:GridSplitter.RenderTransform>
</controls:GridSplitter>
<!-- Row Grid Splitter -->
<controls:GridSplitter Grid.Row="1"
Grid.ColumnSpan="3"
Height="16"
VerticalAlignment="Top">
<controls:GridSplitter.RenderTransform>
<TranslateTransform Y="-8" />
</controls:GridSplitter.RenderTransform>
</controls:GridSplitter>
</Grid>
</Page>

Просмотреть файл

@ -1,17 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SizerBaseExperiment.Samples;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
[ToolkitSample(id: nameof(GridSplitterPage), "GridSplitter Example", description: "Splitter that redistributes space between columns or rows of a Grid Control")]
public sealed partial class GridSplitterPage : Page
{
public GridSplitterPage()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,23 +0,0 @@
---
title: PropertySizer
author: mhawker
description: The PropertySizer is a control which can be used to manipulate the value of another double based property.
keywords: PropertySizer, SizerBase, Control, Layout, NavigationView, Splitter
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 96
issue-id: 101
icon: Assets/PropertySizer.png
---
**If you are using a `Grid`, use `GridSplitter` instead.**
## Examples
The main use-case is for `PropertySizer` to allow you to manipulate the `OpenPaneLength` property of a `NavigationView` control to create a user customizable size shelf. This is handy when using `NavigationView` with a tree of items that represents some project or folder structure for your application.
Both `GridSplitter` and `ContentSizer` are insufficient as they would force the `NavigationView` to a specific size and not allow it to remember its size when it expands or collapses.
> [!SAMPLE PropertySizerNavigationViewPage]

Просмотреть файл

@ -1,72 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SizerBaseExperiment.Samples.PropertySizerNavigationViewPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<muxc:NavigationView x:Name="ViewPanel"
Width="500"
MinHeight="300"
HorizontalAlignment="Left"
IsPaneOpen="True"
OpenPaneLength="300"
PaneDisplayMode="Left">
<muxc:NavigationView.AutoSuggestBox>
<AutoSuggestBox AutomationProperties.Name="Search"
QueryIcon="Find" />
</muxc:NavigationView.AutoSuggestBox>
<muxc:NavigationView.MenuItems>
<muxc:NavigationViewItem Content="Menu Item1"
Tag="SamplePage1">
<muxc:NavigationViewItem.Icon>
<SymbolIcon Symbol="Play" />
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>
<muxc:NavigationViewItem Content="Menu Item2"
Tag="SamplePage2">
<muxc:NavigationViewItem.Icon>
<SymbolIcon Symbol="Save" />
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>
<muxc:NavigationViewItem Content="Menu Item3 with Really Long Name and Such..."
Tag="SamplePage3">
<muxc:NavigationViewItem.Icon>
<SymbolIcon Symbol="Refresh" />
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>
<muxc:NavigationViewItem Content="Menu Item4"
Tag="SamplePage4">
<muxc:NavigationViewItem.Icon>
<SymbolIcon Symbol="Download" />
</muxc:NavigationViewItem.Icon>
</muxc:NavigationViewItem>
</muxc:NavigationView.MenuItems>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Note the use of a TwoWay binding here, this is required for this control to work. -->
<controls:PropertySizer HorizontalAlignment="Left"
Binding="{x:Bind ViewPanel.OpenPaneLength, Mode=TwoWay}"
Maximum="440"
Minimum="52"
Visibility="{x:Bind ViewPanel.IsPaneOpen, Mode=OneWay}" />
<!--In An Application, put your host frame here: <Frame Grid.Column="1"/>-->
<!-- Here we show the content as a border for a visual aid -->
<Border Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Background="{ThemeResource AccentFillColorDefaultBrush}">
<TextBlock HorizontalAlignment="Center"
VerticalAlignment="Center"
Foreground="{ThemeResource TextOnAccentFillColorPrimaryBrush}"
Text="{x:Bind ViewPanel.OpenPaneLength, Mode=OneWay}" />
</Border>
</Grid>
</muxc:NavigationView>
</Page>

Просмотреть файл

@ -1,14 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SizerBaseExperiment.Samples;
[ToolkitSample(id: nameof(PropertySizerNavigationViewPage), "NavigationView Shelf", description: "Shows how to create an expandable shelf using a NavigationView and PropertySizer.")]
public sealed partial class PropertySizerNavigationViewPage : Page
{
public PropertySizerNavigationViewPage()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,8 +0,0 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>SizerBase</ToolkitComponentName>
</PropertyGroup>
<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
</Project>

Просмотреть файл

@ -1,29 +0,0 @@
---
title: Sizer Controls
author: mhawker
description: The Sizer controls allow users to resize various parts of your UI easily in a consistent fashion.
keywords: GridSplitter, ContentSizer, PropertySizer, SizerBase, Control, Layout, Expander, Grid, Splitter
dev_langs:
- csharp
category: Controls
subcategory: Layout
discussion-id: 96
issue-id: 101
icon: Assets/Sizers.png
---
The Sizer controls consist of the following:
- GridSplitter
- ContentSizer
- PropertySizer
They each provide an ability for your users to manipulate different parts of your UI experiences.
This document provides information about common settings you can set on any of these controls.
## Custom Mouse Cursor
You may want to change the cursor that is shown when hovering over your element like this:
> [!SAMPLE SizerCursorPage]

Просмотреть файл

@ -1,26 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SizerBaseExperiment.Samples.SizerCursorPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid MinWidth="400"
MinHeight="300">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border x:Name="SomeContent"
MinWidth="200"
MaxWidth="600"
Background="{ThemeResource AccentFillColorDefaultBrush}" />
<controls:ContentSizer Grid.Column="1"
Cursor="Hand"
TargetControl="{x:Bind SomeContent}" />
</Grid>
</Page>

Просмотреть файл

@ -1,14 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SizerBaseExperiment.Samples;
[ToolkitSample(id: nameof(SizerCursorPage), "Custom Mouse Cursor", description: "Shows how to change the cursor of a Sizer control.")]
public sealed partial class SizerCursorPage : Page
{
public SizerCursorPage()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,13 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.CompilerServices;
// These `InternalsVisibleTo` calls are intended to make it easier for
// for any internal code to be testable in all the different test projects
// used with the Labs infrastructure.
[assembly: InternalsVisibleTo("SizerBase.Tests.Uwp")]
[assembly: InternalsVisibleTo("SizerBase.Tests.WinAppSdk")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.Uwp")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.WinAppSdk")]

Просмотреть файл

@ -1,13 +0,0 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>SizerBase</ToolkitComponentName>
<Description>This package contains SizerBase.</Description>
<Version>0.0.4</Version>
<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.Labs.WinUI.SizerBaseRns</RootNamespace>
</PropertyGroup>
<!-- Sets this up as a toolkit component's source project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" />
</Project>

Просмотреть файл

@ -1,74 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Labs.WinUI.SizerBaseLocal;
namespace CommunityToolkit.Labs.WinUI;
// Events for ContentSizer.
public partial class ContentSizer
{
/// <inheritdoc/>
protected override void OnLoaded(RoutedEventArgs e)
{
if (TargetControl == null)
{
TargetControl = this.FindAscendant<FrameworkElement>();
}
}
private double _currentSize;
/// <inheritdoc/>
protected override void OnDragStarting()
{
if (TargetControl != null)
{
_currentSize =
Orientation == Orientation.Vertical ?
TargetControl.ActualWidth :
TargetControl.ActualHeight;
}
}
/// <inheritdoc/>
protected override bool OnDragHorizontal(double horizontalChange)
{
if (TargetControl == null)
{
return true;
}
horizontalChange = IsDragInverted ? -horizontalChange : horizontalChange;
if (!IsValidWidth(TargetControl, _currentSize + horizontalChange, ActualWidth))
{
return false;
}
TargetControl.Width = _currentSize + horizontalChange;
return true;
}
/// <inheritdoc/>
protected override bool OnDragVertical(double verticalChange)
{
if (TargetControl == null)
{
return false;
}
verticalChange = IsDragInverted ? -verticalChange : verticalChange;
if (!IsValidHeight(TargetControl, _currentSize + verticalChange, ActualHeight))
{
return false;
}
TargetControl.Height = _currentSize + verticalChange;
return true;
}
}

Просмотреть файл

@ -1,62 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
// Properties for ContentSizer.
public partial class ContentSizer
{
/// <summary>
/// Gets or sets a value indicating whether the <see cref="ContentSizer"/> control is resizing in the opposite direction.
/// </summary>
public bool IsDragInverted
{
get { return (bool)GetValue(IsDragInvertedProperty); }
set { SetValue(IsDragInvertedProperty, value); }
}
/// <summary>
/// Identifies the <see cref="IsDragInverted"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsDragInvertedProperty =
DependencyProperty.Register(nameof(IsDragInverted), typeof(bool), typeof(ContentSizer), new PropertyMetadata(false));
/// <summary>
/// Gets or sets the control that the <see cref="ContentSizer"/> is resizing. Be default, this will be the visual ancestor of the <see cref="ContentSizer"/>.
/// </summary>
public FrameworkElement? TargetControl
{
get { return (FrameworkElement?)GetValue(TargetControlProperty); }
set { SetValue(TargetControlProperty, value); }
}
/// <summary>
/// Identifies the <see cref="TargetControl"/> dependency property.
/// </summary>
public static readonly DependencyProperty TargetControlProperty =
DependencyProperty.Register(nameof(TargetControl), typeof(FrameworkElement), typeof(ContentSizer), new PropertyMetadata(null, OnTargetControlChanged));
private static void OnTargetControlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// TODO: Should we do this after the TargetControl is Loaded? (And use ActualWidth?)
// Or should we just do it in the manipulation event if Width is null?
// Check if our width can be manipulated
if (d is SizerBase splitterBase && e.NewValue is FrameworkElement element)
{
// TODO: For Auto ResizeDirection we might want to do detection logic (TBD) here first?
if (splitterBase.Orientation != Orientation.Horizontal && double.IsNaN(element.Width))
{
// We need to set the Width or Height somewhere,
// as if it's NaN we won't be able to manipulate it.
element.Width = element.DesiredSize.Width;
}
if (splitterBase.Orientation != Orientation.Vertical && double.IsNaN(element.Height))
{
element.Height = element.DesiredSize.Height;
}
}
}
}

Просмотреть файл

@ -1,12 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// The <see cref="ContentSizer"/> is a control which can be used to resize any element, usually its parent. If you are using a <see cref="Grid"/>, use <see cref="GridSplitter"/> instead.
/// </summary>
public partial class ContentSizer : SizerBase
{
}

Просмотреть файл

@ -1,31 +0,0 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.
MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.
For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>
<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>
<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>
<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>

Просмотреть файл

@ -1,56 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
public partial class GridSplitter
{
/// <summary>
/// Enum to indicate whether GridSplitter resizes Columns or Rows
/// </summary>
public enum GridResizeDirection
{
/// <summary>
/// Determines whether to resize rows or columns based on its Alignment and
/// width compared to height
/// </summary>
Auto,
/// <summary>
/// Resize columns when dragging Splitter.
/// </summary>
Columns,
/// <summary>
/// Resize rows when dragging Splitter.
/// </summary>
Rows
}
/// <summary>
/// Enum to indicate what Columns or Rows the GridSplitter resizes
/// </summary>
public enum GridResizeBehavior
{
/// <summary>
/// Determine which columns or rows to resize based on its Alignment.
/// </summary>
BasedOnAlignment,
/// <summary>
/// Resize the current and next Columns or Rows.
/// </summary>
CurrentAndNext,
/// <summary>
/// Resize the previous and current Columns or Rows.
/// </summary>
PreviousAndCurrent,
/// <summary>
/// Resize the previous and next Columns or Rows.
/// </summary>
PreviousAndNext
}
}

Просмотреть файл

@ -1,169 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
public partial class GridSplitter
{
/// <inheritdoc/>
protected override void OnLoaded(RoutedEventArgs e)
{
_resizeDirection = GetResizeDirection();
Orientation = _resizeDirection == GridResizeDirection.Rows ?
Orientation.Horizontal : Orientation.Vertical;
_resizeBehavior = GetResizeBehavior();
}
private double _currentSize;
private double _siblingSize;
/// <inheritdoc />
protected override void OnDragStarting()
{
_resizeDirection = GetResizeDirection();
Orientation = _resizeDirection == GridResizeDirection.Rows ?
Orientation.Horizontal : Orientation.Vertical;
_resizeBehavior = GetResizeBehavior();
// Record starting points
if (Orientation == Orientation.Horizontal)
{
_currentSize = CurrentRow?.ActualHeight ?? -1;
_siblingSize = SiblingRow?.ActualHeight ?? -1;
}
else
{
_currentSize = CurrentColumn?.ActualWidth ?? -1;
_siblingSize = SiblingColumn?.ActualWidth ?? -1;
}
}
/// <inheritdoc/>
protected override bool OnDragVertical(double verticalChange)
{
if (CurrentRow == null || SiblingRow == null || Resizable == null)
{
return false;
}
var currentChange = _currentSize + verticalChange;
var siblingChange = _siblingSize + (verticalChange * -1); // sibling moves opposite
// if current row has fixed height then resize it
if (!IsStarRow(CurrentRow))
{
// No need to check for the row Min height because it is automatically respected
return SetRowHeight(CurrentRow, currentChange, GridUnitType.Pixel);
}
// if sibling row has fixed width then resize it
else if (!IsStarRow(SiblingRow))
{
// Would adding to this column make the current column violate the MinWidth?
if (IsValidRowHeight(CurrentRow, currentChange) == false)
{
return false;
}
return SetRowHeight(SiblingRow, siblingChange, GridUnitType.Pixel);
}
// if both row haven't fixed height (auto *)
else
{
// change current row height to the new height with respecting the auto
// change sibling row height to the new height relative to current row
// respect the other star row height by setting it's height to it's actual height with stars
// We need to validate current and sibling height to not cause any unexpected behavior
if (!IsValidRowHeight(CurrentRow, currentChange) ||
!IsValidRowHeight(SiblingRow, siblingChange))
{
return false;
}
foreach (var rowDefinition in Resizable.RowDefinitions)
{
if (rowDefinition == CurrentRow)
{
SetRowHeight(CurrentRow, currentChange, GridUnitType.Star);
}
else if (rowDefinition == SiblingRow)
{
SetRowHeight(SiblingRow, siblingChange, GridUnitType.Star);
}
else if (IsStarRow(rowDefinition))
{
rowDefinition.Height = new GridLength(rowDefinition.ActualHeight, GridUnitType.Star);
}
}
return true;
}
}
/// <inheritdoc/>
protected override bool OnDragHorizontal(double horizontalChange)
{
if (CurrentColumn == null || SiblingColumn == null || Resizable == null)
{
return false;
}
var currentChange = _currentSize + horizontalChange;
var siblingChange = _siblingSize + (horizontalChange * -1); // sibling moves opposite
// if current column has fixed width then resize it
if (!IsStarColumn(CurrentColumn))
{
// No need to check for the Column Min width because it is automatically respected
return SetColumnWidth(CurrentColumn, currentChange, GridUnitType.Pixel);
}
// if sibling column has fixed width then resize it
else if (!IsStarColumn(SiblingColumn))
{
// Would adding to this column make the current column violate the MinWidth?
if (IsValidColumnWidth(CurrentColumn, currentChange) == false)
{
return false;
}
return SetColumnWidth(SiblingColumn, siblingChange, GridUnitType.Pixel);
}
// if both column haven't fixed width (auto *)
else
{
// change current column width to the new width with respecting the auto
// change sibling column width to the new width relative to current column
// respect the other star column width by setting it's width to it's actual width with stars
// We need to validate current and sibling width to not cause any unexpected behavior
if (!IsValidColumnWidth(CurrentColumn, currentChange) ||
!IsValidColumnWidth(SiblingColumn, siblingChange))
{
return false;
}
foreach (var columnDefinition in Resizable.ColumnDefinitions)
{
if (columnDefinition == CurrentColumn)
{
SetColumnWidth(CurrentColumn, currentChange, GridUnitType.Star);
}
else if (columnDefinition == SiblingColumn)
{
SetColumnWidth(SiblingColumn, siblingChange, GridUnitType.Star);
}
else if (IsStarColumn(columnDefinition))
{
columnDefinition.Width = new GridLength(columnDefinition.ActualWidth, GridUnitType.Star);
}
}
return true;
}
}
}

Просмотреть файл

@ -1,245 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
public partial class GridSplitter
{
private static bool IsStarColumn(ColumnDefinition definition)
{
return ((GridLength)definition.GetValue(ColumnDefinition.WidthProperty)).IsStar;
}
private static bool IsStarRow(RowDefinition definition)
{
return ((GridLength)definition.GetValue(RowDefinition.HeightProperty)).IsStar;
}
private bool SetColumnWidth(ColumnDefinition columnDefinition, double newWidth, GridUnitType unitType)
{
var minWidth = columnDefinition.MinWidth;
if (!double.IsNaN(minWidth) && newWidth < minWidth)
{
newWidth = minWidth;
}
var maxWidth = columnDefinition.MaxWidth;
if (!double.IsNaN(maxWidth) && newWidth > maxWidth)
{
newWidth = maxWidth;
}
if (newWidth > ActualWidth)
{
columnDefinition.Width = new GridLength(newWidth, unitType);
return true;
}
return false;
}
private bool IsValidColumnWidth(ColumnDefinition columnDefinition, double newWidth)
{
var minWidth = columnDefinition.MinWidth;
if (!double.IsNaN(minWidth) && newWidth < minWidth)
{
return false;
}
var maxWidth = columnDefinition.MaxWidth;
if (!double.IsNaN(maxWidth) && newWidth > maxWidth)
{
return false;
}
if (newWidth <= ActualWidth)
{
return false;
}
return true;
}
private bool SetRowHeight(RowDefinition rowDefinition, double newHeight, GridUnitType unitType)
{
var minHeight = rowDefinition.MinHeight;
if (!double.IsNaN(minHeight) && newHeight < minHeight)
{
newHeight = minHeight;
}
var maxWidth = rowDefinition.MaxHeight;
if (!double.IsNaN(maxWidth) && newHeight > maxWidth)
{
newHeight = maxWidth;
}
if (newHeight > ActualHeight)
{
rowDefinition.Height = new GridLength(newHeight, unitType);
return true;
}
return false;
}
private bool IsValidRowHeight(RowDefinition rowDefinition, double newHeight)
{
var minHeight = rowDefinition.MinHeight;
if (!double.IsNaN(minHeight) && newHeight < minHeight)
{
return false;
}
var maxHeight = rowDefinition.MaxHeight;
if (!double.IsNaN(maxHeight) && newHeight > maxHeight)
{
return false;
}
if (newHeight <= ActualHeight)
{
return false;
}
return true;
}
// Return the targeted Column based on the resize behavior
private int GetTargetedColumn()
{
var currentIndex = Grid.GetColumn(TargetControl);
return GetTargetIndex(currentIndex);
}
// Return the sibling Row based on the resize behavior
private int GetTargetedRow()
{
var currentIndex = Grid.GetRow(TargetControl);
return GetTargetIndex(currentIndex);
}
// Return the sibling Column based on the resize behavior
private int GetSiblingColumn()
{
var currentIndex = Grid.GetColumn(TargetControl);
return GetSiblingIndex(currentIndex);
}
// Return the sibling Row based on the resize behavior
private int GetSiblingRow()
{
var currentIndex = Grid.GetRow(TargetControl);
return GetSiblingIndex(currentIndex);
}
// Gets index based on resize behavior for first targeted row/column
private int GetTargetIndex(int currentIndex)
{
switch (_resizeBehavior)
{
case GridResizeBehavior.CurrentAndNext:
return currentIndex;
case GridResizeBehavior.PreviousAndNext:
return currentIndex - 1;
case GridResizeBehavior.PreviousAndCurrent:
return currentIndex - 1;
default:
return -1;
}
}
// Gets index based on resize behavior for second targeted row/column
private int GetSiblingIndex(int currentIndex)
{
switch (_resizeBehavior)
{
case GridResizeBehavior.CurrentAndNext:
return currentIndex + 1;
case GridResizeBehavior.PreviousAndNext:
return currentIndex + 1;
case GridResizeBehavior.PreviousAndCurrent:
return currentIndex;
default:
return -1;
}
}
// Checks the control alignment and Width/Height to detect the control resize direction columns/rows
private GridResizeDirection GetResizeDirection()
{
GridResizeDirection direction = ResizeDirection;
if (direction == GridResizeDirection.Auto)
{
// When HorizontalAlignment is Left, Right or Center, resize Columns
if (HorizontalAlignment != HorizontalAlignment.Stretch)
{
direction = GridResizeDirection.Columns;
}
// When VerticalAlignment is Top, Bottom or Center, resize Rows
else if (VerticalAlignment != VerticalAlignment.Stretch)
{
direction = GridResizeDirection.Rows;
}
// Check Width vs Height
else if (ActualWidth <= ActualHeight)
{
direction = GridResizeDirection.Columns;
}
else
{
direction = GridResizeDirection.Rows;
}
}
return direction;
}
// Get the resize behavior (Which columns/rows should be resized) based on alignment and Direction
private GridResizeBehavior GetResizeBehavior()
{
GridResizeBehavior resizeBehavior = ResizeBehavior;
if (resizeBehavior == GridResizeBehavior.BasedOnAlignment)
{
if (_resizeDirection == GridResizeDirection.Columns)
{
switch (HorizontalAlignment)
{
case HorizontalAlignment.Left:
resizeBehavior = GridResizeBehavior.PreviousAndCurrent;
break;
case HorizontalAlignment.Right:
resizeBehavior = GridResizeBehavior.CurrentAndNext;
break;
default:
resizeBehavior = GridResizeBehavior.PreviousAndNext;
break;
}
}
// resize direction is vertical
else
{
switch (VerticalAlignment)
{
case VerticalAlignment.Top:
resizeBehavior = GridResizeBehavior.PreviousAndCurrent;
break;
case VerticalAlignment.Bottom:
resizeBehavior = GridResizeBehavior.CurrentAndNext;
break;
default:
resizeBehavior = GridResizeBehavior.PreviousAndNext;
break;
}
}
}
return resizeBehavior;
}
}

Просмотреть файл

@ -1,78 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
public partial class GridSplitter
{
/// <summary>
/// Identifies the <see cref="ResizeDirection"/> dependency property.
/// </summary>
public static readonly DependencyProperty ResizeDirectionProperty
= DependencyProperty.Register(
nameof(ResizeDirection),
typeof(GridResizeDirection),
typeof(GridSplitter),
new PropertyMetadata(GridResizeDirection.Auto, OnResizeDirectionPropertyChanged));
private static void OnResizeDirectionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is GridSplitter splitter && e.NewValue is GridResizeDirection direction &&
direction != GridResizeDirection.Auto)
{
// Update base classes property based on specific polyfill for GridSplitter
splitter.Orientation =
direction == GridResizeDirection.Rows ?
Orientation.Horizontal :
Orientation.Vertical;
}
}
/// <summary>
/// Identifies the <see cref="ResizeBehavior"/> dependency property.
/// </summary>
public static readonly DependencyProperty ResizeBehaviorProperty
= DependencyProperty.Register(
nameof(ResizeBehavior),
typeof(GridResizeBehavior),
typeof(GridSplitter),
new PropertyMetadata(GridResizeBehavior.BasedOnAlignment));
/// <summary>
/// Identifies the <see cref="ParentLevel"/> dependency property.
/// </summary>
public static readonly DependencyProperty ParentLevelProperty
= DependencyProperty.Register(
nameof(ParentLevel),
typeof(int),
typeof(GridSplitter),
new PropertyMetadata(default(int)));
/// <summary>
/// Gets or sets whether the Splitter resizes the Columns, Rows, or Both.
/// </summary>
public GridResizeDirection ResizeDirection
{
get { return (GridResizeDirection)GetValue(ResizeDirectionProperty); }
set { SetValue(ResizeDirectionProperty, value); }
}
/// <summary>
/// Gets or sets which Columns or Rows the Splitter resizes.
/// </summary>
public GridResizeBehavior ResizeBehavior
{
get { return (GridResizeBehavior)GetValue(ResizeBehaviorProperty); }
set { SetValue(ResizeBehaviorProperty, value); }
}
/// <summary>
/// Gets or sets the level of the parent grid to resize
/// </summary>
public int ParentLevel
{
get { return (int)GetValue(ParentLevelProperty); }
set { SetValue(ParentLevelProperty, value); }
}
}

Просмотреть файл

@ -1,145 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// Represents the control that redistributes space between columns or rows of a Grid control.
/// </summary>
public partial class GridSplitter : SizerBase
{
private GridResizeDirection _resizeDirection;
private GridResizeBehavior _resizeBehavior;
/// <summary>
/// Gets the target parent grid from level
/// </summary>
private FrameworkElement? TargetControl
{
get
{
if (ParentLevel == 0)
{
return this;
}
// TODO: Can we just use our Visual/Logical Tree extensions for this?
var parent = Parent;
for (int i = 2; i < ParentLevel; i++) // TODO: Why is this 2? We need better documentation on ParentLevel
{
if (parent is FrameworkElement frameworkElement)
{
parent = frameworkElement.Parent;
}
else
{
break;
}
}
return parent as FrameworkElement;
}
}
/// <summary>
/// Gets GridSplitter Container Grid
/// </summary>
private Grid? Resizable => TargetControl?.Parent as Grid;
/// <summary>
/// Gets the current Column definition of the parent Grid
/// </summary>
private ColumnDefinition? CurrentColumn
{
get
{
if (Resizable == null)
{
return null;
}
var gridSplitterTargetedColumnIndex = GetTargetedColumn();
if ((gridSplitterTargetedColumnIndex >= 0)
&& (gridSplitterTargetedColumnIndex < Resizable.ColumnDefinitions.Count))
{
return Resizable.ColumnDefinitions[gridSplitterTargetedColumnIndex];
}
return null;
}
}
/// <summary>
/// Gets the Sibling Column definition of the parent Grid
/// </summary>
private ColumnDefinition? SiblingColumn
{
get
{
if (Resizable == null)
{
return null;
}
var gridSplitterSiblingColumnIndex = GetSiblingColumn();
if ((gridSplitterSiblingColumnIndex >= 0)
&& (gridSplitterSiblingColumnIndex < Resizable.ColumnDefinitions.Count))
{
return Resizable.ColumnDefinitions[gridSplitterSiblingColumnIndex];
}
return null;
}
}
/// <summary>
/// Gets the current Row definition of the parent Grid
/// </summary>
private RowDefinition? CurrentRow
{
get
{
if (Resizable == null)
{
return null;
}
var gridSplitterTargetedRowIndex = GetTargetedRow();
if ((gridSplitterTargetedRowIndex >= 0)
&& (gridSplitterTargetedRowIndex < Resizable.RowDefinitions.Count))
{
return Resizable.RowDefinitions[gridSplitterTargetedRowIndex];
}
return null;
}
}
/// <summary>
/// Gets the Sibling Row definition of the parent Grid
/// </summary>
private RowDefinition? SiblingRow
{
get
{
if (Resizable == null)
{
return null;
}
var gridSplitterSiblingRowIndex = GetSiblingRow();
if ((gridSplitterSiblingRowIndex >= 0)
&& (gridSplitterSiblingRowIndex < Resizable.RowDefinitions.Count))
{
return Resizable.RowDefinitions[gridSplitterSiblingRowIndex];
}
return null;
}
}
}

Просмотреть файл

@ -1,66 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
// Events for PropertySizer.
public partial class PropertySizer
{
private double _currentSize;
/// <inheritdoc/>
protected override void OnDragStarting()
{
// We grab the current size of the bound value when we start a drag
// and we manipulate from that set point.
if (ReadLocalValue(BindingProperty) != DependencyProperty.UnsetValue)
{
_currentSize = Binding;
}
}
/// <inheritdoc/>
protected override bool OnDragHorizontal(double horizontalChange)
{
// We use a central function for both horizontal/vertical as
// a general property has no notion of direction when we
// manipulate it, so the logic is abstracted.
return ApplySizeChange(horizontalChange);
}
/// <inheritdoc/>
protected override bool OnDragVertical(double verticalChange)
{
return ApplySizeChange(verticalChange);
}
private bool ApplySizeChange(double newSize)
{
newSize = IsDragInverted ? -newSize : newSize;
// We want to be checking the modified final value for bounds checks.
newSize += _currentSize;
// Check if we hit the min/max value, as we should use that if we're on the edge
if (ReadLocalValue(MinimumProperty) != DependencyProperty.UnsetValue &&
newSize < Minimum)
{
// We use SetValue here as that'll update our bound property vs. overwriting the binding itself.
SetValue(BindingProperty, Minimum);
}
else if (ReadLocalValue(MaximumProperty) != DependencyProperty.UnsetValue &&
newSize > Maximum)
{
SetValue(BindingProperty, Maximum);
}
else
{
// Otherwise, we use the value provided.
SetValue(BindingProperty, newSize);
}
// We're always manipulating the value effectively.
return true;
}
}

Просмотреть файл

@ -1,75 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
// Properties for PropertySizer.
public partial class PropertySizer
{
/// <summary>
/// Gets or sets a value indicating whether the <see cref="PropertySizer"/> control is resizing in the opposite direction.
/// </summary>
public bool IsDragInverted
{
get { return (bool)GetValue(IsDragInvertedProperty); }
set { SetValue(IsDragInvertedProperty, value); }
}
/// <summary>
/// Identifies the <see cref="IsDragInverted"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsDragInvertedProperty =
DependencyProperty.Register(nameof(IsDragInverted), typeof(bool), typeof(PropertySizer), new PropertyMetadata(false));
/// <summary>
/// Gets or sets a two-way binding to a <c>double</c> value that the <see cref="PropertySizer"/> is manipulating.
/// </summary>
/// <remarks>
/// Note that the binding should be configured to be a <c>TwoWay</c> binding in order for the control to notify the source of the changed value.
/// </remarks>
/// <example>
/// &lt;controls:PropertySizer Binding="{Binding OpenPaneLength, ElementName=ViewPanel, Mode=TwoWay}"&gt;
/// </example>
public double Binding
{
get { return (double)GetValue(BindingProperty); }
set { SetValue(BindingProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Binding"/> dependency property.
/// </summary>
public static readonly DependencyProperty BindingProperty =
DependencyProperty.Register(nameof(Binding), typeof(double), typeof(PropertySizer), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the minimum allowed value for the <see cref="PropertySizer"/> to allow for the <see cref="Binding"/> value. Ignored if not provided.
/// </summary>
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Minimum"/> dependency property.
/// </summary>
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register(nameof(Minimum), typeof(double), typeof(PropertySizer), new PropertyMetadata(0));
/// <summary>
/// Gets or sets the maximum allowed value for the <see cref="PropertySizer"/> to allow for the <see cref="Binding"/> value. Ignored if not provided.
/// </summary>
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Maximum"/> dependency property.
/// </summary>
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(PropertySizer), new PropertyMetadata(0));
}

Просмотреть файл

@ -1,12 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// The <see cref="PropertySizer"/> is a control which can be used to manipulate the value of another <c>double</c> based property. For instance manipulating the <c>OpenPaneLength</c> of a <c>NavigationView</c> control. If you are using a <see cref="Grid"/>, use <see cref="GridSplitter"/> instead.
/// </summary>
public partial class PropertySizer : SizerBase
{
}

Просмотреть файл

@ -1,72 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI.Automation.Peers;
/// <summary>
/// Defines a framework element automation peer for the <see cref="SizerBase"/> controls.
/// </summary>
public class SizerAutomationPeer : FrameworkElementAutomationPeer
{
/// <summary>
/// Initializes a new instance of the <see cref="SizerAutomationPeer"/> class.
/// </summary>
/// <param name="owner">
/// The <see cref="SizerBase" /> that is associated with this <see cref="SizerAutomationPeer" />.
/// </param>
public SizerAutomationPeer(SizerBase owner)
: base(owner)
{
}
private SizerBase OwningSizer
{
get
{
return (Owner as SizerBase)!;
}
}
/// <summary>
/// Called by GetClassName that gets a human readable name that, in addition to AutomationControlType,
/// differentiates the control represented by this AutomationPeer.
/// </summary>
/// <returns>The string that contains the name.</returns>
protected override string GetClassNameCore()
{
return Owner.GetType().Name;
}
/// <summary>
/// Called by GetName.
/// </summary>
/// <returns>
/// Returns the first of these that is not null or empty:
/// - Value returned by the base implementation
/// - Name of the owning ContentSizer
/// - ContentSizer class name
/// </returns>
protected override string GetNameCore()
{
string name = AutomationProperties.GetName(this.OwningSizer);
if (!string.IsNullOrEmpty(name))
{
return name;
}
name = this.OwningSizer.Name;
if (!string.IsNullOrEmpty(name))
{
return name;
}
name = base.GetNameCore();
if (!string.IsNullOrEmpty(name))
{
return name;
}
return string.Empty;
}
}

Просмотреть файл

@ -1,178 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// Event implementations for <see cref="SizerBase"/>.
/// </summary>
public partial class SizerBase
{
/// <inheritdoc />
protected override void OnKeyDown(KeyRoutedEventArgs e)
{
// If we're manipulating with mouse/touch, we ignore keyboard inputs.
if (_dragging)
{
return;
}
//// TODO: Do we want Ctrl/Shift to be a small increment (kind of inverse to old GridSplitter logic)?
//// var ctrl = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
//// if (ctrl.HasFlag(CoreVirtualKeyStates.Down))
//// Note: WPF doesn't do anything here.
//// I think if we did anything, we'd create a SmallKeyboardIncrement property?
// Initialize a drag event for this keyboard interaction.
OnDragStarting();
if (Orientation == Orientation.Vertical)
{
var horizontalChange = KeyboardIncrement;
// Important: adjust for RTL language flow settings and invert horizontal axis
#if !HAS_UNO
if (this.FlowDirection == FlowDirection.RightToLeft)
{
horizontalChange *= -1;
}
#endif
if (e.Key == Windows.System.VirtualKey.Left)
{
OnDragHorizontal(-horizontalChange);
}
else if (e.Key == Windows.System.VirtualKey.Right)
{
OnDragHorizontal(horizontalChange);
}
}
else
{
if (e.Key == Windows.System.VirtualKey.Up)
{
OnDragVertical(-KeyboardIncrement);
}
else if (e.Key == Windows.System.VirtualKey.Down)
{
OnDragVertical(KeyboardIncrement);
}
}
}
/// <inheritdoc />
protected override void OnManipulationStarting(ManipulationStartingRoutedEventArgs e)
{
base.OnManipulationStarting(e);
OnDragStarting();
}
/// <inheritdoc />
protected override void OnManipulationDelta(ManipulationDeltaRoutedEventArgs e)
{
// We use Trancate here to provide 'snapping' points with the DragIncrement property
// It works for both our negative and positive values, as otherwise we'd need to use
// Ceiling when negative and Floor when positive to maintain the correct behavior.
var horizontalChange =
Math.Truncate(e.Cumulative.Translation.X / DragIncrement) * DragIncrement;
var verticalChange =
Math.Truncate(e.Cumulative.Translation.Y / DragIncrement) * DragIncrement;
// Important: adjust for RTL language flow settings and invert horizontal axis
#if !HAS_UNO
if (this.FlowDirection == FlowDirection.RightToLeft)
{
horizontalChange *= -1;
}
#endif
if (Orientation == Orientation.Vertical)
{
if (!OnDragHorizontal(horizontalChange))
{
return;
}
}
else if (Orientation == Orientation.Horizontal)
{
if (!OnDragVertical(verticalChange))
{
return;
}
}
base.OnManipulationDelta(e);
}
// private helper bools for Visual States
private bool _pressed = false;
private bool _dragging = false;
private bool _pointerEntered = false;
private void SizerBase_PointerReleased(object sender, PointerRoutedEventArgs e)
{
_pressed = false;
if (IsEnabled)
{
VisualStateManager.GoToState(this, _pointerEntered ? "PointerOver" : "Normal", true);
}
}
private void SizerBase_PointerPressed(object sender, PointerRoutedEventArgs e)
{
_pressed = true;
if (IsEnabled)
{
VisualStateManager.GoToState(this, "Pressed", true);
}
}
private void SizerBase_PointerExited(object sender, PointerRoutedEventArgs e)
{
_pointerEntered = false;
if (!_pressed && !_dragging && IsEnabled)
{
VisualStateManager.GoToState(this, "Normal", true);
}
}
private void SizerBase_PointerEntered(object sender, PointerRoutedEventArgs e)
{
_pointerEntered = true;
if (!_pressed && !_dragging && IsEnabled)
{
VisualStateManager.GoToState(this, "PointerOver", true);
}
}
private void SizerBase_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
_dragging = false;
_pressed = false;
VisualStateManager.GoToState(this, _pointerEntered ? "PointerOver" : "Normal", true);
}
private void SizerBase_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e)
{
_dragging = true;
VisualStateManager.GoToState(this, "Pressed", true);
}
private void SizerBase_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (!IsEnabled)
{
VisualStateManager.GoToState(this, "Disabled", true);
}
else
{
VisualStateManager.GoToState(this, _pointerEntered ? "PointerOver" : "Normal", true);
}
}
}

Просмотреть файл

@ -1,69 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// Protected helper methods for <see cref="SizerBase"/> and subclasses.
/// </summary>
public partial class SizerBase : Control
{
/// <summary>
/// Check for new requested vertical size is valid or not
/// </summary>
/// <param name="target">Target control being resized</param>
/// <param name="newHeight">The requested new height</param>
/// <param name="parentActualHeight">The parent control's ActualHeight</param>
/// <returns>Bool result if requested vertical change is valid or not</returns>
protected static bool IsValidHeight(FrameworkElement target, double newHeight, double parentActualHeight)
{
var minHeight = target.MinHeight;
if (newHeight < 0 || (!double.IsNaN(minHeight) && newHeight < minHeight))
{
return false;
}
var maxHeight = target.MaxHeight;
if (!double.IsNaN(maxHeight) && newHeight > maxHeight)
{
return false;
}
if (newHeight <= parentActualHeight)
{
return false;
}
return true;
}
/// <summary>
/// Check for new requested horizontal size is valid or not
/// </summary>
/// <param name="target">Target control being resized</param>
/// <param name="newWidth">The requested new width</param>
/// <param name="parentActualWidth">The parent control's ActualWidth</param>
/// <returns>Bool result if requested horizontal change is valid or not</returns>
protected static bool IsValidWidth(FrameworkElement target, double newWidth, double parentActualWidth)
{
var minWidth = target.MinWidth;
if (newWidth < 0 || (!double.IsNaN(minWidth) && newWidth < minWidth))
{
return false;
}
var maxWidth = target.MaxWidth;
if (!double.IsNaN(maxWidth) && newWidth > maxWidth)
{
return false;
}
if (newWidth <= parentActualWidth)
{
return false;
}
return true;
}
}

Просмотреть файл

@ -1,128 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#if !WINAPPSDK
using CursorEnum = Windows.UI.Core.CoreCursorType;
#else
using Microsoft.UI.Input;
using CursorEnum = Microsoft.UI.Input.InputSystemCursorShape;
#endif
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// Properties for <see cref="SizerBase"/>
/// </summary>
public partial class SizerBase : Control
{
/// <summary>
/// Gets or sets the cursor to use when hovering over the gripper bar. If left as <c>null</c>, the control will manage the cursor automatically based on the <see cref="Orientation"/> property value.
/// </summary>
public CursorEnum Cursor
{
get { return (CursorEnum)GetValue(CursorProperty); }
set { SetValue(CursorProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Cursor"/> dependency property.
/// </summary>
public static readonly DependencyProperty CursorProperty =
DependencyProperty.Register(nameof(Cursor), typeof(CursorEnum), typeof(SizerBase), new PropertyMetadata(null, OnOrientationPropertyChanged));
/// <summary>
/// Gets or sets the incremental amount of change for draging with the mouse or touch of a sizer control. Effectively a snapping increment for changes. The default is 1.
/// </summary>
/// <example>
/// For instance, if the DragIncrement is set to 16. Then when a component is resized with the sizer, it will only increase or decrease in size in that increment. I.e. -16, 0, 16, 32, 48, etc...
/// </example>
/// <remarks>
/// This value is indepedent of the <see cref="KeyboardIncrement"/> property. If you need to provide consistent snapping when moving regardless of input device, set these properties to the same value.
/// </remarks>
public double DragIncrement
{
get { return (double)GetValue(DragIncrementProperty); }
set { SetValue(DragIncrementProperty, value); }
}
/// <summary>
/// Identifies the <see cref="DragIncrement"/> dependency property.
/// </summary>
public static readonly DependencyProperty DragIncrementProperty =
DependencyProperty.Register(nameof(DragIncrement), typeof(double), typeof(SizerBase), new PropertyMetadata(1d));
/// <summary>
/// Gets or sets the distance each press of an arrow key moves a sizer control. The default is 8.
/// </summary>
/// <remarks>
/// This value is independent of the <see cref="DragIncrement"/> setting when using mouse/touch. If you want a consistent behavior regardless of input device, set them to the same value if snapping is required.
/// </remarks>
public double KeyboardIncrement
{
get { return (double)GetValue(KeyboardIncrementProperty); }
set { SetValue(KeyboardIncrementProperty, value); }
}
/// <summary>
/// Identifies the <see cref="KeyboardIncrement"/> dependency property.
/// </summary>
public static readonly DependencyProperty KeyboardIncrementProperty =
DependencyProperty.Register(nameof(KeyboardIncrement), typeof(double), typeof(SizerBase), new PropertyMetadata(8d));
/// <summary>
/// Gets or sets the orientation the sizer will be and how it will interact with other elements. Defaults to <see cref="Orientation.Vertical"/>.
/// </summary>
/// <remarks>
/// Note if using <see cref="GridSplitter"/>, use the <see cref="GridSplitter.ResizeDirection"/> property instead.
/// </remarks>
public Orientation Orientation
{
get { return (Orientation)GetValue(OrientationProperty); }
set { SetValue(OrientationProperty, value); }
}
/// <summary>
/// Identifies the <see cref="Orientation"/> dependency property.
/// </summary>
public static readonly DependencyProperty OrientationProperty =
DependencyProperty.Register(nameof(Orientation), typeof(Orientation), typeof(SizerBase), new PropertyMetadata(Orientation.Vertical, OnOrientationPropertyChanged));
private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is SizerBase gripper)
{
CursorEnum cursorToUse = gripper.Orientation == Orientation.Vertical ? CursorEnum.SizeWestEast : CursorEnum.SizeNorthSouth;
// See if there's been a cursor override, otherwise we'll pick
var cursor = gripper.ReadLocalValue(CursorProperty);
if (cursor == DependencyProperty.UnsetValue || cursor == null)
{
cursor = cursorToUse;
// On UWP, we use the extension in XAML to control this behavior,
// so we'll update it here (and maintain binding).
// We'll keep it in-sync to maintain behavior for WinUI 3 as well.
gripper.SetValue(CursorProperty, cursor);
// We return here, as the Cursor will trigger this function again anyway to set for WinUI 3
return;
}
// TODO: [UNO] Only supported on certain platforms
// See ProtectedCursor here: https://github.com/unoplatform/uno/blob/3fe3862b270b99dbec4d830b547942af61b1a1d9/src/Uno.UI/UI/Xaml/UIElement.cs#L1015-L1023
#if WINAPPSDK && !HAS_UNO
// Need to wait until we're at least applying template step of loading before setting Cursor
// See https://github.com/microsoft/microsoft-ui-xaml/issues/7062
if (gripper._applyingTemplate &&
cursor is CursorEnum cursorToSet &&
(gripper.ProtectedCursor == null ||
(gripper.ProtectedCursor is InputSystemCursor current &&
current.CursorShape != cursorToSet)))
{
gripper.ProtectedCursor = InputSystemCursor.Create(cursorToSet);
}
#endif
}
}
}

Просмотреть файл

@ -1,130 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Labs.WinUI.Automation.Peers;
namespace CommunityToolkit.Labs.WinUI;
/// <summary>
/// Base class for splitting/resizing type controls like <see cref="GridSplitter"/> and <see cref="ContentSizer"/>. Acts similar to an enlarged <see cref="Windows.UI.Xaml.Controls.Primitives.Thumb"/> type control, but with keyboard support. Subclasses should override the various abstract methods here to implement their behavior.
/// </summary>
public abstract partial class SizerBase : Control
{
/// <summary>
/// Called when the control has been initialized.
/// </summary>
/// <param name="e">Loaded event args.</param>
protected virtual void OnLoaded(RoutedEventArgs e)
{
}
/// <summary>
/// Called when the <see cref="SizerBase"/> control starts to be dragged by the user.
/// Implementor should record current state of manipulated target at this point in time.
/// They will receive the cumulative change in <see cref="OnDragHorizontal(double)"/> or
/// <see cref="OnDragVertical(double)"/> based on the <see cref="Orientation"/> property.
/// </summary>
/// <remarks>
/// This method is also called at the start of a keyboard interaction. Keyboard strokes use the same pattern to emulate a mouse movement for a single change. The appropriate
/// <see cref="OnDragHorizontal(double)"/> or <see cref="OnDragVertical(double)"/>
/// method will also be called after when the keyboard is used.
/// </remarks>
protected abstract void OnDragStarting();
/// <summary>
/// Method to process the requested horizontal resize.
/// </summary>
/// <param name="horizontalChange">The <see cref="ManipulationDeltaRoutedEventArgs.Cumulative"/> horizontal change amount from the start in device-independent pixels DIP.</param>
/// <returns><see cref="bool"/> indicates if a change was made</returns>
/// <remarks>
/// The value provided here is the cumulative change from the beginning of the
/// manipulation. This method will be used regardless of input device. It will already
/// be adjusted for RightToLeft <see cref="FlowDirection"/> of the containing
/// layout/settings. It will also already account for any settings such as
/// <see cref="DragIncrement"/> or <see cref="KeyboardIncrement"/>. The implementor
/// just needs to use the provided value to manipulate their baseline stored
/// in <see cref="OnDragStarting"/> to provide the desired change.
/// </remarks>
protected abstract bool OnDragHorizontal(double horizontalChange);
/// <summary>
/// Method to process the requested vertical resize.
/// </summary>
/// <param name="verticalChange">The <see cref="ManipulationDeltaRoutedEventArgs.Cumulative"/> vertical change amount from the start in device-independent pixels DIP.</param>
/// <returns><see cref="bool"/> indicates if a change was made</returns>
/// <remarks>
/// The value provided here is the cumulative change from the beginning of the
/// manipulation. This method will be used regardless of input device. It will also
/// already account for any settings such as <see cref="DragIncrement"/> or
/// <see cref="KeyboardIncrement"/>. The implementor just needs
/// to use the provided value to manipulate their baseline stored
/// in <see cref="OnDragStarting"/> to provide the desired change.
/// </remarks>
protected abstract bool OnDragVertical(double verticalChange);
/// <summary>
/// Initializes a new instance of the <see cref="SizerBase"/> class.
/// </summary>
public SizerBase()
{
this.DefaultStyleKey = typeof(SizerBase);
}
/// <summary>
/// Creates AutomationPeer (<see cref="UIElement.OnCreateAutomationPeer"/>)
/// </summary>
/// <returns>An automation peer for this <see cref="SizerBase"/>.</returns>
protected override AutomationPeer OnCreateAutomationPeer()
{
return new SizerAutomationPeer(this);
}
// On Uno the ProtectedCursor isn't supported yet, so we don't need this value.
#if WINAPPSDK && !HAS_UNO
// Used to track when we're in the OnApplyTemplateStep to change ProtectedCursor value.
private bool _applyingTemplate = false;
#endif
/// <inheritdoc/>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Unregister Events
Loaded -= SizerBase_Loaded;
PointerEntered -= SizerBase_PointerEntered;
PointerExited -= SizerBase_PointerExited;
PointerPressed -= SizerBase_PointerPressed;
PointerReleased -= SizerBase_PointerReleased;
ManipulationStarted -= SizerBase_ManipulationStarted;
ManipulationCompleted -= SizerBase_ManipulationCompleted;
IsEnabledChanged -= SizerBase_IsEnabledChanged;
// Register Events
Loaded += SizerBase_Loaded;
PointerEntered += SizerBase_PointerEntered;
PointerExited += SizerBase_PointerExited;
PointerPressed += SizerBase_PointerPressed;
PointerReleased += SizerBase_PointerReleased;
ManipulationStarted += SizerBase_ManipulationStarted;
ManipulationCompleted += SizerBase_ManipulationCompleted;
IsEnabledChanged += SizerBase_IsEnabledChanged;
// Trigger initial state transition based on if we're Enabled or not currently.
SizerBase_IsEnabledChanged(this, null!);
#if WINAPPSDK && !HAS_UNO
// On WinAppSDK, we'll trigger this to setup the initial ProtectedCursor value.
_applyingTemplate = true;
#endif
// On UWP, we'll check the current Orientation and set the Cursor property to use here still.
OnOrientationPropertyChanged(this, null!);
}
private void SizerBase_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= SizerBase_Loaded;
OnLoaded(e);
}
}

Просмотреть файл

@ -1,86 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:local="using:CommunityToolkit.Labs.WinUI.SizerBaseLocal"
xmlns:ui="using:Microsoft.Toolkit.Uwp.UI"
xmlns:win="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="GripperBarBackgroundPointerOver"
Color="{ThemeResource SystemBaseLowColor}" />
<SolidColorBrush x:Key="GripperBarBackgroundPressedOver"
Color="{ThemeResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="GripperBarForeground"
Color="{ThemeResource SystemAltHighColor}" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<SolidColorBrush x:Key="GripperBarBackgroundPointerOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="GripperBarBackgroundPressedOver"
Color="{ThemeResource SystemColorHighlightColor}" />
<SolidColorBrush x:Key="GripperBarForeground"
Color="{ThemeResource SystemAltHighColor}" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<local:OrientationToObjectConverter x:Key="OrientationToGlyphConverter"
HorizontalValue="&#xE76F;"
VerticalValue="&#xE784;" />
<StaticResource x:Key="GripperBarFontFamily"
ResourceKey="SymbolThemeFontFamily" />
<Style TargetType="controls:SizerBase">
<Setter Property="IsTabStop" Value="True" />
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="VerticalAlignment" Value="Stretch" />
<Setter Property="IsFocusEngagementEnabled" Value="True" />
<Setter Property="MinWidth" Value="16" />
<Setter Property="MinHeight" Value="16" />
<Setter Property="Background" Value="{ThemeResource SystemControlHighlightChromeHighBrush}" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="AutomationProperties.Name" Value="ms-resource://CommunityToolkit.Labs.WinUI.SizerBase/CommunityToolkit.Labs.WinUI.SizerBase/Resources/WCT_SizerBase_AutomationName" />
<Setter Property="ManipulationMode" Value="TranslateX,TranslateY" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:SizerBase">
<Grid x:Name="RootGrid"
local:FrameworkElementExtensions.Cursor="{TemplateBinding Cursor}"
Background="{TemplateBinding Background}">
<!-- Note: These align with Thumb -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="PointerOver">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource GripperBarBackgroundPointerOver}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Target="RootGrid.Background" Value="{ThemeResource GripperBarBackgroundPressedOver}" />
</VisualState.Setters>
</VisualState>
<!-- TODO -->
<VisualState x:Name="Disabled" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBlock HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
win:AutomationProperties.AccessibilityView="Raw"
FontFamily="{ThemeResource GripperBarFontFamily}"
Foreground="{ThemeResource GripperBarForeground}"
Text="{Binding Orientation, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource OrientationToGlyphConverter}}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Просмотреть файл

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="WCT_SizerBase_AutomationName" xml:space="preserve">
<value>Sizer</value>
<comment>Narrator Resource for SizerBase controls and similar</comment>
</data>
</root>

Просмотреть файл

@ -1,7 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///CommunityToolkit.Labs.WinUI.SizerBase/SizerBase.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

Просмотреть файл

@ -1,45 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI.SizerBaseLocal;
/// <summary>
/// Static class used to provide internal tools
/// </summary>
internal static class ConverterTools
{
/// <summary>
/// Helper method to safely cast an object to a boolean
/// </summary>
/// <param name="parameter">Parameter to cast to a boolean</param>
/// <returns>Bool value or false if cast failed</returns>
internal static bool TryParseBool(object parameter)
{
var parsed = false;
if (parameter != null)
{
bool.TryParse(parameter.ToString(), out parsed);
}
return parsed;
}
/// <summary>
/// Helper method to convert a value from a source type to a target type.
/// </summary>
/// <param name="value">The value to convert</param>
/// <param name="targetType">The target type</param>
/// <returns>The converted value</returns>
internal static object Convert(object value, Type targetType)
{
if (targetType.IsInstanceOfType(value))
{
return value;
}
else
{
return XamlBindingHelper.ConvertValue(targetType, value);
}
}
}

Просмотреть файл

@ -1,225 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// We want this to be private/local to our component.
namespace CommunityToolkit.Labs.WinUI.SizerBaseLocal;
//// IMPORTANT NOTE: This is the old 6.1.1 version of the extensions as I had issues with TPredicate with the new ones here for some reason and just wanted to get this working for now.
/// <summary>
/// Defines a collection of extensions methods for UI.
/// </summary>
public static class VisualTree
{
/// <summary>
/// Find descendant <see cref="FrameworkElement"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
public static FrameworkElement? FindDescendantByName(this DependencyObject element, string name)
{
if (element == null || string.IsNullOrWhiteSpace(name))
{
return null;
}
if (name.Equals((element as FrameworkElement)?.Name, StringComparison.OrdinalIgnoreCase))
{
return element as FrameworkElement;
}
var childCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childCount; i++)
{
var result = VisualTreeHelper.GetChild(element, i).FindDescendantByName(name);
if (result != null)
{
return result;
}
}
return null;
}
/// <summary>
/// Find first descendant control of a specified type.
/// </summary>
/// <typeparam name="T">Type to search for.</typeparam>
/// <param name="element">Parent element.</param>
/// <returns>Descendant control or null if not found.</returns>
public static T? FindDescendant<T>(this DependencyObject element)
where T : DependencyObject
{
T? retValue = default(T);
var childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
if (child is T type)
{
retValue = type;
break;
}
retValue = FindDescendant<T>(child);
if (retValue != null)
{
break;
}
}
return retValue;
}
/// <summary>
/// Find first descendant control of a specified type.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="type">Type of descendant.</param>
/// <returns>Descendant control or null if not found.</returns>
public static object? FindDescendant(this DependencyObject element, Type type)
{
object? retValue = null;
var childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
if (child.GetType() == type)
{
retValue = child;
break;
}
retValue = FindDescendant(child, type);
if (retValue != null)
{
break;
}
}
return retValue;
}
/// <summary>
/// Find all descendant controls of the specified type.
/// </summary>
/// <typeparam name="T">Type to search for.</typeparam>
/// <param name="element">Parent element.</param>
/// <returns>Descendant controls or empty if not found.</returns>
public static IEnumerable<T> FindDescendants<T>(this DependencyObject element)
where T : DependencyObject
{
var childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(element, i);
if (child is T type)
{
yield return type;
}
foreach (T childofChild in child.FindDescendants<T>())
{
yield return childofChild;
}
}
}
/// <summary>
/// Find visual ascendant <see cref="FrameworkElement"/> control using its name.
/// </summary>
/// <param name="element">Parent element.</param>
/// <param name="name">Name of the control to find</param>
/// <returns>Descendant control or null if not found.</returns>
public static FrameworkElement? FindAscendantByName(this DependencyObject element, string name)
{
if (element == null || string.IsNullOrWhiteSpace(name))
{
return null;
}
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return null;
}
if (name.Equals((parent as FrameworkElement)?.Name, StringComparison.OrdinalIgnoreCase))
{
return parent as FrameworkElement;
}
return parent.FindAscendantByName(name);
}
/// <summary>
/// Find first visual ascendant control of a specified type.
/// </summary>
/// <typeparam name="T">Type to search for.</typeparam>
/// <param name="element">Child element.</param>
/// <returns>Ascendant control or null if not found.</returns>
public static T? FindAscendant<T>(this DependencyObject element)
where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return default(T);
}
if (parent is T rtn)
{
return rtn;
}
return parent.FindAscendant<T>();
}
/// <summary>
/// Find first visual ascendant control of a specified type.
/// </summary>
/// <param name="element">Child element.</param>
/// <param name="type">Type of ascendant to look for.</param>
/// <returns>Ascendant control or null if not found.</returns>
public static object? FindAscendant(this DependencyObject element, Type type)
{
var parent = VisualTreeHelper.GetParent(element);
if (parent == null)
{
return null;
}
if (parent.GetType() == type)
{
return parent;
}
return parent.FindAscendant(type);
}
/// <summary>
/// Find all visual ascendants for the element.
/// </summary>
/// <param name="element">Child element.</param>
/// <returns>A collection of parent elements or null if none found.</returns>
public static IEnumerable<DependencyObject> FindAscendants(this DependencyObject element)
{
var parent = VisualTreeHelper.GetParent(element);
while (parent != null)
{
yield return parent;
parent = VisualTreeHelper.GetParent(parent);
}
}
}

Просмотреть файл

@ -1,113 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Windows.UI.Core;
namespace CommunityToolkit.Labs.WinUI.SizerBaseLocal;
/// <inheritdoc cref="FrameworkElementExtensions"/>
public static partial class FrameworkElementExtensions
{
private static readonly object _cursorLock = new object();
private static readonly CoreCursor _defaultCursor = new CoreCursor(CoreCursorType.Arrow, 1);
private static readonly Dictionary<CoreCursorType, CoreCursor> _cursors =
new Dictionary<CoreCursorType, CoreCursor> { { CoreCursorType.Arrow, _defaultCursor } };
/// <summary>
/// Dependency property for specifying the target <see cref="CoreCursorType"/> to be shown
/// over the target <see cref="FrameworkElement"/>.
/// </summary>
public static readonly DependencyProperty CursorProperty =
DependencyProperty.RegisterAttached("Cursor", typeof(CoreCursorType), typeof(FrameworkElementExtensions), new PropertyMetadata(CoreCursorType.Arrow, CursorChanged));
/// <summary>
/// Set the target <see cref="CoreCursorType"/>.
/// </summary>
/// <param name="element">Object where the selector cursor type should be shown.</param>
/// <param name="value">Target cursor type value.</param>
public static void SetCursor(FrameworkElement element, CoreCursorType value)
{
element.SetValue(CursorProperty, value);
}
/// <summary>
/// Get the current <see cref="CoreCursorType"/>.
/// </summary>
/// <param name="element">Object where the selector cursor type should be shown.</param>
/// <returns>Cursor type set on target element.</returns>
public static CoreCursorType GetCursor(FrameworkElement element)
{
return (CoreCursorType)element.GetValue(CursorProperty);
}
private static void CursorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// TODO: How do we want to indicate this isn't supported on the WinAppSDK?
#if !WINAPPSDK
var element = d as FrameworkElement;
if (element == null)
{
throw new NullReferenceException(nameof(element));
}
var value = (CoreCursorType)e.NewValue;
// lock ensures CoreCursor creation and event handlers attachment/detachment is atomic
lock (_cursorLock)
{
if (!_cursors.ContainsKey(value))
{
_cursors[value] = new CoreCursor(value, 1);
}
// make sure event handlers are not attached twice to element
element.PointerEntered -= Element_PointerEntered;
element.PointerEntered += Element_PointerEntered;
element.PointerExited -= Element_PointerExited;
element.PointerExited += Element_PointerExited;
element.Unloaded -= ElementOnUnloaded;
element.Unloaded += ElementOnUnloaded;
}
#endif
}
#if !WINAPPSDK
private static void Element_PointerEntered(object sender, PointerRoutedEventArgs e)
{
// TODO: [UNO] Only supported on certain platforms
// See PointerCursor here: https://github.com/unoplatform/uno/blob/3fe3862b270b99dbec4d830b547942af61b1a1d9/src/Uno.UWP/UI/Core/CoreWindow.cs#L71-L77
#if NETFX_CORE || WASM || __MACOS__ || __SKIA__
CoreCursorType cursor = GetCursor((FrameworkElement)sender);
Window.Current.CoreWindow.PointerCursor = _cursors[cursor];
#endif
}
private static void Element_PointerExited(object sender, PointerRoutedEventArgs e)
{
#if NETFX_CORE || WASM || __MACOS__ || __SKIA__
// when exiting change the cursor to the target Mouse.Cursor value of the new element
CoreCursor cursor;
if (sender != e.OriginalSource && e.OriginalSource is FrameworkElement newElement)
{
cursor = _cursors[GetCursor(newElement)];
}
else
{
cursor = _defaultCursor;
}
Window.Current.CoreWindow.PointerCursor = cursor;
#endif
}
private static void ElementOnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
#if NETFX_CORE || __WASM__ || __MACOS__ || __SKIA__
// when the element is programatically unloaded, reset the cursor back to default
// this is necessary when click triggers immediate change in layout and PointerExited is not called
Window.Current.CoreWindow.PointerCursor = _defaultCursor;
#endif
}
#endif
}

Просмотреть файл

@ -1,76 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI.SizerBaseLocal;
/// <summary>
/// This class returns a value depending on the <see cref="Orientation"/> of the value provided to the converter. In case of default will return the <see cref="VerticalValue"/>.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1001:Types that own disposable fields should be disposable", Justification = "Internal Uno Generator Issue: https://github.com/unoplatform/uno/pull/8743")]
public partial class OrientationToObjectConverter : DependencyObject, IValueConverter
{
/// <summary>
/// Identifies the <see cref="HorizontalValue"/> property.
/// </summary>
public static readonly DependencyProperty HorizontalValueProperty =
DependencyProperty.Register(nameof(HorizontalValue), typeof(object), typeof(OrientationToObjectConverter), new PropertyMetadata(null));
/// <summary>
/// Identifies the <see cref="VerticalValue"/> property.
/// </summary>
public static readonly DependencyProperty VerticalValueProperty =
DependencyProperty.Register(nameof(VerticalValue), typeof(object), typeof(OrientationToObjectConverter), new PropertyMetadata(null));
/// <summary>
/// Gets or sets the value to be returned when the <see cref="Orientation"/> of the provided value is <see cref="Orientation.Horizontal"/>.
/// </summary>
public object HorizontalValue
{
get { return GetValue(HorizontalValueProperty); }
set { SetValue(HorizontalValueProperty, value); }
}
/// <summary>
/// Gets or sets the value to be returned when the <see cref="Orientation"/> of the provided value is <see cref="Orientation.Vertical"/>.
/// </summary>
public object VerticalValue
{
get { return GetValue(VerticalValueProperty); }
set { SetValue(VerticalValueProperty, value); }
}
/// <summary>
/// Convert the <paramref name="value"/>'s Orientation to an other object.
/// </summary>
/// <param name="value">The source data being passed to the target.</param>
/// <param name="targetType">The type of the target property, as a type reference.</param>
/// <param name="parameter">An optional parameter to be used to invert the converter logic.</param>
/// <param name="language">The language of the conversion.</param>
/// <returns>The value to be passed to the target dependency property.</returns>
public object Convert(object value, Type targetType, object parameter, string language)
{
var isHorizontal = value != null && value is Orientation orientation && orientation == Orientation.Horizontal;
// Negate if needed
if (ConverterTools.TryParseBool(parameter))
{
isHorizontal = !isHorizontal;
}
return ConverterTools.Convert(isHorizontal ? HorizontalValue : VerticalValue, targetType);
}
/// <summary>
/// Not implemented.
/// </summary>
/// <param name="value">The source data being passed to the target.</param>
/// <param name="targetType">The type of the target property, as a type reference.</param>
/// <param name="parameter">Optional parameter. Not used.</param>
/// <param name="language">The language of the conversion. Not used.</param>
/// <returns>The value to be passed to the target dependency property.</returns>
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,91 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace CommunityToolkit.Labs.WinUI.SizerBaseLocal;
/// <summary>
/// This class returns an object or another, depending on whether the type of the provided value matches another provided Type.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1001:Types that own disposable fields should be disposable", Justification = "Internal Uno Generator Issue: https://github.com/unoplatform/uno/pull/8743")]
public partial class TypeToObjectConverter : DependencyObject, IValueConverter
{
/// <summary>
/// Identifies the <see cref="TrueValue"/> property.
/// </summary>
public static readonly DependencyProperty TrueValueProperty =
DependencyProperty.Register(nameof(TrueValue), typeof(object), typeof(TypeToObjectConverter), new PropertyMetadata(null));
/// <summary>
/// Identifies the <see cref="FalseValue"/> property.
/// </summary>
public static readonly DependencyProperty FalseValueProperty =
DependencyProperty.Register(nameof(FalseValue), typeof(object), typeof(TypeToObjectConverter), new PropertyMetadata(null));
/// <summary>
/// Identifies the <see cref="Type"/> property.
/// </summary>
public static readonly DependencyProperty TypeProperty =
DependencyProperty.Register(nameof(Type), typeof(Type), typeof(TypeToObjectConverter), new PropertyMetadata(typeof(object)));
/// <summary>
/// Gets or sets the value to be returned when the type of the provided value matches <see cref="Type"/>.
/// </summary>
public object TrueValue
{
get { return GetValue(TrueValueProperty); }
set { SetValue(TrueValueProperty, value); }
}
/// <summary>
/// Gets or sets the value to be returned when the type of the provided value does not match <see cref="Type"/>.
/// </summary>
public object FalseValue
{
get { return GetValue(FalseValueProperty); }
set { SetValue(FalseValueProperty, value); }
}
/// <summary>
/// Gets or sets the Type used to compare the type of the provided value.
/// </summary>
public Type Type
{
get { return (Type)GetValue(TypeProperty); }
set { SetValue(TypeProperty, value); }
}
/// <summary>
/// Convert the <paramref name="value"/>'s Type to an other object.
/// </summary>
/// <param name="value">The source data being passed to the target.</param>
/// <param name="targetType">The type of the target property, as a type reference.</param>
/// <param name="parameter">An optional parameter to be used to invert the converter logic.</param>
/// <param name="language">The language of the conversion.</param>
/// <returns>The value to be passed to the target dependency property.</returns>
public object Convert(object value, Type targetType, object parameter, string language)
{
var typeMatches = value != null && Type.Equals(value.GetType());
// Negate if needed
if (ConverterTools.TryParseBool(parameter))
{
typeMatches = !typeMatches;
}
return ConverterTools.Convert(typeMatches ? TrueValue : FalseValue, targetType);
}
/// <summary>
/// Not implemented.
/// </summary>
/// <param name="value">The source data being passed to the target.</param>
/// <param name="targetType">The type of the target property, as a type reference.</param>
/// <param name="parameter">Optional parameter. Not used.</param>
/// <param name="language">The language of the conversion. Not used.</param>
/// <returns>The value to be passed to the target dependency property.</returns>
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}

Просмотреть файл

@ -1,61 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Labs.WinUI;
using CommunityToolkit.Tooling.TestGen;
using CommunityToolkit.Tests;
using CommunityToolkit.Labs.WinUI.Automation.Peers;
namespace SizerBaseExperiment.Tests;
[TestClass]
public partial class ExampleSizerBaseTestClass : VisualUITestBase
{
[TestMethod]
public async Task ShouldConfigureGridSplitterAutomationPeer()
{
await EnqueueAsync(() =>
{
const string automationName = "MyCustomAutomationName";
const string name = "Sizer";
var gridSplitter = new GridSplitter();
var gridSplitterAutomationPeer = FrameworkElementAutomationPeer.CreatePeerForElement(gridSplitter) as SizerAutomationPeer;
Assert.IsNotNull(gridSplitterAutomationPeer, "Verify that the AutomationPeer is SizerAutomationPeer.");
gridSplitter.Name = name;
Assert.IsTrue(gridSplitterAutomationPeer.GetName().Contains(name), "Verify that the UIA name contains the given Name of the GridSplitter (Sizer).");
gridSplitter.SetValue(AutomationProperties.NameProperty, automationName);
Assert.IsTrue(gridSplitterAutomationPeer.GetName().Contains(automationName), "Verify that the UIA name contains the customized AutomationProperties.Name of the GridSplitter.");
});
}
[UIThreadTestMethod]
public void PropertySizer_TestInitialBinding(PropertySizerTestInitialBinding testControl)
{
var propertySizer = testControl.FindDescendant<PropertySizer>();
Assert.IsNotNull(propertySizer, "Could not find PropertySizer control.");
// Set in XAML Page LINK: PropertySizerTestInitialBinding.xaml#L14
Assert.AreEqual(300, propertySizer.Binding, "Property Sizer not at expected initial value.");
}
[UIThreadTestMethod]
public void PropertySizer_TestChangeBinding(PropertySizerTestInitialBinding testControl)
{
var propertySizer = testControl.FindDescendant<PropertySizer>();
var navigationView = testControl.FindDescendant<MUXC.NavigationView>();
Assert.IsNotNull(propertySizer, "Could not find PropertySizer control.");
Assert.IsNotNull(navigationView, "Could not find NavigationView control.");
navigationView.OpenPaneLength = 200;
// Set in XAML Page LINK: PropertySizerTestInitialBinding.xaml#L14
Assert.AreEqual(200, propertySizer.Binding, "Property Sizer not at expected changed value.");
}
}

Просмотреть файл

@ -1,28 +0,0 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="SizerBaseExperiment.Tests.PropertySizerTestInitialBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.Labs.WinUI"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
mc:Ignorable="d">
<muxc:NavigationView x:Name="ViewPanel"
MinHeight="300"
IsPaneOpen="True"
OpenPaneLength="300"
PaneDisplayMode="Left">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- Note the use of a TwoWay binding here, this is required for this control to work. -->
<controls:PropertySizer HorizontalAlignment="Left"
Binding="{x:Bind ViewPanel.OpenPaneLength, Mode=TwoWay}"
Maximum="440"
Minimum="52" />
</Grid>
</muxc:NavigationView>
</Page>

Просмотреть файл

@ -1,16 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
namespace SizerBaseExperiment.Tests;
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class PropertySizerTestInitialBinding : Page
{
public PropertySizerTestInitialBinding()
{
this.InitializeComponent();
}
}

Просмотреть файл

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<MSBuildAllProjects Condition="'$(MSBuildVersion)' == '' Or '$(MSBuildVersion)' &lt; '16.0'">$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
<HasSharedItems>true</HasSharedItems>
<SharedGUID>55883B50-C4F3-419E-B235-C51279EB4055</SharedGUID>
</PropertyGroup>
<PropertyGroup Label="Configuration">
<Import_RootNamespace>SizerBaseExperiment.Tests</Import_RootNamespace>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)ExampleSizerBaseTestClass.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PropertySizerTestInitialBinding.xaml.cs">
<DependentUpon>PropertySizerTestInitialBinding.xaml</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup>
<Page Include="$(MSBuildThisFileDirectory)PropertySizerTestInitialBinding.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>

Просмотреть файл

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Label="Globals">
<ProjectGuid>55883B50-C4F3-419E-B235-C51279EB4055</ProjectGuid>
<MinimumVisualStudioVersion>14.0</MinimumVisualStudioVersion>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.Default.props" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.Common.props" />
<PropertyGroup />
<Import Project="SizerBase.Tests.projitems" Label="Shared" />
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\CodeSharing\Microsoft.CodeSharing.CSharp.targets" />
</Project>