Merge branch 'master' into viewportbehavior

This commit is contained in:
Michael Hawker MSFT (XAML Llama) 2019-09-14 14:32:50 -07:00 коммит произвёл GitHub
Родитель 8d114ddfcc a4215c7da0
Коммит 7a263cd0b9
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
122 изменённых файлов: 5079 добавлений и 2013 удалений

66
.github/ISSUE_TEMPLATE.md поставляемый
Просмотреть файл

@ -1,66 +0,0 @@
<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->
<!-- For WPF or WinForms controls, please file an issue instead at https://github.com/windows-toolkit/Microsoft.Toolkit.Win32/issues/new -->
## I'm submitting a...
<!-- Please uncomment one or more that apply to this issue -->
<!-- For new features, create a UserVoice request here and link below: https://wpdev.uservoice.com/forums/110705-universal-windows-platform/category/193402-uwp-community-toolkit -->
<!-- - Regression (a behavior that used to work and stopped working in a new release) -->
<!-- - Bug report (I searched for similar issues and did not find one) -->
<!-- - Feature request (UserVoice request: ) -->
<!-- - Sample app request -->
<!-- - Documentation issue or request -->
<!-- - Question of Support request => Please do not submit support request here, instead see https://github.com/windows-toolkit/WindowsCommunityToolkit/blob/master/contributing.md#question -->
## Current behavior
<!-- Describe how the issue manifests. -->
## Expected behavior
<!-- Describe what the desired behavior would be. -->
## Minimal reproduction of the problem with instructions
<!--
For bug reports please provide a *MINIMAL REPRO PROJECT* and the *STEPS TO REPRODUCE*
-->
## Environment
<!-- For bug reports Check one or more of the following options with "x" -->
```
Nuget Package(s):
Package Version(s):
Windows 10 Build Number:
- [ ] Fall Creators Update (16299)
- [ ] April 2018 Update (17134)
- [ ] October 2018 Update (17763)
- [ ] Insider Build (build number: )
App min and target version:
- [ ] Fall Creators Update (16299)
- [ ] April 2018 Update (17134)
- [ ] October 2018 Update (17763)
- [ ] Insider Build (xxxxx)
Device form factor:
- [ ] Desktop
- [ ] Mobile
- [ ] Xbox
- [ ] Surface Hub
- [ ] IoT
Visual Studio
- [ ] 2017 (version: )
- [ ] 2017 Preview (version: )
```

68
.github/ISSUE_TEMPLATE/bug_report.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,68 @@
---
name: Bug report
about: Create a report to help us fix something that isn't working as expected
title: ''
labels: bug
assignees: ''
---
<!--
PLEASE HELP US PROCESS GITHUB ISSUES FASTER BY PROVIDING THE FOLLOWING INFORMATION.
ISSUES MISSING IMPORTANT INFORMATION MAY BE CLOSED WITHOUT INVESTIGATION.
-->
## Describe the bug
A clear and concise description of what the bug is.
- [ ] Is this bug a regression in the toolkit? If so, what toolkit version did you last see it work:
## Steps to Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Environment
<!-- Check one or more of the following options with "x" -->
```
NuGet Package(s):
Package Version(s):
Windows 10 Build Number:
- [ ] Fall Creators Update (16299)
- [ ] April 2018 Update (17134)
- [ ] October 2018 Update (17763)
- [ ] May 2019 Update (18362)
- [ ] Insider Build (build number: )
App min and target version:
- [ ] Fall Creators Update (16299)
- [ ] April 2018 Update (17134)
- [ ] October 2018 Update (17763)
- [ ] May 2019 Update (18362)
- [ ] Insider Build (xxxxx)
Device form factor:
- [ ] Desktop
- [ ] Xbox
- [ ] Surface Hub
- [ ] IoT
Visual Studio
- [ ] 2017 (version: )
- [ ] 2019 (version: )
- [ ] 2019 Preview (version: )
```
## Additional context
Add any other context about the problem here.

18
.github/ISSUE_TEMPLATE/documentation.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,18 @@
---
name: Documentation
about: I have a documentation suggestion or question
title: "[Docs]"
labels: documentation
assignees: ''
---
<!--
Hi!
We have a separate repo for our documentation, please file an issue instead at https://github.com/MicrosoftDocs/WindowsCommunityToolkitDocs/issues/new
Otherwise, this issue will be automatically closed.
Thanks!
-->

21
.github/ISSUE_TEMPLATE/feature_request.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,21 @@
---
name: Feature request
about: I have a new idea or improvement for the toolkit
title: "[Feature]"
labels: feature request
assignees: ''
---
## Describe the problem this feature would solve
<!-- Please describe or link to any existing issues or discussions.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
## Describe the solution
<!-- A clear and concise description of what you want to happen. -->
## Describe alternatives you've considered
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
## Additional context & Screenshots
<!-- Add any other context or screenshots about the feature request here.-->

22
.github/ISSUE_TEMPLATE/question.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,22 @@
---
name: Question
about: I have a question about how to use something in the toolkit.
title: "[Question]"
labels: question
assignees: ''
---
<!--
Hi!
We try and keep our GitHub issue list for bugs and features.
Ideally, it'd be great to post your question on Stack Overflow using the 'windows-community-toolkit' tag here: https://stackoverflow.com/questions/tagged/windows-community-toolkit
If this is more about a scenario that you think is missing documentation, please file an issue instead at https://github.com/MicrosoftDocs/WindowsCommunityToolkitDocs/issues/new
Otherwise, this issue will be automatically closed.
Thanks!
-->

18
.github/ISSUE_TEMPLATE/win32_controls.md поставляемый Normal file
Просмотреть файл

@ -0,0 +1,18 @@
---
name: Win32 Controls
about: I have an issue with a Toolkit WPF or WinForms control
title: "[Win32]"
labels:
assignees: ''
---
<!--
Hi!
We have a separate toolkit repo for our Win32 controls that work in WPF or WinForms, please file an issue instead at https://github.com/windows-toolkit/Microsoft.Toolkit.Win32/issues/new
Otherwise, this issue will automatically be moved to that repo.
Thanks!
-->

1
.gitignore поставляемый
Просмотреть файл

@ -6,6 +6,7 @@
*.user
*.userosscache
*.sln.docstates
*.filters
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs

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

@ -1,6 +1,6 @@
<Project>
<Choose>
<When Condition="'$(TargetFramework)' == 'uap10.0' or '$(TargetFramework)' == 'uap10.0.16299' or '$(TargetFramework)' == 'native'">
<When Condition="'$(TargetFramework)' == 'uap10.0' or '$(TargetFramework)' == 'uap10.0.16299' or '$(TargetFramework)' == 'native' or '$(TargetFramework)' == 'net461'">
<!-- UAP versions for uap10.0 where TPMV isn't implied -->
<PropertyGroup>
<TargetPlatformVersion>10.0.$(DefaultTargetPlatformVersion).0</TargetPlatformVersion>

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

@ -17,7 +17,7 @@
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
<PackageCertificateKeyFile>GazeInputTest_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
@ -104,7 +104,6 @@
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="GazeInputTest_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Content Include="Properties\Default.rd.xml" />

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

@ -54,8 +54,22 @@ namespace Microsoft.Toolkit.Parsers.Markdown.Blocks
actualEnd = start;
// First thing to do is to check if there is a vertical bar on the line.
int barOrNewLineIndex = markdown.IndexOf('|', start, endOfFirstLine - start);
if (barOrNewLineIndex < 0)
var barSections = markdown.Substring(start, endOfFirstLine - start).Split('|');
var allBarsEscaped = true;
// we can skip the last section, because there is no bar at the end of it
for (var i = 0; i < barSections.Length - 1; i++)
{
var barSection = barSections[i];
if (!barSection.EndsWith("\\"))
{
allBarsEscaped = false;
break;
}
}
if (allBarsEscaped)
{
return null;
}
@ -208,7 +222,7 @@ namespace Microsoft.Toolkit.Parsers.Markdown.Blocks
while (pos < maxEndingPos)
{
char c = markdown[pos];
if (c == '|')
if (c == '|' && (pos == 0 || markdown[pos - 1] != '\\'))
{
lineHasVerticalBar = true;
endOfLineFound = false;

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

@ -100,7 +100,7 @@ namespace Microsoft.Toolkit.Parsers.Markdown.Inlines
return base.ToString();
}
return "*" + string.Join(string.Empty, Inlines) + "*";
return "**" + string.Join(string.Empty, Inlines) + "**";
}
}
}
}

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

@ -1,9 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Title>Windows Community Toolkit .NET Standard Parsers</Title>
<Description>This .NET standard library contains various parsers including Markdown and RSS. It is part of the Windows Community Toolkit.</Description>
<Description>
This .NET standard library contains various parsers
Markdown: Allows you to parse a Markdown String into a Markdown Document, and then Render it with a Markdown Renderer.
RSS: Allows you to parse an RSS content String into an RSS Schema.
</Description>
<PackageTags>UWP Toolkit Windows Parsers Parsing Markdown RSS</PackageTags>
<!-- This is a temporary workaround for https://github.com/dotnet/sdk/issues/955 -->

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

@ -3,7 +3,12 @@
<PropertyGroup>
<TargetFrameworks>uap10.0.16299;netstandard2.0;NET462</TargetFrameworks>
<Title>Windows Community Toolkit .NET Standard Services</Title>
<Description>This .NET standard library enables access to different data sources such as Microsoft Graph, OneDrive, Twitter, Microsoft Translator, and LinkedIn. It is part of the Windows Community Toolkit.</Description>
<Description>
This .NET standard library enables access to different data sources such as Microsoft Graph, OneDrive, Twitter, Microsoft Translator, and LinkedIn. It is part of the Windows Community Toolkit.
Namespace:
- Facebook: Album, DataConfig, DataHost, OAuthTokens, Permissions, Photo, Picture, PictureData, PlatformImageSource, Post, RequestSource, Service.
</Description>
<PackageTags>UWP Community Toolkit Windows Microsoft Graph OneDrive Twitter Translator LinkedIn service login OAuth</PackageTags>
<!-- This is a temporary workaround for https://github.com/dotnet/sdk/issues/955 -->

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

@ -278,7 +278,7 @@ namespace Microsoft.Toolkit.Services.MicrosoftGraph
}
/// <summary>
/// Tries to log in user if not already loged in. Calls LoginAsync internaly
/// Tries to log in user if not already logged in. Calls LoginAsync internally
/// </summary>
/// <remarks>Exceptions are not thrown but SignInFailed event is raised</remarks>
/// <returns>Returns success or failure of login attempt.</returns>

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

@ -2,6 +2,7 @@
// 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 static Microsoft.Toolkit.Services.MicrosoftGraph.MicrosoftGraphEnums;
namespace Microsoft.Toolkit.Services.OneDrive
@ -23,11 +24,16 @@ namespace Microsoft.Toolkit.Services.OneDrive
return "rename";
}
if (collisionOption.Equals("ReplaceExisting") || collisionOption.Equals("OpenIfExists"))
if (collisionOption.Equals("ReplaceExisting"))
{
return "replace";
}
if (collisionOption.Equals("OpenIfExists"))
{
throw new ArgumentException("OpenIfExists conflict option is not supported at this time", collisionOption);
}
return "fail";
}

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

@ -357,7 +357,7 @@ namespace Microsoft.Toolkit.Uwp.Connectivity
/// Gets the bluetooth address of this device as a string
/// </summary>
/// <value>The bluetooth address as string.</value>
public string BluetoothAddressAsString => DeviceInfo.Properties["System.Devices.Aep.DeviceAddress"].ToString();
public string BluetoothAddressAsString => DeviceInfo.Properties["System.Devices.Aep.DeviceAddress"]?.ToString();
/// <summary>
/// Gets the bluetooth address of this device
@ -549,4 +549,4 @@ namespace Microsoft.Toolkit.Uwp.Connectivity
});
}
}
}
}

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

@ -3,8 +3,8 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit Devices</Title>
<Description>This library enables easier consumption of Devices / Peripherals connected to Windows device. It is part of the Windows Community Toolkit.</Description>
<PackageTags>UWP Toolkit Windows Devices Bluetooth BTLE Networking</PackageTags>
<Description>This library enables easier consumption of connectivity Devices/Peripherals and handle its connection to Windows devices. It contains BluetoothLE and Network connectivity helpers.</Description>
<PackageTags>UWP Toolkit Windows Devices Bluetooth BluetoothLE BLE Networking</PackageTags>
</PropertyGroup>
<ItemGroup>

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

@ -3,7 +3,12 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit Developer Tools</Title>
<Description>This library provides XAML user controls and services to help developer building their app. It is part of the Windows Community Toolkit.</Description>
<Description>This library provides XAML user controls and services to help developers build their app. It is part of the Windows Community Toolkit.
-AligmentGrid : Displays a Grid that helps align the controls.
-FocusTrackerControl : The FocusTracker Control is a feature that can be used to display information about the current focused XAML element.
-Themes : Provides the source path of the resource dictionaries for the FocusTracker.
</Description>
<PackageTags>UWP Toolkit Windows Controls XAML Developer Tools Accessibility AlignmentGrid</PackageTags>
<UseUwpMetaPackage>true</UseUwpMetaPackage>
</PropertyGroup>

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

@ -38,40 +38,41 @@
<WindowsTargetPlatformMinVersion>10.0.17134.0</WindowsTargetPlatformMinVersion>
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
<ProjectName>Microsoft.Toolkit.Uwp.Input.GazeInteraction</ProjectName>
<TargetFrameworks>UAP,Version=v10.0</TargetFrameworks>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v141</PlatformToolset>
<PlatformToolset>v142</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">

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

@ -1,121 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Resources">
<UniqueIdentifier>f664c808-2b14-44e2-b2c2-0e7f5c370edd</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Sources">
<UniqueIdentifier>{3088c194-1660-4cdf-b724-1d4cd29741ef}</UniqueIdentifier>
</Filter>
<Filter Include="Headers">
<UniqueIdentifier>{3d051054-c757-4fd1-8f31-5a2912c88d15}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="GazeCursor.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeStats.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="OneEuroFilter.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="pch.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeSettingsHelper.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeTargetItem.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeFeedbackPopupFactory.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazePointerProxy.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeInput.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazePointer.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeEventArgs.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="GazeHidParsers.cpp">
<Filter>Sources</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeCursor.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazePointer.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeStats.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="IGazeFilter.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="OneEuroFilter.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeSettingsHelper.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeElement.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeHistoryItem.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeTargetItem.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeFeedbackPopupFactory.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazePointerProxy.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeInput.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="PointerState.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="StateChangedEventArgs.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="DwellProgressState.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="DwellInvokedRoutedEventArgs.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="DwellProgressEventArgs.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="Interaction.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeEventArgs.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeHidUsages.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="GazeHidParsers.h">
<Filter>Headers</Filter>
</ClInclude>
</ItemGroup>
</Project>

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

@ -1,11 +1,17 @@
<Project Sdk="MSBuild.Sdk.Extras">
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFramework>uap10.0</TargetFramework>
<IncludeBuildOutput>false</IncludeBuildOutput>
<Title>Windows Community Toolkit Notifications for JavaScript</Title>
<Description>Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.
Supports adaptive tiles and adaptive/interactive toasts for Windows 10. It is part of the Windows Community Toolkit. Supports C# and C++ UWP project types (see Microsoft.Toolkit.Uwp.Notifications). Also works with C# portable class libraries and non-UWP C# projects like server projects.</Description>
<Description>
This project is used for packaging the WinMD to work for WinJS projects.
Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.
Supports adaptive tiles and adaptive/interactive toasts for Windows 10. It is part of the Windows Community Toolkit.
Supports C# and C++ UWP project types (see Microsoft.Toolkit.Uwp.Notifications).
Also works with C# portable class libraries and non-UWP C# projects like server projects.
</Description>
<PackageTags>notifications win10 windows-10 tile tiles toast toasts badge xml uwp javascript</PackageTags>
<ExtrasImplicitPlatformPackageIsPrivate>true</ExtrasImplicitPlatformPackageIsPrivate>
</PropertyGroup>

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

@ -0,0 +1,102 @@
// 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.Collections.Generic;
using Windows.UI.Notifications;
namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Manages the toast notifications for an app including the ability the clear all toast history and removing individual toasts.
/// </summary>
public sealed class DesktopNotificationHistoryCompat
{
private string _aumid;
private ToastNotificationHistory _history;
/// <summary>
/// Initializes a new instance of the <see cref="DesktopNotificationHistoryCompat"/> class.
/// Do not call this. Instead, call <see cref="DesktopNotificationManagerCompat.History"/> to obtain an instance.
/// </summary>
/// <param name="aumid">An AUMID that uniquely identifies your application.</param>
internal DesktopNotificationHistoryCompat(string aumid)
{
_aumid = aumid;
_history = ToastNotificationManager.History;
}
/// <summary>
/// Removes all notifications sent by this app from action center.
/// </summary>
public void Clear()
{
if (_aumid != null)
{
_history.Clear(_aumid);
}
else
{
_history.Clear();
}
}
/// <summary>
/// Gets all notifications sent by this app that are currently still in Action Center.
/// </summary>
/// <returns>A collection of toasts.</returns>
public IReadOnlyList<ToastNotification> GetHistory()
{
return _aumid != null ? _history.GetHistory(_aumid) : _history.GetHistory();
}
/// <summary>
/// Removes an individual toast, with the specified tag label, from action center.
/// </summary>
/// <param name="tag">The tag label of the toast notification to be removed.</param>
public void Remove(string tag)
{
if (_aumid != null)
{
_history.Remove(tag, string.Empty, _aumid);
}
else
{
_history.Remove(tag);
}
}
/// <summary>
/// Removes a toast notification from the action using the notification's tag and group labels.
/// </summary>
/// <param name="tag">The tag label of the toast notification to be removed.</param>
/// <param name="group">The group label of the toast notification to be removed.</param>
public void Remove(string tag, string group)
{
if (_aumid != null)
{
_history.Remove(tag, group, _aumid);
}
else
{
_history.Remove(tag, group);
}
}
/// <summary>
/// Removes a group of toast notifications, identified by the specified group label, from action center.
/// </summary>
/// <param name="group">The group label of the toast notifications to be removed.</param>
public void RemoveGroup(string group)
{
if (_aumid != null)
{
_history.RemoveGroup(group, _aumid);
}
else
{
_history.RemoveGroup(group);
}
}
}
}

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

@ -0,0 +1,209 @@
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Windows.UI.Notifications;
namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Helper for .NET Framework applications to display toast notifications and respond to toast events
/// </summary>
public class DesktopNotificationManagerCompat
{
/// <summary>
/// A constant that is used as the launch arg when your EXE is launched from a toast notification.
/// </summary>
public const string ToastActivatedLaunchArg = "-ToastActivated";
private static bool _registeredAumidAndComServer;
private static string _aumid;
private static bool _registeredActivator;
/// <summary>
/// If not running under the Desktop Bridge, you must call this method to register your AUMID with the Compat library and to
/// register your COM CLSID and EXE in LocalServer32 registry. Feel free to call this regardless, and we will no-op if running
/// under Desktop Bridge. Call this upon application startup, before calling any other APIs.
/// </summary>
/// <typeparam name="T">Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class.</typeparam>
/// <param name="aumid">An AUMID that uniquely identifies your application.</param>
public static void RegisterAumidAndComServer<T>(string aumid)
where T : NotificationActivator
{
if (string.IsNullOrWhiteSpace(aumid))
{
throw new ArgumentException("You must provide an AUMID.", nameof(aumid));
}
// If running as Desktop Bridge
if (DesktopBridgeHelpers.IsRunningAsUwp())
{
// Clear the AUMID since Desktop Bridge doesn't use it, and then we're done.
// Desktop Bridge apps are registered with platform through their manifest.
// Their LocalServer32 key is also registered through their manifest.
_aumid = null;
_registeredAumidAndComServer = true;
return;
}
_aumid = aumid;
string exePath = Process.GetCurrentProcess().MainModule.FileName;
RegisterComServer<T>(exePath);
_registeredAumidAndComServer = true;
}
private static void RegisterComServer<T>(string exePath)
where T : NotificationActivator
{
// We register the EXE to start up when the notification is activated
string regString = string.Format("SOFTWARE\\Classes\\CLSID\\{{{0}}}\\LocalServer32", typeof(T).GUID);
var key = Microsoft.Win32.Registry.CurrentUser.CreateSubKey(regString);
// Include a flag so we know this was a toast activation and should wait for COM to process
// We also wrap EXE path in quotes for extra security
key.SetValue(null, '"' + exePath + '"' + " " + ToastActivatedLaunchArg);
}
/// <summary>
/// Registers the activator type as a COM server client so that Windows can launch your activator.
/// </summary>
/// <typeparam name="T">Your implementation of NotificationActivator. Must have GUID and ComVisible attributes on class.</typeparam>
public static void RegisterActivator<T>()
where T : NotificationActivator
{
// Register type
var regService = new RegistrationServices();
regService.RegisterTypeForComClients(
typeof(T),
RegistrationClassContext.LocalServer,
RegistrationConnectionType.MultipleUse);
_registeredActivator = true;
}
/// <summary>
/// Creates a toast notifier. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer(string)"/> if you're a classic Win32 app), or this will throw an exception.
/// </summary>
/// <returns><see cref="ToastNotifier"/></returns>
public static ToastNotifier CreateToastNotifier()
{
EnsureRegistered();
if (_aumid != null)
{
// Non-Desktop Bridge
return ToastNotificationManager.CreateToastNotifier(_aumid);
}
else
{
// Desktop Bridge
return ToastNotificationManager.CreateToastNotifier();
}
}
/// <summary>
/// Gets the <see cref="DesktopNotificationHistoryCompat"/> object. You must have called <see cref="RegisterActivator{T}"/> first (and also <see cref="RegisterAumidAndComServer(string)"/> if you're a classic Win32 app), or this will throw an exception.
/// </summary>
public static DesktopNotificationHistoryCompat History
{
get
{
EnsureRegistered();
return new DesktopNotificationHistoryCompat(_aumid);
}
}
private static void EnsureRegistered()
{
// If not registered AUMID yet
if (!_registeredAumidAndComServer)
{
// Check if Desktop Bridge
if (DesktopBridgeHelpers.IsRunningAsUwp())
{
// Implicitly registered, all good!
_registeredAumidAndComServer = true;
}
else
{
// Otherwise, incorrect usage
throw new Exception("You must call RegisterAumidAndComServer first.");
}
}
// If not registered activator yet
if (!_registeredActivator)
{
// Incorrect usage
throw new Exception("You must call RegisterActivator first.");
}
}
/// <summary>
/// Gets a value indicating whether http images can be used within toasts. This is true if running under Desktop Bridge.
/// </summary>
public static bool CanUseHttpImages
{
get { return DesktopBridgeHelpers.IsRunningAsUwp(); }
}
/// <summary>
/// Code from https://github.com/qmatteoq/DesktopBridgeHelpers/edit/master/DesktopBridge.Helpers/Helpers.cs
/// </summary>
private class DesktopBridgeHelpers
{
private const long APPMODEL_ERROR_NO_PACKAGE = 15700L;
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int GetCurrentPackageFullName(ref int packageFullNameLength, StringBuilder packageFullName);
private static bool? _isRunningAsUwp;
public static bool IsRunningAsUwp()
{
if (_isRunningAsUwp == null)
{
if (IsWindows7OrLower)
{
_isRunningAsUwp = false;
}
else
{
int length = 0;
StringBuilder sb = new StringBuilder(0);
int result = GetCurrentPackageFullName(ref length, sb);
sb = new StringBuilder(length);
result = GetCurrentPackageFullName(ref length, sb);
_isRunningAsUwp = result != APPMODEL_ERROR_NO_PACKAGE;
}
}
return _isRunningAsUwp.Value;
}
private static bool IsWindows7OrLower
{
get
{
int versionMajor = Environment.OSVersion.Version.Major;
int versionMinor = Environment.OSVersion.Version.Minor;
double version = versionMajor + ((double)versionMinor / 10);
return version <= 6.1;
}
}
}
}
}

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

@ -0,0 +1,80 @@
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Windows.UI.Notifications;
namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Apps must implement this activator to handle notification activation.
/// </summary>
public abstract class NotificationActivator : NotificationActivator.INotificationActivationCallback
{
/// <inheritdoc/>
public void Activate(string appUserModelId, string invokedArgs, NOTIFICATION_USER_INPUT_DATA[] data, uint dataCount)
{
OnActivated(invokedArgs, new NotificationUserInput(data), appUserModelId);
}
/// <summary>
/// This method will be called when the user clicks on a foreground or background activation on a toast. Parent app must implement this method.
/// </summary>
/// <param name="arguments">The arguments from the original notification. This is either the launch argument if the user clicked the body of your toast, or the arguments from a button on your toast.</param>
/// <param name="userInput">Text and selection values that the user entered in your toast.</param>
/// <param name="appUserModelId">Your AUMID.</param>
public abstract void OnActivated(string arguments, NotificationUserInput userInput, string appUserModelId);
/// <summary>
/// A single user input key/value pair.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
[Serializable]
public struct NOTIFICATION_USER_INPUT_DATA
{
/// <summary>
/// The key of the user input.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string Key;
/// <summary>
/// The value of the user input.
/// </summary>
[MarshalAs(UnmanagedType.LPWStr)]
public string Value;
}
/// <summary>
/// The COM callback that is triggered when your notification is clicked.
/// </summary>
[ComImport]
[Guid("53E31837-6600-4A81-9395-75CFFE746F94")]
[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface INotificationActivationCallback
{
/// <summary>
/// The method called when your notification is clicked.
/// </summary>
/// <param name="appUserModelId">The app id of the app that sent the toast.</param>
/// <param name="invokedArgs">The activation arguments from the toast.</param>
/// <param name="data">The user input from the toast.</param>
/// <param name="dataCount">The number of user inputs.</param>
void Activate(
[In, MarshalAs(UnmanagedType.LPWStr)]
string appUserModelId,
[In, MarshalAs(UnmanagedType.LPWStr)]
string invokedArgs, [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] NOTIFICATION_USER_INPUT_DATA[] data,
[In, MarshalAs(UnmanagedType.U4)]
uint dataCount);
}
}
}

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

@ -0,0 +1,95 @@
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using Windows.UI.Notifications;
namespace Microsoft.Toolkit.Uwp.Notifications
{
/// <summary>
/// Text and selection values that the user entered on your notification. The Key is the ID of the input, and the Value is what the user entered.
/// </summary>
public class NotificationUserInput : IReadOnlyDictionary<string, string>
{
private NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] _data;
internal NotificationUserInput(NotificationActivator.NOTIFICATION_USER_INPUT_DATA[] data)
{
_data = data;
}
/// <summary>
/// Gets the value of an input with the given key.
/// </summary>
/// <param name="key">The key of the inpupt.</param>
/// <returns>The value of the input.</returns>
public string this[string key] => _data.First(i => i.Key == key).Value;
/// <summary>
/// Gets all the keys of the inputs.
/// </summary>
public IEnumerable<string> Keys => _data.Select(i => i.Key);
/// <summary>
/// Gets all the values of the inputs.
/// </summary>
public IEnumerable<string> Values => _data.Select(i => i.Value);
/// <summary>
/// Gets how many inputs there were.
/// </summary>
public int Count => _data.Length;
/// <summary>
/// Checks whether any inpupts have the given key.
/// </summary>
/// <param name="key">The key to look for.</param>
/// <returns>A boolean representing whether any inputs have the given key.</returns>
public bool ContainsKey(string key)
{
return _data.Any(i => i.Key == key);
}
/// <summary>
/// Gets an enumerator of the inputs.
/// </summary>
/// <returns>An enumerator of the inputs.</returns>
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
{
return _data.Select(i => new KeyValuePair<string, string>(i.Key, i.Value)).GetEnumerator();
}
/// <summary>
/// Tries to get the input value for the given key.
/// </summary>
/// <param name="key">The key of the input to look for.</param>
/// <param name="value">The value of the input.</param>
/// <returns>True if found an input with the specified key, else false.</returns>
public bool TryGetValue(string key, out string value)
{
foreach (var item in _data)
{
if (item.Key == key)
{
value = item.Value;
return true;
}
}
value = null;
return false;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

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

@ -1,28 +1,46 @@
<Project Sdk="MSBuild.Sdk.Extras">
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>netstandard1.4;uap10.0;native</TargetFrameworks>
<TargetFrameworks>netstandard1.4;uap10.0;native;net461</TargetFrameworks>
<DefineConstants>$(DefineConstants);NETFX_CORE</DefineConstants>
<Title>Windows Community Toolkit Notifications</Title>
<Description>Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense, instead of directly using XML.
Supports adaptive tiles and adaptive/interactive toasts for Windows 10. It is part of the Windows Community Toolkit. Supports C# and C++ UWP project types (see Microsoft.Toolkit.Uwp.Notifications.JavaScript for the JS version). Also works with C# portable class libraries and non-UWP C# projects like server projects.</Description>
<Description>
Generate tile, toast, and badge notifications for Windows 10 via code, with the help of IntelliSense.
Adds Support for adaptive tiles and adaptive/interactive toasts for Windows 10. It is part of the Windows Community Toolkit.
Supports C# and C++ UWP project types (see Microsoft.Toolkit.Uwp.Notifications.JavaScript for the JS version).
Also works with C# portable class libraries and non-UWP C# projects like server projects.
This project contains outputs for netstandard1.4, uap10.0 and native for WinRT.
</Description>
<PackageTags>notifications win10 windows 10 tile tiles toast toasts badge xml uwp c# csharp c++</PackageTags>
<ExtrasImplicitPlatformPackageIsPrivate Condition=" '$(TargetFramework)' == 'native' ">true</ExtrasImplicitPlatformPackageIsPrivate>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'uap10.0' or '$(TargetFramework)' == 'native' ">
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="6.1.5" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'native' ">
<PackageReference Update="Microsoft.NETCore.UniversalWindowsPlatform" PrivateAssets="all" />
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform" Version="$(ExtrasUwpMetaPackageVersion)" PrivateAssets="all" IsImplicitlyDefined="true" />
</ItemGroup>
<ItemGroup>
<None Include="Microsoft.Toolkit.Uwp.Notifications.targets" Pack="true" PackagePath="build\native" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
</ItemGroup>
<ItemGroup Condition="!('$(TargetFramework)'=='net461')">
<Compile Remove="DesktopNotificationManager\**\*" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net461'">
<Reference Include="System" />
<Reference Include="System.Runtime" />
<Reference Include="Windows">
<HintPath Condition="Exists('$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\$(TargetPlatformVersion)\Windows.winmd')">$(MSBuildProgramFiles32)\Windows Kits\10\UnionMetadata\$(TargetPlatformVersion)\Windows.winmd</HintPath>
<IsWinMDFile>true</IsWinMDFile>
<Private>False</Private>
</Reference>
</ItemGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'native'">
<OutputType>winmdobj</OutputType>
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
@ -34,7 +52,7 @@ Supports adaptive tiles and adaptive/interactive toasts for Windows 10. It is pa
<CopyLocalLockFileAssemblies Condition="'$(CopyLocalLockFileAssemblies)' == ''">false</CopyLocalLockFileAssemblies>
<TargetFrameworkIdentifier>.NETCore</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v5.0</TargetFrameworkVersion>
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v15.0\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
<LanguageTargets>$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v16.0\Microsoft.Windows.UI.Xaml.CSharp.targets</LanguageTargets>
<!-- Need to override the built-in implicit defines for UAP or it'll be NETCORE5_0 -->
<!-- this makes it UAP10_0_10240_0 to match the rest -->

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

@ -0,0 +1,163 @@
// 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.Linq;
using System.Text;
namespace Microsoft.Toolkit.Uwp.Notifications
{
#if !WINRT
#pragma warning disable SA1008
#pragma warning disable SA1009
/// <summary>
/// Builder class used to create <see cref="TileContent"/>
/// </summary>
public partial class TileContentBuilder
{
/// <summary>
/// Helper method for creating a tile notification content for using Contact tile template.
/// </summary>
/// <param name="contactImageUri">Source for the contact picture</param>
/// <param name="contactName">Name of the contact</param>
/// <param name="contactImageAltText">A description of the contact image, for users of assistive technologies.</param>
/// <param name="contactImageAddImageQuery">Indicating whether Windows should append a query string to the image URI supplied in the Tile notification.</param>
/// <param name="textLanguage">Gets or sets the target locale of the XML payload, specified as a BCP-47 language tags such as "en-US" or "fr-FR". The locale specified here overrides any other specified locale, such as that in binding or visual.</param>
/// <returns>An instance of <see cref="TileBindingContentContact"/> represent a payload of a tile notification.</returns>
public static TileBindingContentContact CreateContactTileContent(Uri contactImageUri, string contactName, string contactImageAltText = default(string), bool? contactImageAddImageQuery = default(bool?), string textLanguage = default(string))
{
var contactTileContent = new TileBindingContentContact();
contactTileContent.Image = CreateTileBasicImage(contactImageUri, contactImageAltText, contactImageAddImageQuery);
contactTileContent.Text = new TileBasicText();
contactTileContent.Text.Text = contactName;
if (textLanguage != default(string))
{
contactTileContent.Text.Lang = textLanguage;
}
return contactTileContent;
}
/// <summary>
/// Helper method for creating a tile notification content for using Iconic tile template.
/// </summary>
/// <param name="iconImageUri">Source of the icon image.</param>
/// <param name="iconImageAltText">A description of the icon image, for users of assistive technologies.</param>
/// <param name="iconImageAddImageQuery">Indicating whether Windows should append a query string to the image URI supplied in the Tile notification.</param>
/// <returns>An instance of <see cref="TileBindingContentIconic"/> represent a payload of a tile notification.</returns>
public static TileBindingContentIconic CreateIconicTileContent(Uri iconImageUri, string iconImageAltText = default(string), bool? iconImageAddImageQuery = default(bool?))
{
var iconicTileContent = new TileBindingContentIconic();
iconicTileContent.Icon = CreateTileBasicImage(iconImageUri, iconImageAltText, iconImageAddImageQuery);
return iconicTileContent;
}
/// <summary>
/// Helper method for creating a tile notification content for using People tile template.
/// </summary>
/// <param name="peoplePictureSources">Sources of pictures that will be used on the people tile.</param>
/// <returns>An instance of <see cref="TileBindingContentPeople"/> represent a payload of a tile notification.</returns>
public static TileBindingContentPeople CreatePeopleTileContent(params Uri[] peoplePictureSources)
{
IEnumerable<TileBasicImage> images = peoplePictureSources.Select(u => CreateTileBasicImage(u, default(string), default(bool?)));
return CreatePeopleTileContent(images);
}
/// <summary>
/// Helper method for creating a tile notification content for using People tile template.
/// </summary>
/// <param name="peoplePictures">Sources of pictures with description and image query indicator that will be used on the people tile.</param>
/// <returns>An instance of <see cref="TileBindingContentPeople"/> represent a payload of a tile notification.</returns>
public static TileBindingContentPeople CreatePeopleTileContent(params (Uri source, string imageAltText, bool? addImageQuery)[] peoplePictures)
{
IEnumerable<TileBasicImage> images = peoplePictures.Select(t => CreateTileBasicImage(t.source, t.imageAltText, t.addImageQuery));
return CreatePeopleTileContent(images);
}
/// <summary>
/// Helper method for creating a tile notification content for using People tile template.
/// </summary>
/// <param name="peoplePictures">Pictures that will be used on the people tile.</param>
/// <returns>An instance of <see cref="TileBindingContentPeople"/> represent a payload of a tile notification.</returns>
public static TileBindingContentPeople CreatePeopleTileContent(IEnumerable<TileBasicImage> peoplePictures)
{
var peopleTileContent = new TileBindingContentPeople();
foreach (var image in peoplePictures)
{
peopleTileContent.Images.Add(image);
}
return peopleTileContent;
}
/// <summary>
/// Helper method for creating a tile notification content for using Photos tile template.
/// </summary>
/// <param name="photoSources">Sources of pictures that will be used on the photos tile.</param>
/// <returns>An instance of <see cref="TileBindingContentPhotos"/> represent a payload of a tile notification.</returns>
public static TileBindingContentPhotos CreatePhotosTileContent(params Uri[] photoSources)
{
IEnumerable<TileBasicImage> images = photoSources.Select(u => CreateTileBasicImage(u, default(string), default(bool?)));
return CreatePhotosTileContent(images);
}
/// <summary>
/// Helper method for creating a tile notification content for using Photos tile template.
/// </summary>
/// <param name="photos">Sources of pictures with description and addImageQuery indicator that will be used for the photos tile.</param>
/// <returns>An instance of <see cref="TileBindingContentPhotos"/> represent a payload of a tile notification.</returns>
public static TileBindingContentPhotos CreatePhotosTileContent(params (Uri source, string imageAltText, bool? addImageQuery)[] photos)
{
IEnumerable<TileBasicImage> images = photos.Select(t => CreateTileBasicImage(t.source, t.imageAltText, t.addImageQuery));
return CreatePhotosTileContent(images);
}
/// <summary>
/// Helper method for creating a tile notification content for using Photos tile template.
/// </summary>
/// <param name="photos">Pictures that will be used for the photos tile.</param>
/// <returns>An instance of <see cref="TileBindingContentPhotos"/> represent a payload of a tile notification.</returns>
public static TileBindingContentPhotos CreatePhotosTileContent(IEnumerable<TileBasicImage> photos)
{
var photoTileContent = new TileBindingContentPhotos();
foreach (var image in photos)
{
photoTileContent.Images.Add(image);
}
return photoTileContent;
}
private static TileBasicImage CreateTileBasicImage(Uri imageUri, string imageAltText, bool? addImageQuery)
{
var tileImage = new TileBasicImage();
tileImage.Source = imageUri.OriginalString;
if (imageAltText != default(string))
{
tileImage.AlternateText = imageAltText;
}
if (addImageQuery != default(bool?))
{
tileImage.AddImageQuery = addImageQuery;
}
return tileImage;
}
}
#pragma warning restore SA1008
#pragma warning restore SA1009
#endif
}

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

@ -0,0 +1,531 @@
// 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;
namespace Microsoft.Toolkit.Uwp.Notifications
{
#if !WINRT
/// <summary>
/// Builder class used to create <see cref="TileContent"/>
/// </summary>
public partial class TileContentBuilder
{
/// <summary>
/// Flag used to create all tile size (Small , Medium, Large and Wide)
/// </summary>
public const TileSize AllSize = TileSize.Small | TileSize.Medium | TileSize.Large | TileSize.Wide;
/// <summary>
/// Gets internal instance of <see cref="TileContent"/>. This is equivalent to the call to <see cref="TileContentBuilder.GetTileContent"/>.
/// </summary>
public TileContent Content
{
get; private set;
}
private TileVisual Visual
{
get
{
if (Content.Visual == null)
{
Content.Visual = new TileVisual();
}
return Content.Visual;
}
}
private TileBinding SmallTile
{
get
{
return Visual.TileSmall;
}
set
{
Visual.TileSmall = value;
}
}
private TileBinding MediumTile
{
get
{
return Visual.TileMedium;
}
set
{
Visual.TileMedium = value;
}
}
private TileBinding WideTile
{
get
{
return Visual.TileWide;
}
set
{
Visual.TileWide = value;
}
}
private TileBinding LargeTile
{
get
{
return Visual.TileLarge;
}
set
{
Visual.TileLarge = value;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="TileContentBuilder"/> class.
/// </summary>
public TileContentBuilder()
{
Content = new TileContent();
}
/// <summary>
/// Add a tile layout size that the notification will be displayed on.
/// </summary>
/// <param name="size">The size of tile that the notification will be displayed on.</param>
/// <param name="tileContent">Specialized tile content. Use for special tile template. Default to NULL.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder AddTile(TileSize size, ITileBindingContent tileContent = null)
{
if (size.HasFlag(TileSize.Small))
{
SmallTile = new TileBinding();
SmallTile.Content = tileContent ?? new TileBindingContentAdaptive();
}
if (size.HasFlag(TileSize.Medium))
{
MediumTile = new TileBinding();
MediumTile.Content = tileContent ?? new TileBindingContentAdaptive();
}
if (size.HasFlag(TileSize.Wide))
{
WideTile = new TileBinding();
WideTile.Content = tileContent ?? new TileBindingContentAdaptive();
}
if (size.HasFlag(TileSize.Large))
{
LargeTile = new TileBinding();
LargeTile.Content = tileContent ?? new TileBindingContentAdaptive();
}
return this;
}
/// <summary>
/// Set how the tile notification should display the application branding.
/// </summary>
/// <param name="branding">How branding should appear on the tile</param>
/// <param name="size">The tile size that the <paramref name="branding"/> parameter should be applied to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetBranding(TileBranding branding, TileSize size = AllSize)
{
if (size == AllSize)
{
// Set on visual.
Visual.Branding = branding;
}
else
{
if (size.HasFlag(TileSize.Small) && SmallTile != null)
{
SmallTile.Branding = branding;
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null)
{
MediumTile.Branding = branding;
}
if (size.HasFlag(TileSize.Wide) && WideTile != null)
{
WideTile.Branding = branding;
}
if (size.HasFlag(TileSize.Large) && LargeTile != null)
{
LargeTile.Branding = branding;
}
}
return this;
}
/// <summary>
/// Set the name that will be used to override the application's name on the tile notification.
/// </summary>
/// <param name="displayName">Custom name to display on the tile in place of the application's name</param>
/// <param name="size">The tile size that <paramref name="displayName"/> parameter should be applied to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetDisplayName(string displayName, TileSize size = AllSize)
{
if (size == AllSize)
{
// Set on visual.
Visual.DisplayName = displayName;
}
else
{
if (size.HasFlag(TileSize.Small) && SmallTile != null)
{
SmallTile.DisplayName = displayName;
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null)
{
MediumTile.DisplayName = displayName;
}
if (size.HasFlag(TileSize.Wide) && WideTile != null)
{
WideTile.DisplayName = displayName;
}
if (size.HasFlag(TileSize.Large) && LargeTile != null)
{
LargeTile.DisplayName = displayName;
}
}
return this;
}
/// <summary>
/// Set the optional background image that stays behind the tile notification.
/// </summary>
/// <param name="imageUri">Source of the background image</param>
/// <param name="size">The tile size that the background image should be applied to. Default to all currently supported tile size.</param>
/// <param name="alternateText">Description of the background image, for user of assistance technology</param>
/// <param name="addImageQuery">
/// Indicating whether Windows should append a query string to the image URI supplied in the Tile notification.
/// Use this attribute if your server hosts images and can handle query strings, either by retrieving an image variant based on the query strings or by ignoring the query string and returning the image as specified without the query string.
/// This query string specifies scale, contrast setting, and language.
/// </param>
/// <param name="hintOverlay">The opacity of the black overlay on the background image.</param>
/// <param name="hintCrop">Desired cropping of the image.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetBackgroundImage(Uri imageUri, TileSize size = AllSize, string alternateText = default(string), bool? addImageQuery = default(bool?), int? hintOverlay = default(int?), TileBackgroundImageCrop hintCrop = TileBackgroundImageCrop.Default)
{
TileBackgroundImage backgroundImage = new TileBackgroundImage();
backgroundImage.Source = imageUri.OriginalString;
backgroundImage.HintCrop = hintCrop;
if (alternateText != default(string))
{
backgroundImage.AlternateText = alternateText;
}
if (addImageQuery != default(bool?))
{
backgroundImage.AddImageQuery = addImageQuery;
}
if (hintOverlay != default(int?))
{
backgroundImage.HintOverlay = hintOverlay;
}
return SetBackgroundImage(backgroundImage, size);
}
/// <summary>
/// Set the optional background image that stays behind the tile notification.
/// </summary>
/// <param name="backgroundImage">An instance of <see cref="TileBackgroundImage"/> as the background image for the tile.</param>
/// <param name="size">The tile size that the background image should be applied to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetBackgroundImage(TileBackgroundImage backgroundImage, TileSize size = AllSize)
{
// Set to any available tile at the moment of calling.
if (size.HasFlag(TileSize.Small) && SmallTile != null)
{
GetAdaptiveTileContent(SmallTile).BackgroundImage = backgroundImage;
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null)
{
GetAdaptiveTileContent(MediumTile).BackgroundImage = backgroundImage;
}
if (size.HasFlag(TileSize.Wide) && WideTile != null)
{
GetAdaptiveTileContent(WideTile).BackgroundImage = backgroundImage;
}
if (size.HasFlag(TileSize.Large) && LargeTile != null)
{
GetAdaptiveTileContent(LargeTile).BackgroundImage = backgroundImage;
}
return this;
}
/// <summary>
/// Set the Tile's Peek Image that animate from the top of the tile notification.
/// </summary>
/// <param name="imageUri">Source of the peek image</param>
/// <param name="size">The tile size that the peek image should be applied to. Default to all currently supported tile size.</param>
/// <param name="alternateText">Description of the peek image, for user of assistance technology</param>
/// <param name="addImageQuery">
/// Indicating whether Windows should append a query string to the image URI supplied in the Tile notification.
/// Use this attribute if your server hosts images and can handle query strings, either by retrieving an image variant based on the query strings or by ignoring the query string and returning the image as specified without the query string.
/// This query string specifies scale, contrast setting, and language.
/// </param>
/// <param name="hintOverlay">The opacity of the black overlay on the peek image.</param>
/// <param name="hintCrop">Desired cropping of the image.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetPeekImage(Uri imageUri, TileSize size = AllSize, string alternateText = default(string), bool? addImageQuery = default(bool?), int? hintOverlay = default(int?), TilePeekImageCrop hintCrop = TilePeekImageCrop.Default)
{
TilePeekImage peekImage = new TilePeekImage();
peekImage.Source = imageUri.OriginalString;
peekImage.HintCrop = hintCrop;
if (alternateText != default(string))
{
peekImage.AlternateText = alternateText;
}
if (addImageQuery != default(bool?))
{
peekImage.AddImageQuery = addImageQuery;
}
if (hintOverlay != default(int?))
{
peekImage.HintOverlay = hintOverlay;
}
return SetPeekImage(peekImage, size);
}
/// <summary>
/// Set the Tile's Peek Image that animate from the top of the tile notification.
/// </summary>
/// <param name="peekImage">An instance of <see cref="TilePeekImage"/> for the Tile's peek image </param>
/// <param name="size">The tile size that the peek image should be applied to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetPeekImage(TilePeekImage peekImage, TileSize size = AllSize)
{
// Set to any available tile at the moment of calling.
if (size.HasFlag(TileSize.Small) && SmallTile != null)
{
GetAdaptiveTileContent(SmallTile).PeekImage = peekImage;
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null)
{
GetAdaptiveTileContent(MediumTile).PeekImage = peekImage;
}
if (size.HasFlag(TileSize.Wide) && WideTile != null)
{
GetAdaptiveTileContent(WideTile).PeekImage = peekImage;
}
if (size.HasFlag(TileSize.Large) && LargeTile != null)
{
GetAdaptiveTileContent(LargeTile).PeekImage = peekImage;
}
return this;
}
/// <summary>
/// Set the text stacking (vertical alignment) of the entire binding element.
/// </summary>
/// <param name="textStacking">Text Stacking Option</param>
/// <param name="size">The tile size that the peek image should be applied to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetTextStacking(TileTextStacking textStacking, TileSize size = AllSize)
{
// Set to any available tile at the moment of calling.
if (size.HasFlag(TileSize.Small) && SmallTile != null)
{
GetAdaptiveTileContent(SmallTile).TextStacking = textStacking;
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null)
{
GetAdaptiveTileContent(MediumTile).TextStacking = textStacking;
}
if (size.HasFlag(TileSize.Wide) && WideTile != null)
{
GetAdaptiveTileContent(WideTile).TextStacking = textStacking;
}
if (size.HasFlag(TileSize.Large) && LargeTile != null)
{
GetAdaptiveTileContent(LargeTile).TextStacking = textStacking;
}
return this;
}
/// <summary>
/// Set the tile's activation arguments for chasable tile notification.
/// </summary>
/// <param name="args">App-Defined custom arguments that will be passed in when the user click on the tile when this tile notification is being displayed.</param>
/// <param name="size">The tile size that the custom argument should be applied to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder SetActivationArgument(string args, TileSize size = AllSize)
{
if (size == AllSize)
{
Visual.Arguments = args;
}
else
{
if (size.HasFlag(TileSize.Small) && SmallTile != null)
{
SmallTile.Arguments = args;
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null)
{
MediumTile.Arguments = args;
}
if (size.HasFlag(TileSize.Wide) && WideTile != null)
{
WideTile.Arguments = args;
}
if (size.HasFlag(TileSize.Large) && LargeTile != null)
{
LargeTile.Arguments = args;
}
}
return this;
}
/// <summary>
/// Add a custom text that will appear on the tile notification.
/// </summary>
/// <param name="text">Custom text to display on the tile.</param>
/// <param name="size">The tile size that the custom text would be added to. Default to all currently supported tile size.</param>
/// <param name="hintStyle">Style that controls the text's font size, weight, and opacity.</param>
/// <param name="hintWrap">Indicating whether text wrapping is enabled. For Tiles, this is false by default.</param>
/// <param name="hintMaxLines">The maximum number of lines the text element is allowed to display. For Tiles, this is infinity by default</param>
/// <param name="hintMinLines">The minimum number of lines the text element must display.</param>
/// <param name="hintAlign">The horizontal alignment of the text</param>
/// <param name="language">
/// The target locale of the XML payload, specified as a BCP-47 language tags such as "en-US" or "fr-FR". The locale specified here overrides any other specified locale, such as that in binding or visual.
/// </param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
public TileContentBuilder AddText(string text, TileSize size = AllSize, AdaptiveTextStyle? hintStyle = null, bool? hintWrap = default(bool?), int? hintMaxLines = default(int?), int? hintMinLines = default(int?), AdaptiveTextAlign? hintAlign = null, string language = default(string))
{
// Create the adaptive text.
AdaptiveText adaptive = new AdaptiveText()
{
Text = text
};
if (hintStyle != null)
{
adaptive.HintStyle = hintStyle.Value;
}
if (hintAlign != null)
{
adaptive.HintAlign = hintAlign.Value;
}
if (hintWrap != default(bool?))
{
adaptive.HintWrap = hintWrap;
}
if (hintMaxLines != default(int?))
{
adaptive.HintMaxLines = hintMaxLines;
}
if (hintMinLines != default(int?) && hintMinLines > 0)
{
adaptive.HintMinLines = hintMinLines;
}
if (language != default(string))
{
adaptive.Language = language;
}
// Add to the tile content
return AddAdaptiveTileVisualChild(adaptive, size);
}
/// <summary>
/// Add an adaptive child to the tile notification.
/// </summary>
/// <param name="child">An adaptive child to add</param>
/// <param name="size">Tile size that the adaptive child should be added to. Default to all currently supported tile size.</param>
/// <returns>The current instance of <see cref="TileContentBuilder"/></returns>
/// <remarks>
/// This can be used to add Group and Subgroup to the tile.
/// </remarks>
public TileContentBuilder AddAdaptiveTileVisualChild(ITileBindingContentAdaptiveChild child, TileSize size = AllSize)
{
if (size.HasFlag(TileSize.Small) && SmallTile != null && GetAdaptiveTileContent(SmallTile) != null)
{
GetAdaptiveTileContent(SmallTile).Children.Add(child);
}
if (size.HasFlag(TileSize.Medium) && MediumTile != null && GetAdaptiveTileContent(MediumTile) != null)
{
GetAdaptiveTileContent(MediumTile).Children.Add(child);
}
if (size.HasFlag(TileSize.Wide) && WideTile != null && GetAdaptiveTileContent(MediumTile) != null)
{
GetAdaptiveTileContent(WideTile).Children.Add(child);
}
if (size.HasFlag(TileSize.Large) && LargeTile != null && GetAdaptiveTileContent(LargeTile) != null)
{
GetAdaptiveTileContent(LargeTile).Children.Add(child);
}
return this;
}
/// <summary>
/// Get the instance of <see cref="TileContent"/> that has been built by the builder with specified configuration so far.
/// </summary>
/// <returns>An instance of <see cref="TileContent"/> that can be used to create tile notification.</returns>
public TileContent GetTileContent()
{
return Content;
}
private TileBindingContentAdaptive GetAdaptiveTileContent(TileBinding binding)
{
return binding.Content as TileBindingContentAdaptive;
}
}
#endif
}

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

@ -2,13 +2,34 @@
// 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;
namespace Microsoft.Toolkit.Uwp.Notifications
{
internal enum TileSize
/// <summary>
/// Represent the all tile sizes that are available.
/// </summary>
[Flags]
public enum TileSize
{
Small,
Medium,
Wide,
Large
/// <summary>
/// Small Square Tile
/// </summary>
Small = 0,
/// <summary>
/// Medium Square Tile
/// </summary>
Medium = 1,
/// <summary>
/// Wide Rectangle Tile
/// </summary>
Wide = 2,
/// <summary>
/// Large Square Tile
/// </summary>
Large = 4
}
}

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

@ -0,0 +1,223 @@
// 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.Linq;
using System.Text;
namespace Microsoft.Toolkit.Uwp.Notifications
{
#if !WINRT
#pragma warning disable SA1008
#pragma warning disable SA1009
/// <summary>
/// Builder class used to create <see cref="ToastContent"/>
/// </summary>
public partial class ToastContentBuilder
{
private IToastActions Actions
{
get
{
if (Content.Actions == null)
{
Content.Actions = new ToastActionsCustom();
}
return Content.Actions;
}
}
private IList<IToastButton> ButtonList
{
get
{
return ((ToastActionsCustom)Actions).Buttons;
}
}
private IList<IToastInput> InputList
{
get
{
return ((ToastActionsCustom)Actions).Inputs;
}
}
/// <summary>
/// Add a button to the current toast.
/// </summary>
/// <param name="content">Text to display on the button.</param>
/// <param name="activationType">Type of activation this button will use when clicked. Defaults to Foreground.</param>
/// <param name="arguments">App-defined string of arguments that the app can later retrieve once it is activated when the user clicks the button.</param>
/// <param name="imageUri">Optional image icon for the button to display (required for buttons adjacent to inputs like quick reply).</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddButton(string content, ToastActivationType activationType, string arguments, Uri imageUri = default(Uri))
{
// Add new button
ToastButton button = new ToastButton(content, arguments)
{
ActivationType = activationType
};
if (imageUri != default(Uri))
{
button.ImageUri = imageUri.OriginalString;
}
return AddButton(button);
}
/// <summary>
/// Add a button to the current toast.
/// </summary>
/// <param name="button">An instance of class that implement <see cref="IToastButton"/> for the button that will be used on the toast.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddButton(IToastButton button)
{
// List has max 5 buttons
if (ButtonList.Count == 5)
{
throw new InvalidOperationException("A toast can't have more than 5 buttons");
}
ButtonList.Add(button);
return this;
}
/// <summary>
/// Add an button to the toast that will be display to the right of the input text box, achieving a quick reply scenario.
/// </summary>
/// <param name="textBoxId">ID of an existing <see cref="ToastTextBox"/> in order to have this button display to the right of the input, achieving a quick reply scenario.</param>
/// <param name="content">Text to display on the button.</param>
/// <param name="activationType">Type of activation this button will use when clicked. Defaults to Foreground.</param>
/// <param name="arguments">App-defined string of arguments that the app can later retrieve once it is activated when the user clicks the button.</param>
/// <param name="imageUri">An optional image icon for the button to display (required for buttons adjacent to inputs like quick reply)</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddButton(string textBoxId, string content, ToastActivationType activationType, string arguments, Uri imageUri = default(Uri))
{
// Add new button
ToastButton button = new ToastButton(content, arguments)
{
ActivationType = activationType,
TextBoxId = textBoxId
};
if (imageUri != default(Uri))
{
button.ImageUri = imageUri.OriginalString;
}
return AddButton(button);
}
/// <summary>
/// Add an input text box that the user can type into.
/// </summary>
/// <param name="id">Required ID property so that developers can retrieve user input once the app is activated.</param>
/// <param name="placeHolderContent">Placeholder text to be displayed on the text box when the user hasn't typed any text yet.</param>
/// <param name="title">Title text to display above the text box.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddInputTextBox(string id, string placeHolderContent = default(string), string title = default(string))
{
var inputTextBox = new ToastTextBox(id);
if (placeHolderContent != default(string))
{
inputTextBox.PlaceholderContent = placeHolderContent;
}
if (title != default(string))
{
inputTextBox.Title = title;
}
return AddToastInput(inputTextBox);
}
/// <summary>
/// Add a combo box / drop-down menu that contain options for user to select.
/// </summary>
/// <param name="id">Required ID property used so that developers can retrieve user input once the app is activated.</param>
/// <param name="choices">List of choices that will be available for user to select.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddComboBox(string id, params (string comboBoxItemId, string comboBoxItemContent)[] choices)
{
return AddComboBox(id, default(string), choices);
}
/// <summary>
/// Add a combo box / drop-down menu that contain options for user to select.
/// </summary>
/// <param name="id">Required ID property used so that developers can retrieve user input once the app is activated.</param>
/// <param name="defaultSelectionBoxItemId">Sets which item is selected by default, and refers to the Id property of <see cref="ToastSelectionBoxItem"/>. If you do not provide this or null, the default selection will be empty (user sees nothing).</param>
/// <param name="choices">List of choices that will be available for user to select.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddComboBox(string id, string defaultSelectionBoxItemId, params (string comboBoxItemId, string comboBoxItemContent)[] choices)
{
return AddComboBox(id, default(string), defaultSelectionBoxItemId, choices);
}
/// <summary>
/// Add a combo box / drop-down menu that contain options for user to select.
/// </summary>
/// <param name="id">Required ID property used so that developers can retrieve user input once the app is activated.</param>
/// <param name="title">Title text to display above the Combo Box.</param>
/// <param name="defaultSelectionBoxItemId">Sets which item is selected by default, and refers to the Id property of <see cref="ToastSelectionBoxItem"/>. If you do not provide this or null, the default selection will be empty (user sees nothing).</param>
/// <param name="choices">List of choices that will be available for user to select.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddComboBox(string id, string title, string defaultSelectionBoxItemId, params (string comboBoxItemId, string comboBoxItemContent)[] choices)
{
return AddComboBox(id, title, defaultSelectionBoxItemId, choices as IEnumerable<(string, string)>);
}
/// <summary>
/// Add a combo box / drop-down menu that contain options for user to select.
/// </summary>
/// <param name="id">Required ID property used so that developers can retrieve user input once the app is activated.</param>
/// <param name="title">Title text to display above the Combo Box.</param>
/// <param name="defaultSelectionBoxItemId">Sets which item is selected by default, and refers to the Id property of <see cref="ToastSelectionBoxItem"/>. If you do not provide this or null, the default selection will be empty (user sees nothing).</param>
/// <param name="choices">List of choices that will be available for user to select.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddComboBox(string id, string title, string defaultSelectionBoxItemId, IEnumerable<(string comboBoxItemId, string comboBoxItemContent)> choices)
{
var box = new ToastSelectionBox(id);
if (defaultSelectionBoxItemId != default(string))
{
box.DefaultSelectionBoxItemId = defaultSelectionBoxItemId;
}
if (title != default(string))
{
box.Title = title;
}
for (int i = 0; i < choices.Count(); i++)
{
var choice = choices.ElementAt(i);
box.Items.Add(new ToastSelectionBoxItem(choice.comboBoxItemId, choice.comboBoxItemContent));
}
return AddToastInput(box);
}
/// <summary>
/// Add an input option to the Toast.
/// </summary>
/// <param name="input">An instance of a class that impmement <see cref="IToastInput"/> that will be used on the toast.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddToastInput(IToastInput input)
{
InputList.Add(input);
return this;
}
}
#pragma warning restore SA1008
#pragma warning restore SA1009
#endif
}

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

@ -0,0 +1,424 @@
// 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.Linq;
using System.Text;
#if WINDOWS_UWP
using Windows.UI.Notifications;
#endif
namespace Microsoft.Toolkit.Uwp.Notifications
{
#if !WINRT
/// <summary>
/// Builder class used to create <see cref="ToastContent"/>
/// </summary>
public partial class ToastContentBuilder
{
private ToastVisual Visual
{
get
{
if (Content.Visual == null)
{
Content.Visual = new ToastVisual();
Content.Visual.BindingGeneric = new ToastBindingGeneric();
}
return Content.Visual;
}
}
private ToastGenericAppLogo AppLogoOverrideUri
{
get
{
return Visual.BindingGeneric.AppLogoOverride;
}
set
{
Visual.BindingGeneric.AppLogoOverride = value;
}
}
private ToastGenericAttributionText AttributionText
{
get
{
return Visual.BindingGeneric.Attribution;
}
set
{
Visual.BindingGeneric.Attribution = value;
}
}
private ToastGenericHeroImage HeroImage
{
get
{
return Visual.BindingGeneric.HeroImage;
}
set
{
Visual.BindingGeneric.HeroImage = value;
}
}
private IList<IToastBindingGenericChild> VisualChildren
{
get
{
return Visual.BindingGeneric.Children;
}
}
#if WINDOWS_UWP
/// <summary>
/// Create an instance of NotificationData that can be used to update toast that has a progress bar.
/// </summary>
/// <param name="toast">Instance of ToastContent that contain progress bars that need to be updated</param>
/// <param name="index">Index of the progress bar (0-based) that this notification data is updating in the case that toast has multiple progress bars. Default to 0.</param>
/// <param name="title">Title of the progress bar.</param>
/// <param name="value">Value of the progress bar.</param>
/// <param name="valueStringOverride">An optional string to be displayed instead of the default percentage string. If this isn't provided, something like "70%" will be displayed.</param>
/// <param name="status"> A status string, which is displayed underneath the progress bar on the left. Default to empty.</param>
/// <param name="sequence">A sequence number to prevent out-of-order updates, or assign 0 to indicate "always update".</param>
/// <returns>An instance of NotificationData that can be used to update the toast.</returns>
public static NotificationData CreateProgressBarData(ToastContent toast, int index = 0, string title = default(string), double? value = null, string valueStringOverride = default(string), string status = default(string), uint sequence = 0)
{
var progressBar = toast.Visual.BindingGeneric.Children.Where(c => c is AdaptiveProgressBar).ElementAt(index) as AdaptiveProgressBar;
if (progressBar == null)
{
throw new ArgumentException(nameof(toast), "Given toast does not have any progress bar");
}
NotificationData data = new NotificationData();
data.SequenceNumber = sequence;
if (progressBar.Title is BindableString bindableTitle && title != default(string))
{
data.Values[bindableTitle.BindingName] = title;
}
if (progressBar.Value is BindableProgressBarValue bindableProgressValue && value != null)
{
data.Values[bindableProgressValue.BindingName] = value.ToString();
}
if (progressBar.ValueStringOverride is BindableString bindableValueStringOverride && valueStringOverride != default(string))
{
data.Values[bindableValueStringOverride.BindingName] = valueStringOverride;
}
if (progressBar.Status is BindableString bindableStatus && status != default(string))
{
data.Values[bindableStatus.BindingName] = status;
}
return data;
}
#endif
/// <summary>
/// Add an Attribution Text to be displayed on the toast.
/// </summary>
/// <param name="text">Text to be displayed as Attribution Text</param>
/// <param name="language">The target locale of the XML payload, specified as a BCP-47 language tags such as "en-US" or "fr-FR".</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddAttributionText(string text, string language = default(string))
{
AttributionText = new ToastGenericAttributionText()
{
Text = text
};
if (language != default(string))
{
AttributionText.Language = language;
}
return this;
}
/// <summary>
/// Override the app logo with custom image of choice that will be displayed on the toast.
/// </summary>
/// <param name="uri">The URI of the image. Can be from your application package, application data, or the internet. Internet images must be less than 200 KB in size.</param>
/// <param name="hintCrop">Specify how the image should be cropped.</param>
/// <param name="alternateText">A description of the image, for users of assistive technologies.</param>
/// <param name="addImageQuery">A value whether Windows is allowed to append a query string to the image URI supplied in the Tile notification.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddAppLogoOverride(Uri uri, ToastGenericAppLogoCrop? hintCrop = null, string alternateText = default(string), bool? addImageQuery = default(bool?))
{
AppLogoOverrideUri = new ToastGenericAppLogo()
{
Source = uri.OriginalString
};
if (hintCrop != null)
{
AppLogoOverrideUri.HintCrop = hintCrop.Value;
}
if (alternateText != default(string))
{
AppLogoOverrideUri.AlternateText = alternateText;
}
if (addImageQuery != default(bool?))
{
AppLogoOverrideUri.AddImageQuery = addImageQuery;
}
return this;
}
/// <summary>
/// Add a hero image to the toast.
/// </summary>
/// <param name="uri">The URI of the image. Can be from your application package, application data, or the internet. Internet images must be less than 200 KB in size.</param>
/// <param name="alternateText">A description of the image, for users of assistive technologies.</param>
/// <param name="addImageQuery">A value whether Windows is allowed to append a query string to the image URI supplied in the Tile notification.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddHeroImage(Uri uri, string alternateText = default(string), bool? addImageQuery = default(bool?))
{
HeroImage = new ToastGenericHeroImage()
{
Source = uri.OriginalString
};
if (alternateText != default(string))
{
HeroImage.AlternateText = alternateText;
}
if (addImageQuery != default(bool?))
{
HeroImage.AddImageQuery = addImageQuery;
}
return this;
}
/// <summary>
/// Add an image inline with other toast content.
/// </summary>
/// <param name="uri">The URI of the image. Can be from your application package, application data, or the internet. Internet images must be less than 200 KB in size.</param>
/// <param name="alternateText">A description of the image, for users of assistive technologies.</param>
/// <param name="addImageQuery">A value whether Windows is allowed to append a query string to the image URI supplied in the Tile notification.</param>
/// <param name="hintCrop">A value whether a margin is removed. images have an 8px margin around them.</param>
/// <param name="hintRemoveMargin">the horizontal alignment of the image.This is only supported when inside an <see cref="AdaptiveSubgroup"/>.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddInlineImage(Uri uri, string alternateText = default(string), bool? addImageQuery = default(bool?), AdaptiveImageCrop? hintCrop = null, bool? hintRemoveMargin = default(bool?))
{
var inlineImage = new AdaptiveImage()
{
Source = uri.OriginalString
};
if (hintCrop != null)
{
inlineImage.HintCrop = hintCrop.Value;
}
if (alternateText != default(string))
{
inlineImage.AlternateText = alternateText;
}
if (addImageQuery != default(bool?))
{
inlineImage.AddImageQuery = addImageQuery;
}
if (hintRemoveMargin != default(bool?))
{
inlineImage.HintRemoveMargin = hintRemoveMargin;
}
return AddVisualChild(inlineImage);
}
/// <summary>
/// Add a progress bar to the toast.
/// </summary>
/// <param name="title">Title of the progress bar.</param>
/// <param name="value">Value of the progress bar. Default is 0</param>
/// <param name="isIndeterminate">Determine if the progress bar value should be indeterminate. Default to false.</param>
/// <param name="valueStringOverride">An optional string to be displayed instead of the default percentage string. If this isn't provided, something like "70%" will be displayed.</param>
/// <param name="status">A status string which is displayed underneath the progress bar. This string should reflect the status of the operation, like "Downloading..." or "Installing...". Default to empty.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
/// <remarks>More info at: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/toast-progress-bar </remarks>
public ToastContentBuilder AddProgressBar(string title = default(string), double? value = null, bool isIndeterminate = false, string valueStringOverride = default(string), string status = default(string))
{
int index = VisualChildren.Count(c => c is AdaptiveProgressBar);
var progressBar = new AdaptiveProgressBar()
{
};
if (title == default(string))
{
progressBar.Title = new BindableString($"progressBarTitle_{index}");
}
else
{
progressBar.Title = title;
}
if (isIndeterminate)
{
progressBar.Value = AdaptiveProgressBarValue.Indeterminate;
}
else if (value == null)
{
progressBar.Value = new BindableProgressBarValue($"progressValue_{index}");
}
else
{
progressBar.Value = value.Value;
}
if (valueStringOverride == default(string))
{
progressBar.ValueStringOverride = new BindableString($"progressValueString_{index}");
}
else
{
progressBar.ValueStringOverride = valueStringOverride;
}
if (status == default(string))
{
progressBar.Status = new BindableString($"progressStatus_{index}");
}
else
{
progressBar.Status = status;
}
return AddVisualChild(progressBar);
}
/// <summary>
/// Add text to the toast.
/// </summary>
/// <param name="text">Custom text to display on the tile.</param>
/// <param name="hintStyle">Style that controls the text's font size, weight, and opacity.</param>
/// <param name="hintWrap">Indicating whether text wrapping is enabled. For Tiles, this is false by default.</param>
/// <param name="hintMaxLines">The maximum number of lines the text element is allowed to display. For Tiles, this is infinity by default</param>
/// <param name="hintMinLines">The minimum number of lines the text element must display.</param>
/// <param name="hintAlign">The horizontal alignment of the text</param>
/// <param name="language">
/// The target locale of the XML payload, specified as a BCP-47 language tags such as "en-US" or "fr-FR". The locale specified here overrides any other specified locale, such as that in binding or visual.
/// </param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
/// <exception cref="InvalidOperationException">Throws when attempting to add/reserve more than 4 lines on a single toast. </exception>
/// <exception cref="ArgumentOutOfRangeException">Throws when <paramref name="hintMaxLines"/> value is larger than 2. </exception>
/// <remarks>More info at: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts#text-elements</remarks>
public ToastContentBuilder AddText(string text, AdaptiveTextStyle? hintStyle = null, bool? hintWrap = default(bool?), int? hintMaxLines = default(int?), int? hintMinLines = default(int?), AdaptiveTextAlign? hintAlign = null, string language = default(string))
{
int lineCount = GetCurrentTextLineCount();
if (GetCurrentTextLineCount() == 4)
{
// Reached maximum, we can't go further.
throw new InvalidOperationException("We have reached max lines allowed (4) per toast");
}
AdaptiveText adaptive = new AdaptiveText()
{
Text = text
};
if (hintStyle != null)
{
adaptive.HintStyle = hintStyle.Value;
}
if (hintAlign != null)
{
adaptive.HintAlign = hintAlign.Value;
}
if (hintWrap != default(bool?))
{
adaptive.HintWrap = hintWrap;
}
if (hintMaxLines != default(int?))
{
if (hintMaxLines > 2)
{
throw new ArgumentOutOfRangeException(nameof(hintMaxLines), "max line can't go more than 2 lines.");
}
else if ((lineCount + hintMaxLines) > 4)
{
throw new InvalidOperationException($"Can't exceed more than 4 lines of text per toast. Current line count : {lineCount} | Requesting line count: {lineCount + hintMaxLines}");
}
adaptive.HintMaxLines = hintMaxLines;
}
if (hintMinLines != default(int?) && hintMinLines > 0)
{
adaptive.HintMinLines = hintMinLines;
}
if (language != default(string))
{
adaptive.Language = language;
}
return AddVisualChild(adaptive);
}
/// <summary>
/// Add a visual element to the toast.
/// </summary>
/// <param name="child">An instance of a class that implement <see cref="IToastBindingGenericChild"/>.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddVisualChild(IToastBindingGenericChild child)
{
VisualChildren.Add(child);
return this;
}
private int GetCurrentTextLineCount()
{
if (!VisualChildren.Any(c => c is AdaptiveText))
{
return 0;
}
var textList = VisualChildren.Where(c => c is AdaptiveText).Select(c => c as AdaptiveText).ToList();
// First one is already the header.
// https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/adaptive-interactive-toasts#text-elements
// The default (and maximum) is up to 2 lines of text for the title, and up to 4 lines (combined) for the two additional description elements (the second and third AdaptiveText).
AdaptiveText text = textList.First();
int count = 0;
count += text.HintMaxLines ?? 2;
for (int i = 1; i < textList.Count; i++)
{
text = textList[i];
count += text.HintMaxLines ?? 1;
}
return count;
}
}
#endif
}

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

@ -0,0 +1,137 @@
// 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 Microsoft.Toolkit.Uwp.Notifications
{
#if !WINRT
/// <summary>
/// Builder class used to create <see cref="ToastContent"/>
/// </summary>
public partial class ToastContentBuilder
{
/// <summary>
/// Gets internal instance of <see cref="ToastContent"/>. This is equivalent to the call to <see cref="ToastContentBuilder.GetToastContent"/>.
/// </summary>
public ToastContent Content
{
get; private set;
}
/// <summary>
/// Initializes a new instance of the <see cref="ToastContentBuilder"/> class.
/// </summary>
public ToastContentBuilder()
{
Content = new ToastContent();
}
/// <summary>
/// Add custom time stamp on the toast to override the time display on the toast.
/// </summary>
/// <param name="dateTime">Custom Time to be displayed on the toast</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddCustomTimeStamp(DateTime dateTime)
{
Content.DisplayTimestamp = dateTime;
return this;
}
/// <summary>
/// Add a header to a toast.
/// </summary>
/// <param name="id">A developer-created identifier that uniquely identifies this header. If two notifications have the same header id, they will be displayed underneath the same header in Action Center.</param>
/// <param name="title">A title for the header.</param>
/// <param name="arguments">A developer-defined string of arguments that is returned to the app when the user clicks this header.</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
/// <remarks>More info about toast header: https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/toast-headers </remarks>
public ToastContentBuilder AddHeader(string id, string title, string arguments)
{
Content.Header = new ToastHeader(id, title, arguments);
return this;
}
/// <summary>
/// Add info that can be used by the application when the app was activated/launched by the toast.
/// </summary>
/// <param name="launchArgs">Custom app-defined launch arguments to be passed along on toast activation</param>
/// <param name="activationType">Set the activation type that will be used when the user click on this toast</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddToastActivationInfo(string launchArgs, ToastActivationType activationType)
{
Content.Launch = launchArgs;
Content.ActivationType = activationType;
return this;
}
/// <summary>
/// Sets the amount of time the Toast should display. You typically should use the
/// Scenario attribute instead, which impacts how long a Toast stays on screen.
/// </summary>
/// <param name="duration">Duration of the toast</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder SetToastDuration(ToastDuration duration)
{
Content.Duration = duration;
return this;
}
/// <summary>
/// Sets the scenario, to make the Toast behave like an alarm, reminder, or more.
/// </summary>
/// <param name="scenario">Scenario to be used for the toast's behavior</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder SetToastScenario(ToastScenario scenario)
{
Content.Scenario = scenario;
return this;
}
/// <summary>
/// Set custom audio to go along with the toast.
/// </summary>
/// <param name="src">Source to the media that will be played when the toast is pop</param>
/// <param name="loop">Indicating whether sound should repeat as long as the Toast is shown; false to play only once (default).</param>
/// <param name="silent">Indicating whether sound is muted; false to allow the Toast notification sound to play (default).</param>
/// <returns>The current instance of <see cref="ToastContentBuilder"/></returns>
public ToastContentBuilder AddAudio(Uri src, bool? loop = null, bool? silent = null)
{
if (!src.IsFile)
{
throw new ArgumentException(nameof(src), "Audio Source has to be a file.");
}
Content.Audio = new ToastAudio();
Content.Audio.Src = src;
if (loop != null)
{
Content.Audio.Loop = loop.Value;
}
if (silent != null)
{
Content.Audio.Silent = silent.Value;
}
return this;
}
/// <summary>
/// Get the instance of <see cref="ToastContent"/> that has been built by the builder with specified configuration so far.
/// </summary>
/// <returns>An instance of <see cref="ToastContent"/> that can be used to create tile notification.</returns>
public ToastContent GetToastContent()
{
return Content;
}
}
#endif
}

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

@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Title>Windows Community Toolkit UWP Platform Specific Analyzer</Title>
<Description>This standard library provides analyzer and code fixer to ensure that version / platform specific code is well guarded. It is part of the Windows Community Toolkit.</Description>
<Description>This standard library provides code analysis and code fixers (on CS and VB) to ensure that version / platform specific code is well guarded.</Description>
<PackageTags>UWP Toolkit Windows Platform Specific Analyzer</PackageTags>
<IncludeBuildOutput>false</IncludeBuildOutput>

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

@ -16,12 +16,11 @@
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PackageCertificateKeyFile>Microsoft.Toolkit.Uwp.SampleApp_TemporaryKey.pfx</PackageCertificateKeyFile>
<AppxAutoIncrementPackageRevision>True</AppxAutoIncrementPackageRevision>
<AppxBundle>Always</AppxBundle>
<AppxBundlePlatforms>x86</AppxBundlePlatforms>
<PackageCertificateThumbprint>7A086872CBF1D8A795A97B9559A3C88B3550527E</PackageCertificateThumbprint>
<Win32Resource>MiddleClickScrolling-CursorType.res</Win32Resource>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
@ -530,6 +529,9 @@
<SubType>Designer</SubType>
</Content>
<Content Include="SamplePages\Weibo Service\WeiboCode.bind" />
<Compile Include="SamplePages\ImageEx\ImageExLazyLoadingControl.xaml.cs">
<DependentUpon>ImageExLazyLoadingControl.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\OnDevice\OnDevicePage.xaml.cs">
<DependentUpon>OnDevicePage.xaml</DependentUpon>
</Compile>
@ -932,7 +934,6 @@
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
<None Include="Microsoft.Toolkit.Uwp.SampleApp_TemporaryKey.pfx" />
</ItemGroup>
<ItemGroup>
<Content Include="Properties\Default.rd.xml" />
@ -962,6 +963,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\ImageEx\ImageExLazyLoadingControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SamplePages\OnDevice\OnDevicePage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>

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

@ -71,8 +71,10 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
internal static async Task<Sample> FindAsync(string category, string name)
{
var categories = await Samples.GetCategoriesAsync();
// Replace any spaces in the category name as it's used for the host part of the URI in deep links and that can't have spaces.
return categories?
.FirstOrDefault(c => c.Name.Equals(category, StringComparison.OrdinalIgnoreCase))?
.FirstOrDefault(c => c.Name.Replace(" ", string.Empty).Equals(category, StringComparison.OrdinalIgnoreCase))?
.Samples
.FirstOrDefault(s => s.Name.Equals(name, StringComparison.OrdinalIgnoreCase));
}

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

@ -33,7 +33,8 @@
OffsetY="@[OffsetY:DoubleSlider:2.0:0.0-100.0]"
Color="@[Color:Brush:Black]"
VerticalAlignment="Center"
HorizontalAlignment="Center">
HorizontalAlignment="Center"
IsMasked="@[Is Masked:Bool:true]">
<TextBlock TextWrapping="Wrap">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. In eget sem luctus, gravida diam cursus, rutrum ipsum.
Pellentesque semper magna nec sapien ornare tincidunt. Sed pellentesque, turpis quis laoreet pellentesque, urna sapien efficitur nulla,
@ -53,7 +54,8 @@
OffsetX="@[OffsetX]"
OffsetY="@[OffsetY]"
Color="@[Color]"
Margin="20">
Margin="20"
IsMasked="@[Is Masked]">
<Polygon Points="50,0 0,50 50,50"
Stroke="BlueViolet" StrokeThickness="2" Fill="Blue" />
</controls:DropShadowPanel>
@ -63,7 +65,8 @@
OffsetX="@[OffsetX]"
OffsetY="@[OffsetY]"
Color="@[Color]"
Margin="20">
Margin="20"
IsMasked="@[Is Masked]">
<Rectangle Width="100" Height="50"
Stroke="Green" StrokeThickness="5" />
</controls:DropShadowPanel>
@ -73,13 +76,14 @@
OffsetX="@[OffsetX]"
OffsetY="@[OffsetY]"
Color="@[Color]"
Margin="20">
Margin="20"
IsMasked="@[Is Masked]">
<Polyline Points="0,0 50,50 50,0 0,50"
Stroke="Black" StrokeThickness="2" />
</controls:DropShadowPanel>
</StackPanel>
<TextBlock Style="{StaticResource TitleText}" >Images</TextBlock>
<TextBlock Style="{StaticResource TitleText}">Images</TextBlock>
<Border Style="{StaticResource DividingBorder}" />
<StackPanel Orientation="Horizontal">
@ -89,7 +93,8 @@
OffsetY="@[OffsetY]"
Color="@[Color]"
VerticalAlignment="Center"
HorizontalAlignment="Center">
HorizontalAlignment="Center"
IsMasked="@[Is Masked]">
<Image Width="200" Source="/SamplePages/DropShadowPanel/Unicorn.png" Stretch="Uniform" />
</controls:DropShadowPanel>
<controls:DropShadowPanel BlurRadius="@[BlurRadius]"
@ -98,7 +103,8 @@
OffsetY="@[OffsetY]"
Color="@[Color]"
VerticalAlignment="Center"
HorizontalAlignment="Center">
HorizontalAlignment="Center"
IsMasked="@[Is Masked]">
<Image Width="200" Source="/SamplePages/DropShadowPanel/Trex.png" Stretch="Uniform" />
</controls:DropShadowPanel>
</StackPanel>

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

@ -46,5 +46,6 @@
Style="{StaticResource BaseStyle}"/>
</StackPanel>
</ScrollViewer>
<Border x:Name="LazyLoadingControlHost" />
</Grid>
</Page>

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

@ -0,0 +1,44 @@
<UserControl x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.ImageExLazyLoadingControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<Grid Background="#80000000">
<Grid Margin="40"
Background="White">
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid Height="3000">
<Border Width="200"
Height="200"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Black"
BorderThickness="1">
<controls:ImageEx EnableLazyLoading="True"
ImageExOpened="ImageEx_ImageExOpened"
IsCacheEnabled="False"
Source="/Assets/Photos/LunchBreak.jpg" />
</Border>
</Grid>
</ScrollViewer>
<TextBlock HorizontalAlignment="Left"
VerticalAlignment="Top"
Foreground="OrangeRed"
IsHitTestVisible="False"
Text="Please scroll down to see the effect." />
<Button Width="48"
Height="48"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Background="Transparent"
BorderThickness="0"
Click="CloseButton_Click">
<SymbolIcon Symbol="Cancel" />
</Button>
</Grid>
</Grid>
</UserControl>

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

@ -0,0 +1,31 @@
// 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 Microsoft.Toolkit.Uwp.UI.Controls;
using Windows.UI.Popups;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
public sealed partial class ImageExLazyLoadingControl
{
public ImageExLazyLoadingControl()
{
InitializeComponent();
}
public event EventHandler CloseButtonClick;
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
CloseButtonClick?.Invoke(this, EventArgs.Empty);
}
private async void ImageEx_ImageExOpened(object sender, ImageExOpenedEventArgs e)
{
await new MessageDialog("Image Opened").ShowAsync();
}
}
}

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

@ -21,6 +21,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
private int imageIndex;
private StackPanel container;
private ResourceDictionary resources;
private Border lazyLoadingControlHost;
public ImageExPage()
{
@ -33,6 +34,7 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
// Need to use logical tree here as scrollviewer hasn't initialized yet even with dispatch.
container = control.FindChildByName("Container") as StackPanel;
resources = control.Resources;
lazyLoadingControlHost = control.FindChildByName("LazyLoadingControlHost") as Border;
}
private async void Load()
@ -67,6 +69,26 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
AddImage(false, false, true);
});
if (ImageExBase.IsLazyLoadingSupported)
{
SampleController.Current.RegisterNewCommand("Lazy loading sample (17763 or higher supported)", (sender, args) =>
{
var imageExLazyLoadingControl = new ImageExLazyLoadingControl();
imageExLazyLoadingControl.CloseButtonClick += (_, __) =>
{
if (lazyLoadingControlHost != null)
{
lazyLoadingControlHost.Child = null;
}
};
if (lazyLoadingControlHost != null)
{
lazyLoadingControlHost.Child = imageExLazyLoadingControl;
}
});
}
SampleController.Current.RegisterNewCommand("Clear image cache", async (sender, args) =>
{
container?.Children?.Clear();

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

@ -23,158 +23,101 @@ private async void PinTile()
}
public static TileContent GenerateTileContent(string username, string avatarLogoSource)
{
return new TileContent()
{
Visual = new TileVisual()
{
TileMedium = GenerateTileBindingMedium(username, avatarLogoSource),
TileWide = GenerateTileBindingWide(username, avatarLogoSource),
TileLarge = GenerateTileBindingLarge(username, avatarLogoSource)
}
};
}
{
var builder = new TileContentBuilder();
private static TileBinding GenerateTileBindingMedium(string username, string avatarLogoSource)
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
PeekImage = new TilePeekImage()
{
Source = avatarLogoSource,
HintCrop = TilePeekImageCrop.Circle
},
// Medium Tile built using only builder method.
builder.AddTile(Notifications.TileSize.Medium)
.SetPeekImage(new Uri(avatarLogoSource, UriKind.Relative), Notifications.TileSize.Medium, hintCrop: TilePeekImageCrop.Circle)
.SetTextStacking(TileTextStacking.Center, Notifications.TileSize.Medium)
.AddText("Hi,", Notifications.TileSize.Medium, hintStyle: AdaptiveTextStyle.Base, hintAlign: AdaptiveTextAlign.Center)
.AddText(username, Notifications.TileSize.Medium, hintStyle: AdaptiveTextStyle.CaptionSubtle, hintAlign: AdaptiveTextAlign.Center);
TextStacking = TileTextStacking.Center,
// Wide Tile using custom-made layout.
builder.AddTile(Notifications.TileSize.Wide)
.AddAdaptiveTileVisualChild(GenerateWideTileContent(username, avatarLogoSource), Notifications.TileSize.Wide);
Children =
{
new AdaptiveText()
{
Text = "Hi,",
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.Base
},
// Large Tile using custom-made layout conjunction with builder helper method
builder.AddTile(Notifications.TileSize.Large)
.AddAdaptiveTileVisualChild(CreateLargeTileLogoPayload(avatarLogoSource), Notifications.TileSize.Large)
.AddText("Hi,", Notifications.TileSize.Large, hintAlign: AdaptiveTextAlign.Center, hintStyle: AdaptiveTextStyle.Title)
.AddText(username, Notifications.TileSize.Large, hintAlign: AdaptiveTextAlign.Center, hintStyle: AdaptiveTextStyle.SubtitleSubtle);
new AdaptiveText()
{
Text = username,
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.CaptionSubtle
}
}
}
};
}
return builder.Content;
}
private static TileBinding GenerateTileBindingWide(string username, string avatarLogoSource)
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
{
HintWeight = 33,
private static ITileBindingContentAdaptiveChild GenerateWideTileContent(string username, string avatarLogoSource)
{
return new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
{
HintWeight = 33,
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
new AdaptiveSubgroup()
{
HintTextStacking = AdaptiveSubgroupTextStacking.Center,
new AdaptiveSubgroup()
{
HintTextStacking = AdaptiveSubgroupTextStacking.Center,
Children =
{
new AdaptiveText()
{
Text = "Hi,",
HintStyle = AdaptiveTextStyle.Title
},
Children =
{
new AdaptiveText()
{
Text = "Hi,",
HintStyle = AdaptiveTextStyle.Title
},
new AdaptiveText()
{
Text = username,
HintStyle = AdaptiveTextStyle.SubtitleSubtle
}
}
}
}
}
}
}
};
}
new AdaptiveText()
{
Text = username,
HintStyle = AdaptiveTextStyle.SubtitleSubtle
}
}
}
}
};
}
private static TileBinding GenerateTileBindingLarge(string username, string avatarLogoSource)
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
TextStacking = TileTextStacking.Center,
private static ITileBindingContentAdaptiveChild CreateLargeTileLogoPayload(string avatarLogoSource)
{
return new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
{
HintWeight = 1
},
Children =
{
new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
{
HintWeight = 1
},
// We surround the image by two subgroups so that it doesn't take the full width
new AdaptiveSubgroup()
{
HintWeight = 2,
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
// We surround the image by two subgroups so that it doesn't take the full width
new AdaptiveSubgroup()
{
HintWeight = 2,
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
new AdaptiveSubgroup()
{
HintWeight = 1
}
}
},
new AdaptiveText()
{
Text = "Hi,",
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.Title
},
new AdaptiveText()
{
Text = username,
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.SubtitleSubtle
}
}
}
};
}
new AdaptiveSubgroup()
{
HintWeight = 1
}
}
};
}

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

@ -27,96 +27,64 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
public static TileContent GenerateTileContent(string username, string avatarLogoSource)
{
return new TileContent()
{
Visual = new TileVisual()
{
TileMedium = GenerateTileBindingMedium(username, avatarLogoSource),
TileWide = GenerateTileBindingWide(username, avatarLogoSource),
TileLarge = GenerateTileBindingLarge(username, avatarLogoSource)
}
};
var builder = new TileContentBuilder();
// Medium Tile built using only builder method.
builder.AddTile(Notifications.TileSize.Medium)
.SetPeekImage(new Uri(avatarLogoSource, UriKind.Relative), Notifications.TileSize.Medium, hintCrop: TilePeekImageCrop.Circle)
.SetTextStacking(TileTextStacking.Center, Notifications.TileSize.Medium)
.AddText("Hi,", Notifications.TileSize.Medium, hintStyle: AdaptiveTextStyle.Base, hintAlign: AdaptiveTextAlign.Center)
.AddText(username, Notifications.TileSize.Medium, hintStyle: AdaptiveTextStyle.CaptionSubtle, hintAlign: AdaptiveTextAlign.Center);
// Wide Tile using custom-made layout.
builder.AddTile(Notifications.TileSize.Wide)
.AddAdaptiveTileVisualChild(GenerateWideTileContent(username, avatarLogoSource), Notifications.TileSize.Wide);
// Large Tile using custom-made layout conjunction with builder helper method
builder.AddTile(Notifications.TileSize.Large)
.AddAdaptiveTileVisualChild(CreateLargeTileLogoPayload(avatarLogoSource), Notifications.TileSize.Large)
.AddText("Hi,", Notifications.TileSize.Large, hintAlign: AdaptiveTextAlign.Center, hintStyle: AdaptiveTextStyle.Title)
.AddText(username, Notifications.TileSize.Large, hintAlign: AdaptiveTextAlign.Center, hintStyle: AdaptiveTextStyle.SubtitleSubtle);
return builder.Content;
}
private static TileBinding GenerateTileBindingMedium(string username, string avatarLogoSource)
private static ITileBindingContentAdaptiveChild GenerateWideTileContent(string username, string avatarLogoSource)
{
return new TileBinding()
return new AdaptiveGroup()
{
Content = new TileBindingContentAdaptive()
Children =
{
PeekImage = new TilePeekImage()
new AdaptiveSubgroup()
{
Source = avatarLogoSource,
HintCrop = TilePeekImageCrop.Circle
HintWeight = 33,
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
TextStacking = TileTextStacking.Center,
Children =
new AdaptiveSubgroup()
{
new AdaptiveText()
{
Text = "Hi,",
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.Base
},
HintTextStacking = AdaptiveSubgroupTextStacking.Center,
new AdaptiveText()
Children =
{
Text = username,
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.CaptionSubtle
}
}
}
};
}
private static TileBinding GenerateTileBindingWide(string username, string avatarLogoSource)
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
new AdaptiveText()
{
new AdaptiveSubgroup()
{
HintWeight = 33,
Text = "Hi,",
HintStyle = AdaptiveTextStyle.Title
},
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
new AdaptiveSubgroup()
{
HintTextStacking = AdaptiveSubgroupTextStacking.Center,
Children =
{
new AdaptiveText()
{
Text = "Hi,",
HintStyle = AdaptiveTextStyle.Title
},
new AdaptiveText()
{
Text = username,
HintStyle = AdaptiveTextStyle.SubtitleSubtle
}
}
}
new AdaptiveText()
{
Text = username,
HintStyle = AdaptiveTextStyle.SubtitleSubtle
}
}
}
@ -124,59 +92,34 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
};
}
private static TileBinding GenerateTileBindingLarge(string username, string avatarLogoSource)
private static ITileBindingContentAdaptiveChild CreateLargeTileLogoPayload(string avatarLogoSource)
{
return new TileBinding()
return new AdaptiveGroup()
{
Content = new TileBindingContentAdaptive()
Children =
{
TextStacking = TileTextStacking.Center,
Children =
new AdaptiveSubgroup()
{
new AdaptiveGroup()
HintWeight = 1
},
// We surround the image by two subgroups so that it doesn't take the full width
new AdaptiveSubgroup()
{
HintWeight = 2,
Children =
{
Children =
new AdaptiveImage()
{
new AdaptiveSubgroup()
{
HintWeight = 1
},
// We surround the image by two subgroups so that it doesn't take the full width
new AdaptiveSubgroup()
{
HintWeight = 2,
Children =
{
new AdaptiveImage()
{
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
}
},
new AdaptiveSubgroup()
{
HintWeight = 1
}
Source = avatarLogoSource,
HintCrop = AdaptiveImageCrop.Circle
}
},
new AdaptiveText()
{
Text = "Hi,",
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.Title
},
new AdaptiveText()
{
Text = username,
HintAlign = AdaptiveTextAlign.Center,
HintStyle = AdaptiveTextStyle.SubtitleSubtle
}
},
new AdaptiveSubgroup()
{
HintWeight = 1
}
}
};

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

@ -41,8 +41,6 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
new RemoteSystemStatusTypeFilter((RemoteSystemStatusType)Enum.Parse(typeof(RemoteSystemStatusType), statusType?.SelectedValue.ToString()))
};
_remoteDeviceHelper = new RemoteDeviceHelper(filters);
DevicesList.DataContext = _remoteDeviceHelper;
}

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

@ -26,7 +26,9 @@
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<controls:StaggeredPanel DesiredColumnWidth="@[DesiredColumnWidth:Slider:250:50-400]"
HorizontalAlignment="@[HorizontalAlignment:Enum:HorizontalAlignment.Left]"/>
HorizontalAlignment="@[HorizontalAlignment:Enum:HorizontalAlignment.Left]"
ColumnSpacing="@[ColumnSpacing:Slider:5:0-50]@"
RowSpacing="@[RowSpacing:Slider:5:0-50]@" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>

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

@ -23,6 +23,11 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
var gridView = control.FindChildByName("GridView") as ItemsControl;
if (gridView == null)
{
return;
}
var items = await new Data.PhotosDataSource().GetItemsAsync();
gridView.ItemsSource = items
.Select((p, i) => new

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

@ -6,63 +6,19 @@ private void PopToast()
}
public static ToastContent GenerateToastContent()
{
return new ToastContent()
{
Launch = "action=viewEvent&eventId=1983",
Scenario = ToastScenario.Reminder,
{
var builder = new ToastContentBuilder().SetToastScenario(ToastScenario.Reminder)
.AddToastActivationInfo("action=viewEvent&eventId=1983", ToastActivationType.Foreground)
.AddText("Adaptive Tiles Meeting")
.AddText("Conf Room 2001 / Building 135")
.AddText("10:00 AM - 10:30 AM")
.AddComboBox("snoozeTime", "15", ("1", "1 minute"),
("15", "15 minutes"),
("60", "1 hour"),
("240", "4 hours"),
("1440", "1 day"))
.AddButton(new ToastButtonSnooze() { SelectionBoxId = "snoozeTime" })
.AddButton(new ToastButtonDismiss());
Visual = new ToastVisual()
{
BindingGeneric = new ToastBindingGeneric()
{
Children =
{
new AdaptiveText()
{
Text = "Adaptive Tiles Meeting"
},
new AdaptiveText()
{
Text = "Conf Room 2001 / Building 135"
},
new AdaptiveText()
{
Text = "10:00 AM - 10:30 AM"
}
}
}
},
Actions = new ToastActionsCustom()
{
Inputs =
{
new ToastSelectionBox("snoozeTime")
{
DefaultSelectionBoxItemId = "15",
Items =
{
new ToastSelectionBoxItem("1", "1 minute"),
new ToastSelectionBoxItem("15", "15 minutes"),
new ToastSelectionBoxItem("60", "1 hour"),
new ToastSelectionBoxItem("240", "4 hours"),
new ToastSelectionBoxItem("1440", "1 day")
}
}
},
Buttons =
{
new ToastButtonSnooze()
{
SelectionBoxId = "snoozeTime"
},
new ToastButtonDismiss()
}
}
};
}
return builder.Content;
}

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

@ -23,68 +23,30 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
Initialize();
}
#pragma warning disable SA1008 // Parenthesis spacing
#pragma warning disable SA1117 // Parameters must be on same line or separate lines
public static ToastContent GenerateToastContent()
{
return new ToastContent()
{
Launch = "action=viewEvent&eventId=1983",
Scenario = ToastScenario.Reminder,
var builder = new ToastContentBuilder().SetToastScenario(ToastScenario.Reminder)
.AddToastActivationInfo("action=viewEvent&eventId=1983", ToastActivationType.Foreground)
.AddText("Adaptive Tiles Meeting")
.AddText("Conf Room 2001 / Building 135")
.AddText("10:00 AM - 10:30 AM")
.AddComboBox("snoozeTime", "15", ("1", "1 minute"),
("15", "15 minutes"),
("60", "1 hour"),
("240", "4 hours"),
("1440", "1 day"))
.AddButton(new ToastButtonSnooze() { SelectionBoxId = "snoozeTime" })
.AddButton(new ToastButtonDismiss());
Visual = new ToastVisual()
{
BindingGeneric = new ToastBindingGeneric()
{
Children =
{
new AdaptiveText()
{
Text = "Adaptive Tiles Meeting"
},
new AdaptiveText()
{
Text = "Conf Room 2001 / Building 135"
},
new AdaptiveText()
{
Text = "10:00 AM - 10:30 AM"
}
}
}
},
Actions = new ToastActionsCustom()
{
Inputs =
{
new ToastSelectionBox("snoozeTime")
{
DefaultSelectionBoxItemId = "15",
Items =
{
new ToastSelectionBoxItem("1", "1 minute"),
new ToastSelectionBoxItem("15", "15 minutes"),
new ToastSelectionBoxItem("60", "1 hour"),
new ToastSelectionBoxItem("240", "4 hours"),
new ToastSelectionBoxItem("1440", "1 day")
}
}
},
Buttons =
{
new ToastButtonSnooze()
{
SelectionBoxId = "snoozeTime"
},
new ToastButtonDismiss()
}
}
};
return builder.Content;
}
#pragma warning restore SA1008
#pragma warning restore SA1117
private void ButtonPopToast_Click(object sender, RoutedEventArgs e)
{
PopToast();

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

@ -30,81 +30,91 @@ private async void PinTile()
}
public static ToastContent GenerateToastContent()
{
// Start by constructing the visual portion of the toast
ToastBindingGeneric binding = new ToastBindingGeneric();
{
ToastContentBuilder builder = new ToastContentBuilder();
// We'll always have this summary text on our toast notification
// (it is required that your toast starts with a text element)
binding.Children.Add(new AdaptiveText()
{
Text = "Today will be mostly sunny with a high of 63 and a low of 42."
});
// Include launch string so we know what to open when user clicks toast
builder.AddToastActivationInfo("action=viewForecast&zip=98008", ToastActivationType.Foreground);
// If Adaptive Toast Notifications are supported
if (IsAdaptiveToastSupported())
{
// Use the rich Tile-like visual layout
binding.Children.Add(new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateSubgroup("Wed", "Sunny.png", 59, 43),
GenerateSubgroup("Thu", "Sunny.png", 62, 42),
GenerateSubgroup("Fri", "Sunny.png", 71, 66)
}
});
}
// We'll always have this summary text on our toast notification
// (it is required that your toast starts with a text element)
builder.AddText("Today will be mostly sunny with a high of 63 and a low of 42.");
// Otherwise...
else
{
// We'll just add two simple lines of text
binding.Children.Add(new AdaptiveText()
{
Text = "Monday ? 63° / 42°"
});
// If Adaptive Toast Notifications are supported
if (IsAdaptiveToastSupported())
{
// Use the rich Tile-like visual layout
builder.AddVisualChild(new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateSubgroup("Wed", "Sunny.png", 59, 43),
GenerateSubgroup("Thu", "Sunny.png", 62, 42),
GenerateSubgroup("Fri", "Sunny.png", 71, 66)
}
});
}
binding.Children.Add(new AdaptiveText()
{
Text = "Tuesday ? 57° / 38°"
});
}
// Otherwise...
else
{
// We'll just add two simple lines of text
builder.AddText("Monday ? 63° / 42°")
.AddText("Tuesday ? 57° / 38°");
}
// Construct the entire notification
return new ToastContent()
{
Visual = new ToastVisual()
{
// Use our binding from above
BindingGeneric = binding,
// Set the base URI for the images, so we don't redundantly specify the entire path
builder.Content.Visual.BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative);
// Set the base URI for the images, so we don't redundantly specify the entire path
BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative)
},
// Include launch string so we know what to open when user clicks toast
Launch = "action=viewForecast&zip=98008"
};
}
return builder.Content;
}
public static TileContent GenerateTileContent()
{
return new TileContent()
{
Visual = new TileVisual()
{
TileSmall = GenerateTileBindingSmall(),
TileMedium = GenerateTileBindingMedium(),
TileWide = GenerateTileBindingWide(),
TileLarge = GenerateTileBindingLarge(),
{
TileContentBuilder builder = new TileContentBuilder();
// Set the base URI for the images, so we don't redundantly specify the entire path
BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative)
}
};
// Small Tile
builder.AddTile(Notifications.TileSize.Small)
.SetTextStacking(TileTextStacking.Center, Notifications.TileSize.Small)
.AddText("Mon", hintStyle: AdaptiveTextStyle.Body, hintAlign: AdaptiveTextAlign.Center)
.AddText("63°", hintStyle: AdaptiveTextStyle.Base, hintAlign: AdaptiveTextAlign.Center);
// Medium Tile
builder.AddTile(Notifications.TileSize.Medium)
.AddAdaptiveTileVisualChild(
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38)
}
}, Notifications.TileSize.Medium);
// Wide Tile
builder.AddTile(Notifications.TileSize.Wide)
.AddAdaptiveTileVisualChild(
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateSubgroup("Wed", "Sunny.png", 59, 43),
GenerateSubgroup("Thu", "Sunny.png", 62, 42),
GenerateSubgroup("Fri", "Sunny.png", 71, 66)
}
}, Notifications.TileSize.Wide);
// Large tile
builder.AddTile(Notifications.TileSize.Large, GenerateLargeTileContent());
// Set the base URI for the images, so we don't redundantly specify the entire path
builder.Content.Visual.BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative);
return builder.Content;
}
private static bool IsAdaptiveToastSupported()
@ -122,148 +132,72 @@ private static bool IsAdaptiveToastSupported()
}
}
private static TileBinding GenerateTileBindingSmall()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
TextStacking = TileTextStacking.Center,
private static TileBindingContentAdaptive GenerateLargeTileContent()
{
return new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
{
HintWeight = 30,
Children =
{
new AdaptiveImage() { Source = "Mostly Cloudy.png" }
}
},
Children =
{
new AdaptiveText()
{
Text = "Mon",
HintStyle = AdaptiveTextStyle.Body,
HintAlign = AdaptiveTextAlign.Center
},
new AdaptiveSubgroup()
{
Children =
{
new AdaptiveText()
{
Text = "Monday",
HintStyle = AdaptiveTextStyle.Base
},
new AdaptiveText()
{
Text = "63°",
HintStyle = AdaptiveTextStyle.Base,
HintAlign = AdaptiveTextAlign.Center
}
}
}
};
}
new AdaptiveText()
{
Text = "63° / 42°"
},
private static TileBinding GenerateTileBindingMedium()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38)
}
}
}
}
};
}
new AdaptiveText()
{
Text = "20% chance of rain",
HintStyle = AdaptiveTextStyle.CaptionSubtle
},
private static TileBinding GenerateTileBindingWide()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateSubgroup("Wed", "Sunny.png", 59, 43),
GenerateSubgroup("Thu", "Sunny.png", 62, 42),
GenerateSubgroup("Fri", "Sunny.png", 71, 66)
}
}
}
}
};
}
new AdaptiveText()
{
Text = "Winds 5 mph NE",
HintStyle = AdaptiveTextStyle.CaptionSubtle
}
}
}
}
},
private static TileBinding GenerateTileBindingLarge()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
{
HintWeight = 30,
Children =
{
new AdaptiveImage() { Source = "Mostly Cloudy.png" }
}
},
// For spacing
new AdaptiveText(),
new AdaptiveSubgroup()
{
Children =
{
new AdaptiveText()
{
Text = "Monday",
HintStyle = AdaptiveTextStyle.Base
},
new AdaptiveText()
{
Text = "63° / 42°"
},
new AdaptiveText()
{
Text = "20% chance of rain",
HintStyle = AdaptiveTextStyle.CaptionSubtle
},
new AdaptiveText()
{
Text = "Winds 5 mph NE",
HintStyle = AdaptiveTextStyle.CaptionSubtle
}
}
}
}
},
// For spacing
new AdaptiveText(),
new AdaptiveGroup()
{
Children =
{
GenerateLargeSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateLargeSubgroup("Wed", "Sunny.png", 59, 43),
GenerateLargeSubgroup("Thu", "Sunny.png", 62, 42),
GenerateLargeSubgroup("Fri", "Sunny.png", 71, 66)
}
}
}
}
};
}
new AdaptiveGroup()
{
Children =
{
GenerateLargeSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateLargeSubgroup("Wed", "Sunny.png", 59, 43),
GenerateLargeSubgroup("Thu", "Sunny.png", 62, 42),
GenerateLargeSubgroup("Fri", "Sunny.png", 71, 66)
}
}
}
};
}
private static AdaptiveSubgroup GenerateSubgroup(string day, string img, int tempHi, int tempLo)
{

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

@ -29,21 +29,20 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
public static ToastContent GenerateToastContent()
{
// Start by constructing the visual portion of the toast
ToastBindingGeneric binding = new ToastBindingGeneric();
ToastContentBuilder builder = new ToastContentBuilder();
// Include launch string so we know what to open when user clicks toast
builder.AddToastActivationInfo("action=viewForecast&zip=98008", ToastActivationType.Foreground);
// We'll always have this summary text on our toast notification
// (it is required that your toast starts with a text element)
binding.Children.Add(new AdaptiveText()
{
Text = "Today will be mostly sunny with a high of 63 and a low of 42."
});
builder.AddText("Today will be mostly sunny with a high of 63 and a low of 42.");
// If Adaptive Toast Notifications are supported
if (IsAdaptiveToastSupported())
{
// Use the rich Tile-like visual layout
binding.Children.Add(new AdaptiveGroup()
builder.AddVisualChild(new AdaptiveGroup()
{
Children =
{
@ -60,49 +59,60 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
else
{
// We'll just add two simple lines of text
binding.Children.Add(new AdaptiveText()
{
Text = "Monday ⛅ 63° / 42°"
});
binding.Children.Add(new AdaptiveText()
{
Text = "Tuesday ☁ 57° / 38°"
});
builder.AddText("Monday ⛅ 63° / 42°")
.AddText("Tuesday ☁ 57° / 38°");
}
// Construct the entire notification
return new ToastContent()
{
Visual = new ToastVisual()
{
// Use our binding from above
BindingGeneric = binding,
// Set the base URI for the images, so we don't redundantly specify the entire path
builder.Content.Visual.BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative);
// Set the base URI for the images, so we don't redundantly specify the entire path
BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative)
},
// Include launch string so we know what to open when user clicks toast
Launch = "action=viewForecast&zip=98008"
};
return builder.Content;
}
public static TileContent GenerateTileContent()
{
return new TileContent()
{
Visual = new TileVisual()
{
TileSmall = GenerateTileBindingSmall(),
TileMedium = GenerateTileBindingMedium(),
TileWide = GenerateTileBindingWide(),
TileLarge = GenerateTileBindingLarge(),
TileContentBuilder builder = new TileContentBuilder();
// Set the base URI for the images, so we don't redundantly specify the entire path
BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative)
}
};
// Small Tile
builder.AddTile(Notifications.TileSize.Small)
.SetTextStacking(TileTextStacking.Center, Notifications.TileSize.Small)
.AddText("Mon", hintStyle: AdaptiveTextStyle.Body, hintAlign: AdaptiveTextAlign.Center)
.AddText("63°", hintStyle: AdaptiveTextStyle.Base, hintAlign: AdaptiveTextAlign.Center);
// Medium Tile
builder.AddTile(Notifications.TileSize.Medium)
.AddAdaptiveTileVisualChild(
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38)
}
}, Notifications.TileSize.Medium);
// Wide Tile
builder.AddTile(Notifications.TileSize.Wide)
.AddAdaptiveTileVisualChild(
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateSubgroup("Wed", "Sunny.png", 59, 43),
GenerateSubgroup("Thu", "Sunny.png", 62, 42),
GenerateSubgroup("Fri", "Sunny.png", 71, 66)
}
}, Notifications.TileSize.Wide);
// Large tile
builder.AddTile(Notifications.TileSize.Large, GenerateLargeTileContent());
// Set the base URI for the images, so we don't redundantly specify the entire path
builder.Content.Visual.BaseUri = new Uri("Assets/NotificationAssets/", UriKind.Relative);
return builder.Content;
}
private static bool IsAdaptiveToastSupported()
@ -120,143 +130,67 @@ namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
}
}
private static TileBinding GenerateTileBindingSmall()
private static TileBindingContentAdaptive GenerateLargeTileContent()
{
return new TileBinding()
return new TileBindingContentAdaptive()
{
Content = new TileBindingContentAdaptive()
Children =
{
TextStacking = TileTextStacking.Center,
Children =
new AdaptiveGroup()
{
new AdaptiveText()
Children =
{
Text = "Mon",
HintStyle = AdaptiveTextStyle.Body,
HintAlign = AdaptiveTextAlign.Center
},
new AdaptiveText()
{
Text = "63°",
HintStyle = AdaptiveTextStyle.Base,
HintAlign = AdaptiveTextAlign.Center
}
}
}
};
}
private static TileBinding GenerateTileBindingMedium()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
new AdaptiveSubgroup()
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38)
}
}
}
}
};
}
private static TileBinding GenerateTileBindingWide()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
GenerateSubgroup("Mon", "Mostly Cloudy.png", 63, 42),
GenerateSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateSubgroup("Wed", "Sunny.png", 59, 43),
GenerateSubgroup("Thu", "Sunny.png", 62, 42),
GenerateSubgroup("Fri", "Sunny.png", 71, 66)
}
}
}
}
};
}
private static TileBinding GenerateTileBindingLarge()
{
return new TileBinding()
{
Content = new TileBindingContentAdaptive()
{
Children =
{
new AdaptiveGroup()
{
Children =
{
new AdaptiveSubgroup()
HintWeight = 30,
Children =
{
HintWeight = 30,
Children =
{
new AdaptiveImage() { Source = "Mostly Cloudy.png" }
}
},
new AdaptiveImage() { Source = "Mostly Cloudy.png" }
}
},
new AdaptiveSubgroup()
new AdaptiveSubgroup()
{
Children =
{
Children =
new AdaptiveText()
{
new AdaptiveText()
{
Text = "Monday",
HintStyle = AdaptiveTextStyle.Base
},
Text = "Monday",
HintStyle = AdaptiveTextStyle.Base
},
new AdaptiveText()
{
Text = "63° / 42°"
},
new AdaptiveText()
{
Text = "63° / 42°"
},
new AdaptiveText()
{
Text = "20% chance of rain",
HintStyle = AdaptiveTextStyle.CaptionSubtle
},
new AdaptiveText()
{
Text = "20% chance of rain",
HintStyle = AdaptiveTextStyle.CaptionSubtle
},
new AdaptiveText()
{
Text = "Winds 5 mph NE",
HintStyle = AdaptiveTextStyle.CaptionSubtle
}
new AdaptiveText()
{
Text = "Winds 5 mph NE",
HintStyle = AdaptiveTextStyle.CaptionSubtle
}
}
}
},
}
},
// For spacing
new AdaptiveText(),
// For spacing
new AdaptiveText(),
new AdaptiveGroup()
new AdaptiveGroup()
{
Children =
{
Children =
{
GenerateLargeSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateLargeSubgroup("Wed", "Sunny.png", 59, 43),
GenerateLargeSubgroup("Thu", "Sunny.png", 62, 42),
GenerateLargeSubgroup("Fri", "Sunny.png", 71, 66)
}
GenerateLargeSubgroup("Tue", "Cloudy.png", 57, 38),
GenerateLargeSubgroup("Wed", "Sunny.png", 59, 43),
GenerateLargeSubgroup("Thu", "Sunny.png", 62, 42),
GenerateLargeSubgroup("Fri", "Sunny.png", 71, 66)
}
}
}

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

@ -94,6 +94,8 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
return;
}
SamplePickerGridView.ItemsSource = samples;
var groups = samples.GroupBy(sample => sample.Subcategory);
if (group && groups.Count() > 1)
@ -187,7 +189,9 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
if (button != null)
{
button.Click -= MoreInfoClicked;
button.LostFocus -= MoreInfoLostFocus;
button.Click += MoreInfoClicked;
button.LostFocus += MoreInfoLostFocus;
}
var itemIndex = SamplePickerGridView.IndexFromContainer(itemContainer);
@ -249,13 +253,8 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
private void MoreInfoClicked(object sender, RoutedEventArgs e)
{
if (MoreInfoContent == null)
{
return;
}
var button = (Button)sender;
var sample = button.DataContext as Sample;
var sampleData = button.DataContext as Sample;
var container = button.FindAscendant<GridViewItem>();
if (container == null)
@ -263,8 +262,32 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
return;
}
var point = container.TransformToVisual(this).TransformPoint(new Windows.Foundation.Point(0, 0));
InitMoreInfoContentContainer(container);
MoreInfoContent.DataContext = sampleData;
if (MoreInfoCanvas.Visibility == Visibility.Visible)
{
HideMoreInfo();
}
else
{
MoreInfoCanvas.Visibility = Visibility.Visible;
}
}
private void MoreInfoLostFocus(object sender, RoutedEventArgs e)
{
HideMoreInfo();
}
private void InitMoreInfoContentContainer(GridViewItem container)
{
if (MoreInfoContent == null)
{
return;
}
var point = container.TransformToVisual(this).TransformPoint(new Windows.Foundation.Point(0, 0));
var x = point.X - ((MoreInfoContent.Width - container.ActualWidth) / 2);
var y = point.Y - ((MoreInfoContent.Height - container.ActualHeight) / 2);
@ -281,9 +304,6 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
var centerY = (point.Y + (container.ActualHeight / 2)) - y;
VisualExtensions.SetCenterPoint(MoreInfoContent, new Vector3((float)centerX, (float)centerY, 0).ToString());
MoreInfoContent.DataContext = sample;
MoreInfoCanvas.Visibility = Visibility.Visible;
}
private void HideMoreInfo()

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

@ -91,6 +91,7 @@
<GridView x:Name="SamplePickerGridView"
animations:ReorderGridAnimation.Duration="200"
IsItemClickEnabled="True"
Loaded="SamplePickerGridView_Loaded"
ItemContainerStyle="{StaticResource SamplePickerItemStyle}"
ItemContainerTransitions="{x:Null}"
ItemTemplate="{StaticResource SampleTemplate}"

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

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp.Helpers;
using Microsoft.Toolkit.Uwp.SampleApp.Pages;
using Microsoft.Toolkit.Uwp.UI.Extensions;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Navigation;
@ -119,5 +120,16 @@ namespace Microsoft.Toolkit.Uwp.SampleApp
HideSamplePicker();
NavigateToSample(e.ClickedItem as Sample);
}
private void SamplePickerGridView_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
SamplePickerGrid.RegisterPropertyChangedCallback(UIElement.VisibilityProperty, (s, args) =>
{
if (s is UIElement samplePicker && samplePicker.Visibility == Visibility.Visible)
{
DispatcherHelper.ExecuteOnUIThreadAsync(() => SamplePickerGridView.Focus(FocusState.Keyboard));
}
});
}
}
}

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

@ -3,7 +3,19 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit Animations</Title>
<Description>This library provides helpers and extensions on top of Windows Composition and XAML storyboards. It is part of the Windows Community Toolkit.</Description>
<Description>
This library provides helpers and extensions on top of Windows Composition and XAML storyboards. It is part of the Windows Community Toolkit.
Namespace:
- Behaviors: Blur, CompositionBehaviorBase, CompositionBehaviorBase, Fade, FadeHeaderBehavior, Light, Offset, QuickReturnHeaderBehavior, Rotate, Saturation, Scale, StickyHeaderBehavior.
- CompositionAnimations:
- Animations: AnimationBase, OffsetAnimation, OpacityAnimation, RotationAnimation, RotationInDegreesAnimation, ScalarAnimation, ScaleAnimation, TranslationAnimation, TypedAnimationBase, Vector2Animation, Vector3Animation, Vector4Animation
- CompositionAnimations: ExpressionKeyFrame, KeyFrame, KeyFrameCollection, ScalarKeyFrame, TypedKeyFrame, Vector2KeyFrame, Vector3KeyFrame, Vector4KeyFrame
- ConnectedAnimations: Connected, ConnectedAnimationHelper, ConnectedAnimationListProperty, ConnectedAnimationProperties
- Effects: AnimationEffect, Blur, Saturation
- Expressions: ExpressionNodes, ExpressionValues, ReferenceNodes, CompositionExtensions, ExpressionFunctions, OperationType
- AnimationExtensions: Blur, Fade, Light, Offset, Rotate, Saturation, Scale
</Description>
<PackageTags>UWP Toolkit Windows Animations Composition Connected Implicit XAML</PackageTags>
</PropertyGroup>

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

@ -86,7 +86,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Animations
}
double duration = (double)view.GetValue(DurationProperty);
elementImplicitAnimation[nameof(Visual.Offset)] = CreateOffsetAnimation(compositor, duration);
if (double.IsNaN(duration))
{
elementImplicitAnimation.Remove(nameof(Visual.Offset));
}
else
{
elementImplicitAnimation[nameof(Visual.Offset)] = CreateOffsetAnimation(compositor, duration);
}
}
private static void OnContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)

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

@ -9,8 +9,10 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Toolkit.Uwp.UI.Controls.Design</RootNamespace>
<AssemblyName>Microsoft.Toolkit.Uwp.UI.Controls.DataGrid.Design</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<AssetTargetFallback>$(AssetTargetFallback);uap10.0.16299</AssetTargetFallback>
</PropertyGroup>
<PropertyGroup>
<TargetPlatformVersion>8.1</TargetPlatformVersion>
@ -77,7 +79,6 @@
</Reference>
<Reference Include="Windows.Foundation.UniversalApiContract">
<HintPath>$(ProgramFiles)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.UniversalApiContract\7.0.0.0\Windows.Foundation.UniversalApiContract.winmd</HintPath>
<Aliases>WindowsRuntime</Aliases>
<Private>False</Private>
</Reference>

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

@ -19,7 +19,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.Design.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {

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

@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.Design.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

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

@ -4,6 +4,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
@ -39,6 +40,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
private Brush _foreground;
private HashSet<object> _notifyingDataItems;
/// <summary>
/// Identifies the ItemsSource dependency property.
@ -264,6 +266,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
comboBox.SelectionChanged += (sender, args) =>
{
var item = args.AddedItems.FirstOrDefault();
if (item != null)
{
var newValue = !string.IsNullOrEmpty(DisplayMemberPath)
@ -336,6 +339,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
else
{
textBlockElement.Text = GetDisplayValue(dataItem);
HookDataItemPropertyChanged(dataItem);
}
}
@ -534,6 +539,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
_owningGrid = OwningGrid;
_owningGrid.Columns.CollectionChanged += new NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
_owningGrid.LoadingRow += OwningGrid_LoadingRow;
_owningGrid.UnloadingRow += OwningGrid_UnloadingRow;
_owningGrid.CellEditEnded += OwningGrid_CellEditEnded;
}
@ -545,9 +551,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private void OwningGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
HookDataItemPropertyChanged(e.Row.DataContext);
SetDisplayMemberPathValue(e.Row);
}
private void OwningGrid_UnloadingRow(object sender, DataGridRowEventArgs e)
{
UnhookDataItemPropertyChanged(e.Row.DataContext);
}
private void OwningGrid_CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
{
SetDisplayMemberPathValue(e.Row);
@ -557,8 +569,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
if (OwningGrid == null && _owningGrid != null)
{
_notifyingDataItems?.Clear();
_owningGrid.Columns.CollectionChanged -= new NotifyCollectionChangedEventHandler(Columns_CollectionChanged);
_owningGrid.LoadingRow -= OwningGrid_LoadingRow;
_owningGrid.UnloadingRow -= this.OwningGrid_UnloadingRow;
_owningGrid.CellEditEnded -= OwningGrid_CellEditEnded;
_owningGrid = null;
}
@ -637,5 +651,65 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
}
}
private void HookDataItemPropertyChanged(object dataItem)
{
if (Binding.Mode == BindingMode.OneTime)
{
return;
}
var notifyingDataItem = dataItem as INotifyPropertyChanged;
if (notifyingDataItem == null)
{
return;
}
if (_notifyingDataItems == null)
{
_notifyingDataItems = new HashSet<object>();
}
if (!_notifyingDataItems.Contains(dataItem))
{
notifyingDataItem.PropertyChanged += DataItem_PropertyChanged;
_notifyingDataItems.Add(dataItem);
}
}
private void UnhookDataItemPropertyChanged(object dataItem)
{
if (_notifyingDataItems == null)
{
return;
}
var notifyingDataItem = dataItem as INotifyPropertyChanged;
if (notifyingDataItem == null)
{
return;
}
if (_notifyingDataItems.Contains(dataItem))
{
notifyingDataItem.PropertyChanged -= DataItem_PropertyChanged;
_notifyingDataItems.Remove(dataItem);
}
}
private void DataItem_PropertyChanged(object dataItem, PropertyChangedEventArgs e)
{
if (this.OwningGrid != null && Binding?.Path != null && this.Binding.Path.Path == e.PropertyName)
{
var dataGridRow = OwningGrid.GetRowFromItem(dataItem);
if (dataGridRow != null && this.GetCellContent(dataGridRow) is TextBlock textBlockElement)
{
textBlockElement.Text = GetDisplayValue(dataItem);
}
}
}
}
}

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

@ -2,7 +2,10 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit Controls DataGrid</Title>
<Description>This library provides a XAML DataGrid control. It is part of the Windows Community Toolkit.</Description>
<Description>
This library provides a XAML DataGrid control. It is part of the Windows Community Toolkit.
</Description>
<PackageTags>UWP Toolkit Windows Controls XAML DataGrid</PackageTags>
<RootNamespace>Microsoft.Toolkit.Uwp.UI.Controls</RootNamespace>
<UseUwpMetaPackage>true</UseUwpMetaPackage>

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

@ -9,8 +9,11 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Toolkit.Uwp.UI.Controls.Design</RootNamespace>
<AssemblyName>Microsoft.Toolkit.Uwp.UI.Controls.Design</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<NoWarn>$(NoWarn);0618</NoWarn>
<AssetTargetFallback>$(AssetTargetFallback);uap10.0.16299</AssetTargetFallback>
</PropertyGroup>
<PropertyGroup>
<TargetPlatformVersion>8.1</TargetPlatformVersion>

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

@ -19,7 +19,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.Design.Properties {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {

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

@ -12,7 +12,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.Design.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.3.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.3.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

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

@ -24,7 +24,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.Design
b.AddCustomAttributes(nameof(TextToolbar.DefaultButtons), new CategoryAttribute(Properties.Resources.CategoryCommon));
b.AddCustomAttributes(nameof(TextToolbar.CustomButtons), new CategoryAttribute(Properties.Resources.CategoryCommon));
b.AddCustomAttributes(nameof(TextToolbar.ButtonModifications), new CategoryAttribute(Properties.Resources.CategoryCommon));
b.AddCustomAttributes(nameof(TextToolbar.Labels), new CategoryAttribute(Properties.Resources.CategoryCommon));
b.AddCustomAttributes(new ToolboxCategoryAttribute(ToolboxCategoryPaths.Toolkit, false));
}
);

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

@ -3,7 +3,22 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit Graph Controls</Title>
<Description>This library provides Microsoft Graph XAML controls. It is part of the Windows Community Toolkit.</Description>
<Description>
This library provides Microsoft Graph XAML controls. It is part of the Windows Community Toolkit.
Classes:
- AadLogin: The AAD Login Control leverages MSAL libraries to support basic AAD sign-in processes for Microsoft Graph and beyond.
- FileSelectedEventArgs: Arguments relating to a file selected event of SharePointFiles control.
- PeoplePicker: The PeoplePicker Control is a simple control that allows for selection of one or more users from an organizational AD.
- PeopleSelectionChangedEventArgs: Arguments relating to the people selected event of PeoplePicker control.
- PlannerTaskList: The PlannerTaskList Control displays a simple list of Planner tasks.
- PowerBIEmbedded: The PowerBI embedded control is a simple wrapper to an IFRAME for a PowerBI embed.
- ProfileCard: The Profile Card control is a simple way to display a user in multiple different formats and mixes of name/image/e-mail.
- SharePointFileList: The SharePointFiles Control displays a simple list of SharePoint Files.
- SignInEventArgs: Arguments relating to a sign-in event of Aadlogin control.
- SignInFailedEventArgs: Arguments relating to a sign-in event of Aadlogin control.
</Description>
<PackageTags>UWP Toolkit Windows Controls Microsoft Graph AadLogin ProfileCard PeoplePicker SharePointFiles</PackageTags>
</PropertyGroup>

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

@ -186,6 +186,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// </summary>
internal void UpdatePosition()
{
if (storyboard?.GetCurrentState() == ClockState.Active)
{
storyboard.SkipToFill();
}
storyboard = new Storyboard();
ManipulationMode = ManipulationModes.None;

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

@ -52,6 +52,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public static readonly DependencyProperty ShadowOpacityProperty =
DependencyProperty.Register(nameof(ShadowOpacity), typeof(double), typeof(DropShadowPanel), new PropertyMetadata(1.0, OnShadowOpacityChanged));
/// <summary>
/// Identifies the <see cref="IsMasked"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsMaskedProperty =
DependencyProperty.Register(nameof(IsMasked), typeof(bool), typeof(DropShadowPanel), new PropertyMetadata(true, OnIsMaskedChanged));
/// <summary>
/// Gets a value indicating whether the platform supports drop shadows.
/// </summary>
@ -182,57 +188,71 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
}
/// <summary>
/// Gets or sets a value indicating whether the panel uses an alpha mask to create a more precise shadow vs. a quicker rectangle shape.
/// </summary>
/// <remarks>
/// Turn this off to lose fidelity and gain performance of the panel.
/// </remarks>
public bool IsMasked
{
get { return (bool)GetValue(IsMaskedProperty); }
set { SetValue(IsMaskedProperty, value); }
}
private static void OnBlurRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported)
if (IsSupported && d is DropShadowPanel panel)
{
var panel = d as DropShadowPanel;
panel?.OnBlurRadiusChanged((double)e.NewValue);
panel.OnBlurRadiusChanged((double)e.NewValue);
}
}
private static void OnColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported)
if (IsSupported && d is DropShadowPanel panel)
{
var panel = d as DropShadowPanel;
panel?.OnColorChanged((Color)e.NewValue);
panel.OnColorChanged((Color)e.NewValue);
}
}
private static void OnOffsetXChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported)
if (IsSupported && d is DropShadowPanel panel)
{
var panel = d as DropShadowPanel;
panel?.OnOffsetXChanged((double)e.NewValue);
panel.OnOffsetXChanged((double)e.NewValue);
}
}
private static void OnOffsetYChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported)
if (IsSupported && d is DropShadowPanel panel)
{
var panel = d as DropShadowPanel;
panel?.OnOffsetYChanged((double)e.NewValue);
panel.OnOffsetYChanged((double)e.NewValue);
}
}
private static void OnOffsetZChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported)
if (IsSupported && d is DropShadowPanel panel)
{
var panel = d as DropShadowPanel;
panel?.OnOffsetZChanged((double)e.NewValue);
panel.OnOffsetZChanged((double)e.NewValue);
}
}
private static void OnShadowOpacityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported)
if (IsSupported && d is DropShadowPanel panel)
{
var panel = d as DropShadowPanel;
panel?.OnShadowOpacityChanged((double)e.NewValue);
panel.OnShadowOpacityChanged((double)e.NewValue);
}
}
private static void OnIsMaskedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (IsSupported && d is DropShadowPanel panel)
{
panel.UpdateShadowMask();
}
}
}

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

@ -162,7 +162,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
return;
}
if (Content != null)
if (Content != null && IsMasked)
{
CompositionBrush mask = null;

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

@ -86,6 +86,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
base.OnApplyTemplate();
SetHeaderVisibility();
SetOrientation();
}
/// <summary>
@ -100,12 +101,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (HeaderedContentControl)d;
var orientation = control.Orientation == Orientation.Vertical
? nameof(Orientation.Vertical)
: nameof(Orientation.Horizontal);
VisualStateManager.GoToState(control, orientation, true);
control.SetOrientation();
}
private static void OnHeaderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@ -119,10 +115,28 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
if (GetTemplateChild(PartHeaderPresenter) is FrameworkElement headerPresenter)
{
headerPresenter.Visibility = Header != null
? Visibility.Visible
: Visibility.Collapsed;
if (Header is string headerText)
{
headerPresenter.Visibility = string.IsNullOrEmpty(headerText)
? Visibility.Collapsed
: Visibility.Visible;
}
else
{
headerPresenter.Visibility = Header != null
? Visibility.Visible
: Visibility.Collapsed;
}
}
}
private void SetOrientation()
{
var orientation = this.Orientation == Orientation.Vertical
? nameof(Orientation.Vertical)
: nameof(Orientation.Horizontal);
VisualStateManager.GoToState(this, orientation, true);
}
}
}

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

@ -332,5 +332,116 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
return !targetRect.IsEmpty && targetRect.Width > 0 && targetRect.Height > 0;
}
private static Point GetSafeSizeChangeWhenKeepAspectRatio(Rect targetRect, ThumbPosition thumbPosition, Rect selectedRect, Point originSizeChange, double aspectRatio)
{
var safeWidthChange = originSizeChange.X;
var safeHeightChange = originSizeChange.Y;
var maxWidthChange = 0d;
var maxHeightChange = 0d;
switch (thumbPosition)
{
case ThumbPosition.Top:
maxWidthChange = targetRect.Width - selectedRect.Width;
maxHeightChange = selectedRect.Top - targetRect.Top;
break;
case ThumbPosition.Bottom:
maxWidthChange = targetRect.Width - selectedRect.Width;
maxHeightChange = targetRect.Bottom - selectedRect.Bottom;
break;
case ThumbPosition.Left:
maxWidthChange = selectedRect.Left - targetRect.Left;
maxHeightChange = targetRect.Height - selectedRect.Height;
break;
case ThumbPosition.Right:
maxWidthChange = targetRect.Right - selectedRect.Right;
maxHeightChange = targetRect.Height - selectedRect.Height;
break;
case ThumbPosition.UpperLeft:
maxWidthChange = selectedRect.Left - targetRect.Left;
maxHeightChange = selectedRect.Top - targetRect.Top;
break;
case ThumbPosition.UpperRight:
maxWidthChange = targetRect.Right - selectedRect.Right;
maxHeightChange = selectedRect.Top - targetRect.Top;
break;
case ThumbPosition.LowerLeft:
maxWidthChange = selectedRect.Left - targetRect.Left;
maxHeightChange = targetRect.Bottom - selectedRect.Bottom;
break;
case ThumbPosition.LowerRight:
maxWidthChange = targetRect.Right - selectedRect.Right;
maxHeightChange = targetRect.Bottom - selectedRect.Bottom;
break;
}
if (originSizeChange.X > maxWidthChange)
{
safeWidthChange = maxWidthChange;
safeHeightChange = safeWidthChange / aspectRatio;
}
if (originSizeChange.Y > maxHeightChange)
{
safeHeightChange = maxHeightChange;
safeWidthChange = safeHeightChange * aspectRatio;
}
return new Point(safeWidthChange, safeHeightChange);
}
private static bool CanContains(Rect targetRect, Rect testRect)
{
return (targetRect.Width - testRect.Width > -ThresholdValue) && (targetRect.Height - testRect.Height > -ThresholdValue);
}
private static bool TryGetContainedRect(Rect targetRect, ref Rect testRect)
{
if (!CanContains(targetRect, testRect))
{
return false;
}
if (targetRect.Left > testRect.Left)
{
testRect.X += targetRect.Left - testRect.Left;
}
if (targetRect.Top > testRect.Top)
{
testRect.Y += targetRect.Top - testRect.Top;
}
if (targetRect.Right < testRect.Right)
{
testRect.X += targetRect.Right - testRect.Right;
}
if (targetRect.Bottom < testRect.Bottom)
{
testRect.Y += targetRect.Bottom - testRect.Bottom;
}
return true;
}
private static bool IsCornerThumb(ThumbPosition thumbPosition)
{
switch (thumbPosition)
{
case ThumbPosition.Top:
case ThumbPosition.Bottom:
case ThumbPosition.Left:
case ThumbPosition.Right:
return false;
case ThumbPosition.UpperLeft:
case ThumbPosition.UpperRight:
case ThumbPosition.LowerLeft:
case ThumbPosition.LowerRight:
return true;
}
return false;
}
}
}

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

@ -112,45 +112,66 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
var startPoint = new Point(_startX, _startY);
var endPoint = new Point(_endX, _endY);
var currentSelectedRect = new Rect(startPoint, endPoint);
switch (position)
{
case ThumbPosition.Top:
startPoint.Y += diffPos.Y;
if (KeepAspectRatio)
{
var changeX = diffPos.Y * UsedAspectRatio;
startPoint.X += changeX / 2;
endPoint.X -= changeX / 2;
var originSizeChange = new Point(-diffPos.Y * UsedAspectRatio, -diffPos.Y);
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
startPoint.X += -safeChange.X / 2;
endPoint.X += safeChange.X / 2;
startPoint.Y += -safeChange.Y;
}
else
{
startPoint.Y += diffPos.Y;
}
break;
case ThumbPosition.Bottom:
endPoint.Y += diffPos.Y;
if (KeepAspectRatio)
{
var changeX = diffPos.Y * UsedAspectRatio;
startPoint.X -= changeX / 2;
endPoint.X += changeX / 2;
var originSizeChange = new Point(diffPos.Y * UsedAspectRatio, diffPos.Y);
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
startPoint.X += -safeChange.X / 2;
endPoint.X += safeChange.X / 2;
endPoint.Y += safeChange.Y;
}
else
{
endPoint.Y += diffPos.Y;
}
break;
case ThumbPosition.Left:
startPoint.X += diffPos.X;
if (KeepAspectRatio)
{
var changeY = diffPos.X / UsedAspectRatio;
startPoint.Y += changeY / 2;
endPoint.Y -= changeY / 2;
var originSizeChange = new Point(-diffPos.X, -diffPos.X / UsedAspectRatio);
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
startPoint.Y += -safeChange.Y / 2;
endPoint.Y += safeChange.Y / 2;
startPoint.X += -safeChange.X;
}
else
{
startPoint.X += diffPos.X;
}
break;
case ThumbPosition.Right:
endPoint.X += diffPos.X;
if (KeepAspectRatio)
{
var changeY = diffPos.X / UsedAspectRatio;
startPoint.Y -= changeY / 2;
endPoint.Y += changeY / 2;
var originSizeChange = new Point(diffPos.X, diffPos.X / UsedAspectRatio);
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
startPoint.Y += -safeChange.Y / 2;
endPoint.Y += safeChange.Y / 2;
endPoint.X += safeChange.X;
}
else
{
endPoint.X += diffPos.X;
}
break;
@ -158,8 +179,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
if (KeepAspectRatio)
{
effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian);
diffPos.X = effectiveLength * Math.Sin(radian);
diffPos.Y = effectiveLength * Math.Cos(radian);
var originSizeChange = new Point(-effectiveLength * Math.Sin(radian), -effectiveLength * Math.Cos(radian));
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
diffPos.X = -safeChange.X;
diffPos.Y = -safeChange.Y;
}
startPoint.X += diffPos.X;
@ -170,8 +193,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
diffPointRadian = -diffPointRadian;
effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian);
diffPos.X = -effectiveLength * Math.Sin(radian);
diffPos.Y = effectiveLength * Math.Cos(radian);
var originSizeChange = new Point(-effectiveLength * Math.Sin(radian), -effectiveLength * Math.Cos(radian));
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
diffPos.X = safeChange.X;
diffPos.Y = -safeChange.Y;
}
endPoint.X += diffPos.X;
@ -182,8 +207,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
diffPointRadian = -diffPointRadian;
effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian);
diffPos.X = -effectiveLength * Math.Sin(radian);
diffPos.Y = effectiveLength * Math.Cos(radian);
var originSizeChange = new Point(effectiveLength * Math.Sin(radian), effectiveLength * Math.Cos(radian));
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
diffPos.X = -safeChange.X;
diffPos.Y = safeChange.Y;
}
startPoint.X += diffPos.X;
@ -193,8 +220,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
if (KeepAspectRatio)
{
effectiveLength = diffPos.Y / Math.Cos(diffPointRadian) * Math.Cos(diffPointRadian - radian);
diffPos.X = effectiveLength * Math.Sin(radian);
diffPos.Y = effectiveLength * Math.Cos(radian);
var originSizeChange = new Point(effectiveLength * Math.Sin(radian), effectiveLength * Math.Cos(radian));
var safeChange = GetSafeSizeChangeWhenKeepAspectRatio(_restrictedSelectRect, position, currentSelectedRect, originSizeChange, UsedAspectRatio);
diffPos.X = safeChange.X;
diffPos.Y = safeChange.Y;
}
endPoint.X += diffPos.X;
@ -223,12 +252,20 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
var isEffectiveRegion = IsSafePoint(_restrictedSelectRect, startPoint) &&
IsSafePoint(_restrictedSelectRect, endPoint);
var selectedRect = new Rect(startPoint, endPoint);
if (!isEffectiveRegion)
{
return;
if (!IsCornerThumb(position) && TryGetContainedRect(_restrictedSelectRect, ref selectedRect))
{
startPoint = new Point(selectedRect.Left, selectedRect.Top);
endPoint = new Point(selectedRect.Right, selectedRect.Bottom);
}
else
{
return;
}
}
var selectedRect = new Rect(startPoint, endPoint);
selectedRect.Union(CanvasRect);
if (selectedRect != CanvasRect)
{

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

@ -412,5 +412,36 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
InitImageLayout(true);
}
/// <summary>
/// Tries to set a new value for the cropped region, returns true if it succeeded, false if the region is invalid
/// </summary>
/// <param name="rect">The new cropped region.</param>
/// <returns>bool</returns>
public bool TrySetCroppedRegion(Rect rect)
{
// Reject regions smaller than the minimum size
if (rect.Width < MinCropSize.Width || rect.Height < MinCropSize.Height)
{
return false;
}
// Reject regions that are not contained in the original picture
if (rect.Left < _restrictedCropRect.Left || rect.Top < _restrictedCropRect.Top || rect.Right > _restrictedCropRect.Right || rect.Bottom > _restrictedCropRect.Bottom)
{
return false;
}
// If an aspect ratio is set, reject regions that don't respect it
// If cropping a circle, reject regions where the aspect ratio is not 1
if (KeepAspectRatio && UsedAspectRatio != rect.Width / rect.Height)
{
return false;
}
_currentCroppedRect = rect;
UpdateImageLayout(true);
return true;
}
}
}

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

@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using Windows.Foundation.Metadata;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Media;
@ -50,6 +51,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// </summary>
public static readonly DependencyProperty CachingStrategyProperty = DependencyProperty.Register(nameof(CachingStrategy), typeof(ImageExCachingStrategy), typeof(ImageExBase), new PropertyMetadata(ImageExCachingStrategy.Custom));
/// <summary>
/// Identifies the <see cref="EnableLazyLoading"/> dependency property.
/// </summary>
public static readonly DependencyProperty EnableLazyLoadingProperty = DependencyProperty.Register(nameof(EnableLazyLoading), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false));
/// <summary>
/// Gets a value indicating whether <see cref="EnableLazyLoading"/> is supported
/// </summary>
public static bool IsLazyLoadingSupported { get; } = ApiInformation.IsEventPresent("Windows.UI.Xaml.FrameworkElement", nameof(EffectiveViewportChanged));
/// <summary>
/// Returns a mask that represents the alpha channel of an image as a <see cref="CompositionBrush"/>
/// </summary>
@ -139,5 +150,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
get { return (ImageExCachingStrategy)GetValue(CachingStrategyProperty); }
set { SetValue(CachingStrategyProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating whether gets or sets is lazy loading enable. (17763 or higher supported)
/// </summary>
/// <remarks>Windows 10 build 17763 or higher required.</remarks>
public bool EnableLazyLoading
{
get { return (bool)GetValue(EnableLazyLoadingProperty); }
set { SetValue(EnableLazyLoadingProperty, value); }
}
}
}

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

@ -27,6 +27,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private Uri _uri;
private bool _isHttpSource;
private CancellationTokenSource _tokenSource = null;
private object _lazyLoadingSource;
/// <summary>
/// Gets or sets the source used by the image
@ -41,9 +42,29 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
var control = d as ImageExBase;
if (control == null)
{
return;
}
if (e.OldValue == null || e.NewValue == null || !e.OldValue.Equals(e.NewValue))
{
control?.SetSource(e.NewValue);
if (IsLazyLoadingSupported)
{
if (e.NewValue == null || !control.EnableLazyLoading || control._isInViewport)
{
control._lazyLoadingSource = null;
control.SetSource(e.NewValue);
}
else
{
control._lazyLoadingSource = e.NewValue;
}
}
else
{
control.SetSource(e.NewValue);
}
}
}

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

@ -21,6 +21,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
[TemplatePart(Name = PartProgress, Type = typeof(ProgressRing))]
public abstract partial class ImageExBase : Control
{
private bool _isInViewport;
/// <summary>
/// Image name in template
/// </summary>
@ -77,6 +79,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public ImageExBase()
{
LockObj = new object();
if (IsLazyLoadingSupported)
{
EffectiveViewportChanged += ImageExBase_EffectiveViewportChanged;
}
}
/// <summary>
@ -170,7 +177,22 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
ImageExInitialized?.Invoke(this, EventArgs.Empty);
SetSource(Source);
if (IsLazyLoadingSupported)
{
if (Source == null || !EnableLazyLoading || _isInViewport)
{
_lazyLoadingSource = null;
SetSource(Source);
}
else
{
_lazyLoadingSource = Source;
}
}
else
{
SetSource(Source);
}
AttachImageOpened(OnImageOpened);
AttachImageFailed(OnImageFailed);
@ -202,5 +224,30 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(new Exception(e.ErrorMessage)));
VisualStateManager.GoToState(this, FailedState, true);
}
private void ImageExBase_EffectiveViewportChanged(FrameworkElement sender, EffectiveViewportChangedEventArgs args)
{
var bringIntoViewDistanceX = args.BringIntoViewDistanceX;
var bringIntoViewDistanceY = args.BringIntoViewDistanceY;
var width = ActualWidth;
var height = ActualHeight;
if (bringIntoViewDistanceX <= width && bringIntoViewDistanceY <= height)
{
_isInViewport = true;
if (_lazyLoadingSource != null)
{
var source = _lazyLoadingSource;
_lazyLoadingSource = null;
SetSource(source);
}
}
else
{
_isInViewport = false;
}
}
}
}

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

@ -44,22 +44,22 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private void DismissTimer_Tick(object sender, object e)
{
_dismissTimer.Stop();
Dismiss(InAppNotificationDismissKind.Timeout);
}
private void OpenAnimationTimer_Tick(object sender, object e)
{
_animationTimer.Stop();
Opened?.Invoke(this, EventArgs.Empty);
SetValue(AutomationProperties.NameProperty, StringExtensions.GetLocalized("WindowsCommunityToolkit_InAppNotification_NameProperty", "/Microsoft.Toolkit.Uwp.UI.Controls/Resources"));
peer = FrameworkElementAutomationPeer.CreatePeerForElement(ContentTemplateRoot);
if (Content?.GetType() == typeof(string))
lock (_openAnimationTimer)
{
AutomateTextNotification(Content.ToString());
_openAnimationTimer.Stop();
Opened?.Invoke(this, EventArgs.Empty);
SetValue(AutomationProperties.NameProperty, StringExtensions.GetLocalized("WindowsCommunityToolkit_InAppNotification_NameProperty", "/Microsoft.Toolkit.Uwp.UI.Controls/Resources"));
peer = FrameworkElementAutomationPeer.CreatePeerForElement(ContentTemplateRoot);
if (Content?.GetType() == typeof(string))
{
AutomateTextNotification(Content.ToString());
}
}
_animationTimer.Tick -= OpenAnimationTimer_Tick;
}
private void AutomateTextNotification(string message)
@ -75,11 +75,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
}
private void DismissAnimationTimer_Tick(object sender, object e)
private void ClosingAnimationTimer_Tick(object sender, object e)
{
_animationTimer.Stop();
Closed?.Invoke(this, new InAppNotificationClosedEventArgs(_lastDismissKind));
_animationTimer.Tick -= DismissAnimationTimer_Tick;
lock (_closingAnimationTimer)
{
_closingAnimationTimer.Stop();
Closed?.Invoke(this, new InAppNotificationClosedEventArgs(_lastDismissKind));
}
}
}
}

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

@ -19,7 +19,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public partial class InAppNotification : ContentControl
{
private InAppNotificationDismissKind _lastDismissKind;
private DispatcherTimer _animationTimer = new DispatcherTimer();
private DispatcherTimer _openAnimationTimer = new DispatcherTimer();
private DispatcherTimer _closingAnimationTimer = new DispatcherTimer();
private DispatcherTimer _dismissTimer = new DispatcherTimer();
private Button _dismissButton;
private VisualStateGroup _visualStateGroup;
@ -33,6 +34,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
DefaultStyleKey = typeof(InAppNotification);
_dismissTimer.Tick += DismissTimer_Tick;
_openAnimationTimer.Tick += OpenAnimationTimer_Tick;
_closingAnimationTimer.Tick += ClosingAnimationTimer_Tick;
}
/// <inheritdoc />
@ -70,29 +73,34 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <param name="duration">Displayed duration of the notification in ms (less or equal 0 means infinite duration)</param>
public void Show(int duration = 0)
{
_animationTimer.Stop();
_dismissTimer.Stop();
lock (_openAnimationTimer)
lock (_closingAnimationTimer)
lock (_dismissTimer)
{
_openAnimationTimer.Stop();
_closingAnimationTimer.Stop();
_dismissTimer.Stop();
var eventArgs = new InAppNotificationOpeningEventArgs();
Opening?.Invoke(this, eventArgs);
var eventArgs = new InAppNotificationOpeningEventArgs();
Opening?.Invoke(this, eventArgs);
if (eventArgs.Cancel)
{
return;
}
if (eventArgs.Cancel)
{
return;
}
Visibility = Visibility.Visible;
VisualStateManager.GoToState(this, StateContentVisible, true);
Visibility = Visibility.Visible;
VisualStateManager.GoToState(this, StateContentVisible, true);
_animationTimer.Interval = AnimationDuration;
_animationTimer.Tick += OpenAnimationTimer_Tick;
_animationTimer.Start();
_openAnimationTimer.Interval = AnimationDuration;
_openAnimationTimer.Start();
if (duration > 0)
{
_dismissTimer.Interval = TimeSpan.FromMilliseconds(duration);
_dismissTimer.Start();
}
if (duration > 0)
{
_dismissTimer.Interval = TimeSpan.FromMilliseconds(duration);
_dismissTimer.Start();
}
}
}
/// <summary>
@ -154,38 +162,54 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <param name="dismissKind">Kind of action that triggered dismiss event</param>
private void Dismiss(InAppNotificationDismissKind dismissKind)
{
if (Visibility == Visibility.Visible)
{
// Continue to display notification if on remaining stacked notification
if (_stackedNotificationOptions.Any())
{
_stackedNotificationOptions.RemoveAt(0);
if (_stackedNotificationOptions.Any())
lock (_openAnimationTimer)
lock (_closingAnimationTimer)
lock (_dismissTimer)
{
DisplayNextStackedNotification(_stackedNotificationOptions[0]);
return;
if (Visibility == Visibility.Visible)
{
_dismissTimer.Stop();
// Continue to display notification if on remaining stacked notification
if (_stackedNotificationOptions.Any())
{
_stackedNotificationOptions.RemoveAt(0);
if (_stackedNotificationOptions.Any())
{
var notificationOptions = _stackedNotificationOptions[0];
UpdateContent(notificationOptions);
if (notificationOptions.Duration > 0)
{
_dismissTimer.Interval = TimeSpan.FromMilliseconds(notificationOptions.Duration);
_dismissTimer.Start();
}
return;
}
}
_openAnimationTimer.Stop();
_closingAnimationTimer.Stop();
var closingEventArgs = new InAppNotificationClosingEventArgs(dismissKind);
Closing?.Invoke(this, closingEventArgs);
if (closingEventArgs.Cancel)
{
return;
}
VisualStateManager.GoToState(this, StateContentCollapsed, true);
_lastDismissKind = dismissKind;
_closingAnimationTimer.Interval = AnimationDuration;
_closingAnimationTimer.Start();
}
}
}
_animationTimer.Stop();
var closingEventArgs = new InAppNotificationClosingEventArgs(dismissKind);
Closing?.Invoke(this, closingEventArgs);
if (closingEventArgs.Cancel)
{
return;
}
VisualStateManager.GoToState(this, StateContentCollapsed, true);
_lastDismissKind = dismissKind;
_animationTimer.Interval = AnimationDuration;
_animationTimer.Tick += DismissAnimationTimer_Tick;
_animationTimer.Start();
}
}
/// <summary>
@ -198,23 +222,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
(StackMode == StackMode.QueueBehind && _stackedNotificationOptions.Count == 0);
}
/// <summary>
/// Display the next stacked notification using StackedNotificationInfo
/// </summary>
/// <param name="notificationOptions">Information to display for the next notification</param>
private void DisplayNextStackedNotification(NotificationOptions notificationOptions)
{
UpdateContent(notificationOptions);
_dismissTimer.Stop();
if (notificationOptions.Duration > 0)
{
_dismissTimer.Interval = TimeSpan.FromMilliseconds(notificationOptions.Duration);
_dismissTimer.Start();
}
}
/// <summary>
/// Update the Content of the notification
/// </summary>

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

@ -2,8 +2,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:contract5Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,5)"
xmlns:contract5NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,5)">
xmlns:contract7Present="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractPresent(Windows.Foundation.UniversalApiContract,7)"
xmlns:contract7NotPresent="http://schemas.microsoft.com/winfx/2006/xaml/presentation?IsApiContractNotPresent(Windows.Foundation.UniversalApiContract,7)">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls/InAppNotification/Styles/MSEdgeNotificationStyle.xaml" />
@ -31,11 +31,11 @@
<Setter Property="Template" Value="{StaticResource MSEdgeNotificationTemplate}" />
</Style>
<contract5NotPresent:Style TargetType="local:InAppNotification" BasedOn="{StaticResource BaseInAppNotificationsStyle}">
<contract7NotPresent:Style TargetType="local:InAppNotification" BasedOn="{StaticResource BaseInAppNotificationsStyle}">
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
</contract5NotPresent:Style>
</contract7NotPresent:Style>
<contract5Present:Style TargetType="local:InAppNotification" BasedOn="{StaticResource BaseInAppNotificationsStyle}">
<contract7Present:Style TargetType="local:InAppNotification" BasedOn="{StaticResource BaseInAppNotificationsStyle}">
<Setter Property="Background" Value="{ThemeResource SystemControlChromeMediumLowAcrylicElementMediumBrush}" />
</contract5Present:Style>
</contract7Present:Style>
</ResourceDictionary>

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

@ -3,13 +3,52 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit Controls</Title>
<Description>This library provides XAML templated controls. It is part of the Windows Community Toolkit.</Description>
<Description>
This library provides XAML templated controls. It is part of the Windows Community Toolkit.
Controls:
- AdaptiveGridView: Presents items in a evenly-spaced set of columns to fill the total available display space.
- BladeView: BladeView provides a horizontal collection of blades for master-detail scenarios. The control is based on the experience demonstrated by the Azure Portal.
- CameraPreview: Allows to easily preview video from available camera frame source groups and also get realtime video frames/ software bitmaps from the selected source.
- Carousel: Presents items in a carousel control. It reacts to changes in the layout as well as the content so it can adapt to different form factors automatically.
- DataGrid: Control that presents data in a customizable table of rows and columns.
- DockPanel: Defines an area where you can arrange child elements either horizontally or vertically, relative to each other.
- DropShadowPanel: DropShadowPanel contol allows the creation of a DropShadow for any Xaml FrameworkElement in markup.
- Expander: Expander control allows user to show/hide content based on a boolean state.
- GridSplitter: GridSplitter represents the control that redistributes space between columns or rows of a Grid control.
- HeaderedContentControl: Allows content to be displayed with a specified header.
- HeaderedItemsControl: Allows items to be displayed with a specified header.
- HeaderedTextBlock: The HeaderedTextBlock control is designed to provide a header for read only text. This control is useful for displaying read only forms.
- ImageCropper: ImageCropper control allows user to crop image freely.
- ImageEx: Images are downloaded asynchronously showing a load indicator. Source images are then stored in the App local cache to preserve resources and load time.
- InAppNotification: The In App Notification control offers the ability to show local notifications in your application.
- InfiniteCanvas: InfiniteCanvas is a canvas that supports Infinite Scrolling, Ink, Text, Format Text, Zoom in/out, Redo, Undo, Export canvas data, Import canvas data.
- LayoutTransformControl: Control that implements support for transformations as if applied by LayoutTransform.
- Loading: LoadingControl helps to show content with animation to the user while the app is doing some calculation.
- MarkdownTextBlock: An efficient and extensible control that can parse and render markdown.
- MasterDetailsView: The MasterDetailsView control allows the user to implement the Master/Details design pattern.
- Menu: This control will be removed in a future major release. Please use the MenuBar control from the WinUI Library instead.
- OrbitView: The OrbitView Control positions items in a circle around a center element and supports orbits and anchors.
- RadialGauge: The radial gauge displays a value within a range, using a needle on a circular face.
- RadialProgressBar: The radial progress bar displays progress as a circle getting filled.
- RangeSelector: The RangeSelector is a "double slider" control for range values.
- RemoteDevicePicker: Remote Device Picker Control for Project Rome.
- RotatorTile: RotatorTile is an ItemsControl that rotates through a set of items one-by-one. It enables you to show multiple items of data in a live-tile like way.
- ScrollHeader: A UI control that works as a ListView or GridView header control with quick return, sticky and fade behavior.
- StaggeredPanel: The StaggeredPanel allows for layout of items in a column approach where an item will be added to whichever column has used the least amount of space.
- TabView: A control for displaying multiple items in the same space and allows a user to easily switch between them.
- TextToolbar: A Toolbar for Editing Text attached to a RichEditBox. It can format RTF and Markdown, or use a Custom Formatter, and specify your own Formatter with Buttons and Actions.
- TileControl: A ContentControl that show an image repeated many times.The control can be synchronized with a Scrollviewer and animated easily.
- UniformGrid: Presents items in a evenly-spaced set of rows or columns to fill the total available display space.
- WrapPanel: The WrapPanel Control positions child elements in sequential position from left to right, breaking content to the next line at the edge of the containing box.
</Description>
<PackageTags>UWP Toolkit Windows Controls XAML Range WrapPanel Adaptive Markdown BladeView Blade CameraPreview Camera Carousel DockPanel DropShadow Expander GridSplitter HeaderedContent ImageEx InAppNotification InfiniteCanvas Master Details MasterDetails Menu Orbit Radial Gauge RadiaGauge RadialProgressBar Scroll ScrollHeader StaggeredPanel Staggered Tile UniformGrid Uniform Grid</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ColorCode.UWP" Version="2.0.6" />
<PackageReference Include="Robmikh.CompositionSurfaceFactory" Version="0.7.3" />
<PackageReference Include="System.ValueTuple" Version="4.4.0" />
<ProjectReference Include="..\Microsoft.Toolkit.Uwp.UI.Animations\Microsoft.Toolkit.Uwp.UI.Animations.csproj" />
<ProjectReference Include="..\Microsoft.Toolkit.Parsers\Microsoft.Toolkit.Parsers.csproj" />

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

@ -12,6 +12,7 @@ using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Automation.Peers;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
@ -27,20 +28,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
[TemplatePart(Name = ScalePartName, Type = typeof(Path))]
[TemplatePart(Name = TrailPartName, Type = typeof(Path))]
[TemplatePart(Name = ValueTextPartName, Type = typeof(TextBlock))]
public class RadialGauge : Control
public class RadialGauge : RangeBase
{
/// <summary>
/// Identifies the Minimum dependency property.
/// </summary>
public static readonly DependencyProperty MinimumProperty =
DependencyProperty.Register(nameof(Minimum), typeof(double), typeof(RadialGauge), new PropertyMetadata(0.0, OnScaleChanged));
/// <summary>
/// Identifies the Maximum dependency property.
/// </summary>
public static readonly DependencyProperty MaximumProperty =
DependencyProperty.Register(nameof(Maximum), typeof(double), typeof(RadialGauge), new PropertyMetadata(100.0, OnScaleChanged));
/// <summary>
/// Identifies the optional StepSize property.
/// </summary>
@ -65,12 +54,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public static readonly DependencyProperty NeedleBrushProperty =
DependencyProperty.Register(nameof(NeedleBrush), typeof(SolidColorBrush), typeof(RadialGauge), new PropertyMetadata(null, OnFaceChanged));
/// <summary>
/// Identifies the Value dependency property.
/// </summary>
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(double), typeof(RadialGauge), new PropertyMetadata(0.0, OnValueChanged));
/// <summary>
/// Identifies the Unit dependency property.
/// </summary>
@ -200,6 +183,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
DefaultStyleKey = typeof(RadialGauge);
SmallChange = 1;
LargeChange = 10;
Unloaded += RadialGauge_Unloaded;
}
@ -210,22 +195,22 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private void RadialGauge_KeyDown(object sender, KeyRoutedEventArgs e)
{
double step = 1;
double step = SmallChange;
var ctrl = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
if (ctrl.HasFlag(CoreVirtualKeyStates.Down))
{
step = 5;
step = LargeChange;
}
step = Math.Max(StepSize, step);
if (e.Key == VirtualKey.Left)
if ((e.Key == VirtualKey.Left) || (e.Key == VirtualKey.Down))
{
Value = Math.Max(Minimum, Value - step);
e.Handled = true;
return;
}
if (e.Key == VirtualKey.Right)
if ((e.Key == VirtualKey.Right) || (e.Key == VirtualKey.Up))
{
Value = Math.Min(Maximum, Value + step);
e.Handled = true;
@ -241,24 +226,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
Unloaded -= RadialGauge_Unloaded;
}
/// <summary>
/// Gets or sets the minimum value of the scale.
/// </summary>
public double Minimum
{
get { return (double)GetValue(MinimumProperty); }
set { SetValue(MinimumProperty, value); }
}
/// <summary>
/// Gets or sets the maximum value of the scale.
/// </summary>
public double Maximum
{
get { return (double)GetValue(MaximumProperty); }
set { SetValue(MaximumProperty, value); }
}
/// <summary>
/// Gets or sets the rounding interval for the Value.
/// </summary>
@ -286,15 +253,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
set { SetValue(ScaleWidthProperty, value); }
}
/// <summary>
/// Gets or sets the current value.
/// </summary>
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
/// <summary>
/// Gets or sets the displayed unit measure.
/// </summary>
@ -492,9 +450,25 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
base.OnApplyTemplate();
}
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
/// <inheritdoc/>
protected override void OnMinimumChanged(double oldMinimum, double newMinimum)
{
OnValueChanged(d);
base.OnMinimumChanged(oldMinimum, newMinimum);
OnScaleChanged(this);
}
/// <inheritdoc/>
protected override void OnMaximumChanged(double oldMaximum, double newMaximum)
{
base.OnMaximumChanged(oldMaximum, newMaximum);
OnScaleChanged(this);
}
/// <inheritdoc/>
protected override void OnValueChanged(double oldValue, double newValue)
{
OnValueChanged(this);
base.OnValueChanged(oldValue, newValue);
}
private static void OnValueChanged(DependencyObject d)

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

@ -152,6 +152,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
_minThumb.DragDelta += MinThumb_DragDelta;
_minThumb.DragStarted += MinThumb_DragStarted;
_minThumb.KeyDown += MinThumb_KeyDown;
_minThumb.KeyUp += Thumb_KeyUp;
}
if (_maxThumb != null)
@ -160,6 +161,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
_maxThumb.DragDelta += MaxThumb_DragDelta;
_maxThumb.DragStarted += MaxThumb_DragStarted;
_maxThumb.KeyDown += MaxThumb_KeyDown;
_maxThumb.KeyUp += Thumb_KeyUp;
}
if (_containerCanvas != null)
@ -189,12 +191,22 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
case VirtualKey.Left:
RangeMin -= StepFrequency;
SyncThumbs();
SyncThumbs(fromMinKeyDown: true);
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Visible;
}
e.Handled = true;
break;
case VirtualKey.Right:
RangeMin += StepFrequency;
SyncThumbs();
SyncThumbs(fromMinKeyDown: true);
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Visible;
}
e.Handled = true;
break;
}
@ -206,12 +218,38 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
case VirtualKey.Left:
RangeMax -= StepFrequency;
SyncThumbs();
SyncThumbs(fromMaxKeyDown: true);
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Visible;
}
e.Handled = true;
break;
case VirtualKey.Right:
RangeMax += StepFrequency;
SyncThumbs();
SyncThumbs(fromMaxKeyDown: true);
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Visible;
}
e.Handled = true;
break;
}
}
private void Thumb_KeyUp(object sender, KeyRoutedEventArgs e)
{
switch (e.Key)
{
case VirtualKey.Left:
case VirtualKey.Right:
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Collapsed;
}
e.Handled = true;
break;
}
@ -240,6 +278,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
ValueChanged?.Invoke(this, new RangeChangedEventArgs(RangeMax, normalizedPosition, RangeSelectorProperty.MaximumValue));
}
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Collapsed;
}
VisualStateManager.GoToState(this, "Normal", false);
}
@ -262,6 +305,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
SyncThumbs();
if (_toolTip != null)
{
_toolTip.Visibility = Visibility.Collapsed;
}
}
private void ContainerCanvas_PointerMoved(object sender, PointerRoutedEventArgs e)
@ -586,7 +634,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private static void UpdateToolTipText(RangeSelector rangeSelector, TextBlock toolTip, double newValue)
{
toolTip.Text = string.Format("{0:0.##}", newValue);
if (toolTip != null)
{
toolTip.Text = string.Format("{0:0.##}", newValue);
}
}
/// <summary>
@ -636,7 +687,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
}
private void SyncThumbs()
private void SyncThumbs(bool fromMinKeyDown = false, bool fromMaxKeyDown = false)
{
if (_containerCanvas == null)
{
@ -649,6 +700,19 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
Canvas.SetLeft(_minThumb, relativeLeft);
Canvas.SetLeft(_maxThumb, relativeRight);
if (fromMinKeyDown || fromMaxKeyDown)
{
DragThumb(
fromMinKeyDown ? _minThumb : _maxThumb,
fromMinKeyDown ? 0 : Canvas.GetLeft(_minThumb),
fromMinKeyDown ? Canvas.GetLeft(_maxThumb) : DragWidth(),
fromMinKeyDown ? relativeLeft : relativeRight);
if (_toolTipText != null)
{
UpdateToolTipText(this, _toolTipText, fromMinKeyDown ? RangeMin : RangeMax);
}
}
SyncActiveRectangle();
}

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

@ -1,41 +1,43 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:animations="using:Microsoft.Toolkit.Uwp.UI.Animations"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls">
<Style x:Key="SliderThumbStyle" TargetType="Thumb">
<Setter Property="UseSystemFocusVisuals" Value="True"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Background" Value="{ThemeResource SliderThumbBackground}"/>
<Setter Property="Height" Value="24"/>
<Setter Property="Width" Value="8"/>
<Setter Property="FocusVisualMargin" Value="-14,-6,-14,-6"/>
<Style x:Key="SliderThumbStyle"
TargetType="Thumb">
<Setter Property="UseSystemFocusVisuals" Value="True" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Background" Value="{ThemeResource SliderThumbBackground}" />
<Setter Property="Height" Value="24" />
<Setter Property="Width" Value="8" />
<Setter Property="FocusVisualMargin" Value="-14,-6,-14,-6" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="4"/>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="4" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="controls:RangeSelector">
<Setter Property="Background" Value="{ThemeResource SliderTrackFill}"/>
<Setter Property="BorderThickness" Value="{ThemeResource SliderBorderThemeThickness}"/>
<Setter Property="Foreground" Value="{ThemeResource SliderTrackValueFill}"/>
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
<Setter Property="VerticalAlignment" Value="Top"/>
<Setter Property="Background" Value="{ThemeResource SliderTrackFill}" />
<Setter Property="BorderThickness" Value="{ThemeResource SliderBorderThemeThickness}" />
<Setter Property="Foreground" Value="{ThemeResource SliderTrackValueFill}" />
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:RangeSelector">
<Grid x:Name="ControlGrid" Height="24" >
<Grid x:Name="ControlGrid"
Height="24">
<Border x:Name="OutOfRangeContentContainer"
Background="Transparent"
Grid.Column="1">
Grid.Column="1"
Background="Transparent">
<Rectangle x:Name="BackgroundElement"
Height="2"
Fill="{TemplateBinding Background}" />
@ -45,25 +47,39 @@
Grid.Column="1"
Background="Transparent">
<Rectangle x:Name="ActiveRectangle"
HorizontalAlignment="Stretch"
Height="2"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Fill="{TemplateBinding Foreground}" />
<Grid x:Name="ToolTip"
BorderThickness="1"
<Grid x:Name="ToolTip"
Margin="0,-44,0,8"
Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}"
BorderBrush="{ThemeResource SystemControlForegroundChromeHighBrush}"
Background="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}"
Margin="0,-44,0,8"
BorderThickness="1"
Visibility="Collapsed">
<TextBlock x:Name="ToolTipText"
<animations:Implicit.ShowAnimations>
<animations:OpacityAnimation From="0"
To="1.0"
Duration="0:0:0.3" />
</animations:Implicit.ShowAnimations>
<animations:Implicit.HideAnimations>
<animations:ScalarAnimation Target="Opacity"
To="0"
Duration="0:0:1">
<animations:ScalarKeyFrame Key="0.7"
Value="1.0" />
</animations:ScalarAnimation>
</animations:Implicit.HideAnimations>
<TextBlock x:Name="ToolTipText"
Margin="8"
Foreground="{ThemeResource SystemControlForegroundBaseHighBrush}" />
</Grid>
<Thumb x:Name="MinThumb"
AutomationProperties.Name="Min thumb"
IsTabStop="True"
IsTabStop="True"
Style="{StaticResource SliderThumbStyle}"
TabIndex="0" />
<Thumb x:Name="MaxThumb"

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

@ -247,7 +247,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
sb.Completed += async (a, b) =>
{
if (_currentElement != null)
if (_currentElement != null && _nextElement != null)
{
_currentElement.DataContext = _nextElement.DataContext;
}
@ -475,7 +475,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
else if (e.NewStartingIndex == _currentIndex + 1)
{
// Upcoming item was changed, so update the datacontext
_nextElement.DataContext = GetNext();
if (_nextElement != null)
{
_nextElement.DataContext = GetNext();
}
}
}
}
@ -497,7 +500,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
else if (_currentIndex + 1 == e.NewStartingIndex)
{
// Upcoming item was changed, so update the datacontext
_nextElement.DataContext = GetNext();
if (_nextElement != null)
{
_nextElement.DataContext = GetNext();
}
}
}
}
@ -557,7 +563,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
if (index > -1)
{
ctrl._currentIndex = index;
ctrl._nextElement.DataContext = e.NewValue;
if (ctrl._nextElement != null)
{
ctrl._nextElement.DataContext = e.NewValue;
}
ctrl.RotateToNextItem();
ctrl._timer.Stop();
ctrl._timer.Start();

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

@ -70,34 +70,90 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
typeof(StaggeredPanel),
new PropertyMetadata(default(Thickness), OnPaddingChanged));
/// <summary>
/// Gets or sets the spacing between columns of items.
/// </summary>
public double ColumnSpacing
{
get { return (double)GetValue(ColumnSpacingProperty); }
set { SetValue(ColumnSpacingProperty, value); }
}
/// <summary>
/// Identifies the <see cref="ColumnSpacing"/> dependency property.
/// </summary>
public static readonly DependencyProperty ColumnSpacingProperty = DependencyProperty.Register(
nameof(ColumnSpacing),
typeof(double),
typeof(StaggeredPanel),
new PropertyMetadata(0d, OnPaddingChanged));
/// <summary>
/// Gets or sets the spacing between rows of items.
/// </summary>
public double RowSpacing
{
get { return (double)GetValue(RowSpacingProperty); }
set { SetValue(RowSpacingProperty, value); }
}
/// <summary>
/// Identifies the <see cref="RowSpacing"/> dependency property.
/// </summary>
public static readonly DependencyProperty RowSpacingProperty = DependencyProperty.Register(
nameof(RowSpacing),
typeof(double),
typeof(StaggeredPanel),
new PropertyMetadata(0d, OnPaddingChanged));
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
availableSize.Width = availableSize.Width - Padding.Left - Padding.Right;
availableSize.Height = availableSize.Height - Padding.Top - Padding.Bottom;
double availableWidth = availableSize.Width - Padding.Left - Padding.Right;
double availableHeight = availableSize.Height - Padding.Top - Padding.Bottom;
_columnWidth = Math.Min(DesiredColumnWidth, availableWidth);
int numColumns = Math.Max(1, (int)Math.Floor(availableWidth / _columnWidth));
// adjust for column spacing on all columns expect the first
double totalWidth = _columnWidth + ((numColumns - 1) * (_columnWidth + ColumnSpacing));
if (totalWidth > availableWidth)
{
numColumns--;
}
else if (double.IsInfinity(availableWidth))
{
availableWidth = totalWidth;
}
_columnWidth = Math.Min(DesiredColumnWidth, availableSize.Width);
int numColumns = (int)Math.Floor(availableSize.Width / _columnWidth);
if (HorizontalAlignment == HorizontalAlignment.Stretch)
{
_columnWidth = availableSize.Width / numColumns;
availableWidth = availableWidth - ((numColumns - 1) * ColumnSpacing);
_columnWidth = availableWidth / numColumns;
}
if (Children.Count == 0)
{
return new Size(0, 0);
}
var columnHeights = new double[numColumns];
var itemsPerColumn = new double[numColumns];
for (int i = 0; i < Children.Count; i++)
{
var columnIndex = GetColumnIndex(columnHeights);
var child = Children[i];
child.Measure(new Size(_columnWidth, availableSize.Height));
child.Measure(new Size(_columnWidth, availableHeight));
var elementSize = child.DesiredSize;
columnHeights[columnIndex] += elementSize.Height;
columnHeights[columnIndex] += elementSize.Height + (itemsPerColumn[columnIndex] > 0 ? RowSpacing : 0);
itemsPerColumn[columnIndex]++;
}
double desiredHeight = columnHeights.Max();
return new Size(availableSize.Width, desiredHeight);
return new Size(availableWidth, desiredHeight);
}
/// <inheritdoc/>
@ -105,7 +161,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
double horizontalOffset = Padding.Left;
double verticalOffset = Padding.Top;
int numColumns = (int)Math.Floor(finalSize.Width / _columnWidth);
int numColumns = Math.Max(1, (int)Math.Floor(finalSize.Width / _columnWidth));
// adjust for horizontal spacing on all columns expect the first
double totalWidth = _columnWidth + ((numColumns - 1) * (_columnWidth + ColumnSpacing));
if (totalWidth > finalSize.Width)
{
numColumns--;
}
if (HorizontalAlignment == HorizontalAlignment.Right)
{
horizontalOffset += finalSize.Width - (numColumns * _columnWidth);
@ -116,6 +180,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
var columnHeights = new double[numColumns];
var itemsPerColumn = new double[numColumns];
for (int i = 0; i < Children.Count; i++)
{
@ -124,19 +189,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
var child = Children[i];
var elementSize = child.DesiredSize;
double elementWidth = elementSize.Width;
double elementHeight = elementSize.Height;
if (elementWidth > _columnWidth)
{
double differencePercentage = _columnWidth / elementWidth;
elementHeight = elementHeight * differencePercentage;
elementWidth = _columnWidth;
}
Rect bounds = new Rect(horizontalOffset + (_columnWidth * columnIndex), columnHeights[columnIndex] + verticalOffset, elementWidth, elementHeight);
double itemHorizontalOffset = horizontalOffset + (_columnWidth * columnIndex) + (ColumnSpacing * columnIndex);
double itemVerticalOffset = columnHeights[columnIndex] + verticalOffset + (RowSpacing * itemsPerColumn[columnIndex]);
Rect bounds = new Rect(itemHorizontalOffset, itemVerticalOffset, _columnWidth, elementHeight);
child.Arrange(bounds);
columnHeights[columnIndex] += elementSize.Height;
itemsPerColumn[columnIndex]++;
}
return base.ArrangeOverride(finalSize);
@ -175,4 +237,4 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
return columnIndex;
}
}
}
}

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

@ -117,6 +117,82 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="TextToolbarStrings_BoldLabel" xml:space="preserve">
<value>Bold</value>
<comment>Label for TextToolbar Control bold button.</comment>
</data>
<data name="TextToolbarStrings_CancelLabel" xml:space="preserve">
<value>Cancel</value>
<comment>Label for TextToolbar Control Cancel message.</comment>
</data>
<data name="TextToolbarStrings_CodeLabel" xml:space="preserve">
<value>Code</value>
<comment>Label for TextToolbar Control Code button.</comment>
</data>
<data name="TextToolbarStrings_CreateLinkLabel" xml:space="preserve">
<value>Create Link</value>
<comment>Label for TextToolbar Control Create Link button.</comment>
</data>
<data name="TextToolbarStrings_EmptyTextLabel" xml:space="preserve">
<value>Empty Text</value>
<comment>Label for TextToolbar Control Empty Text.</comment>
</data>
<data name="TextToolbarStrings_HeaderLabel" xml:space="preserve">
<value>Header</value>
<comment>Label for TextToolbar Control Header button.</comment>
</data>
<data name="TextToolbarStrings_ItalicsLabel" xml:space="preserve">
<value>Italics</value>
<comment>Label for TextToolbar Control italics button.</comment>
</data>
<data name="TextToolbarStrings_LabelLabel" xml:space="preserve">
<value>Label</value>
<comment>Label for TextToolbar Control Label button.</comment>
</data>
<data name="TextToolbarStrings_LinkInvalidLabel" xml:space="preserve">
<value>Link Invalid</value>
<comment>Label for TextToolbar Control Link Invalid message.</comment>
</data>
<data name="TextToolbarStrings_LinkLabel" xml:space="preserve">
<value>Link</value>
<comment>Label for TextToolbar Control Link button.</comment>
</data>
<data name="TextToolbarStrings_ListLabel" xml:space="preserve">
<value>List</value>
<comment>Label for TextToolbar Control List button.</comment>
</data>
<data name="TextToolbarStrings_OkLabel" xml:space="preserve">
<value>Ok</value>
<comment>Label for TextToolbar Control Ok message.</comment>
</data>
<data name="TextToolbarStrings_OrderedListLabel" xml:space="preserve">
<value>Ordered List</value>
<comment>Label for TextToolbar Control Ordered List button.</comment>
</data>
<data name="TextToolbarStrings_QuoteLabel" xml:space="preserve">
<value>Quote</value>
<comment>Label for TextToolbar Control Quote button.</comment>
</data>
<data name="TextToolbarStrings_RelativeLabel" xml:space="preserve">
<value>Relative</value>
<comment>Label for TextToolbar Control Relative.</comment>
</data>
<data name="TextToolbarStrings_StrikethroughLabel" xml:space="preserve">
<value>Strikethrough</value>
<comment>Label for TextToolbar Control Strikethrough button.</comment>
</data>
<data name="TextToolbarStrings_UnderlineLabel" xml:space="preserve">
<value>Underline</value>
<comment>Label for TextToolbar Control Underline button.</comment>
</data>
<data name="TextToolbarStrings_UrlLabel" xml:space="preserve">
<value>Url</value>
<comment>Label for TextToolbar Control Url button.</comment>
</data>
<data name="TextToolbarStrings_WarningLabel" xml:space="preserve">
<value>Warning</value>
<comment>Label for TextToolbar Control Warning message.</comment>
</data>
<data name="WindowsCommunityToolkit_BladeView_ExpandButton_Collapsed" xml:space="preserve">
<value>Collapse Blade</value>
<comment>Narrator Resource for BladeView collapsed status</comment>

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

@ -191,6 +191,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
var tabitem = element as TabViewItem;
tabitem.Loaded -= TabViewItem_Loaded;
tabitem.Closing -= TabViewItem_Closing;
tabitem.Loaded += TabViewItem_Loaded;
tabitem.Closing += TabViewItem_Closing;

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

@ -4,6 +4,8 @@
using System;
using Windows.Devices.Input;
using Windows.System;
using Windows.UI.Core;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@ -58,8 +60,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <inheritdoc/>
protected override void OnPointerPressed(PointerRoutedEventArgs e)
{
base.OnPointerPressed(e);
_isMiddleClick = false;
if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
@ -71,7 +71,24 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
_isMiddleClick = true;
}
// Disable unwanted behaviour inherited by ListViewItem:
// Disable "Ctrl + Left click" to deselect tab
// Or variant like "Ctrl + Shift + Left click"
// Or "Ctrl + Alt + Left click"
if (pointerPoint.Properties.IsLeftButtonPressed)
{
var ctrl = Window.Current.CoreWindow.GetKeyState(VirtualKey.Control);
if (ctrl.HasFlag(CoreVirtualKeyStates.Down))
{
// return here so the event won't be picked up by the base class
// but keep this event unhandled so it can be picked up further
return;
}
}
}
base.OnPointerPressed(e);
}
/// <inheritdoc/>

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

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.Extensions;
using Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons;
namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
@ -43,6 +44,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
{
var select = Formatter.Selected;
int originalStart = Formatter.Selected.StartPosition;
string urlLabel = StringExtensions.GetLocalized("TextToolbarStrings_UrlLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources");
string labelLabel = StringExtensions.GetLocalized("TextToolbarStrings_LabelLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources");
// Replaces Selection of first Line only.
if (select.Text.Contains("\r"))
@ -54,14 +57,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
{
if (!string.IsNullOrWhiteSpace(link))
{
Formatter.SetSelection($"[{Formatter.Model.Labels.LabelLabel}](", ")", false, link);
Formatter.SetSelection($"[{labelLabel}](", ")", false, link);
select.StartPosition = select.EndPosition;
select.EndPosition = select.StartPosition;
}
else
{
string startChars = $"[{Formatter.Model.Labels.LabelLabel}](";
string filler = Formatter.Model.Labels.UrlLabel;
string startChars = $"[{labelLabel}](";
string filler = urlLabel;
Formatter.SetSelection(startChars, ")", false, filler);
select.StartPosition = originalStart + startChars.Length;
select.EndPosition = select.StartPosition + filler.Length;
@ -69,7 +72,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
}
else if (string.IsNullOrWhiteSpace(link))
{
Formatter.SetSelection($"[{label}](", ")", false, Formatter.Model.Labels.UrlLabel);
Formatter.SetSelection($"[{label}](", ")", false, urlLabel);
}
else
{

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

@ -4,6 +4,7 @@
using System;
using System.Linq;
using Microsoft.Toolkit.Uwp.Extensions;
using Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons;
using Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common;
using Windows.UI.Text;
@ -47,7 +48,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
{
Content = new MarkdownTextBlock
{
Text = val + Model.Labels.HeaderLabel,
Text = val + StringExtensions.GetLocalized("TextToolbarStrings_HeaderLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
IsTextSelectionEnabled = false
},
Tag = val,
@ -455,7 +456,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
QuoteButton = new ToolbarButton
{
Name = TextToolbar.QuoteElement,
ToolTip = Model.Labels.QuoteLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_QuoteLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new SymbolIcon { Symbol = Symbol.Message },
Activation = FormatQuote
};
@ -472,13 +473,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.MarkDown
{
Name = TextToolbar.HeadersElement,
Icon = new SymbolIcon { Symbol = Symbol.FontSize },
ToolTip = Model.Labels.HeaderLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_HeaderLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Activation = StyleHeader
},
new ToolbarButton
{
Name = TextToolbar.CodeElement,
ToolTip = Model.Labels.CodeLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_CodeLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new FontIcon { Glyph = "{}", FontFamily = new FontFamily("Segoe UI"), Margin = new Thickness(0, -5, 0, 0) },
Activation = FormatCode
},

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

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.Extensions;
using Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons;
using Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common;
using Windows.System;
@ -122,7 +123,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarFormats.RichText
StrikeButton = CommonButtons.Strikethrough;
Underline = new ToolbarButton
{
ToolTip = Model.Labels.UnderlineLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_UnderlineLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new SymbolIcon { Symbol = Symbol.Underline },
ShortcutKey = VirtualKey.U,
Activation = ((RichTextButtonActions)ButtonActions).FormatUnderline

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

@ -51,12 +51,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public static readonly DependencyProperty DefaultButtonModificationsProperty =
DependencyProperty.Register(nameof(ButtonModifications), typeof(DefaultButtonModificationList), typeof(TextToolbar), new PropertyMetadata(null, OnDefaultButtonModificationsChanged));
/// <summary>
/// Identifies the <see cref="Labels"/> dependency property.
/// </summary>
public static readonly DependencyProperty LabelsProperty =
DependencyProperty.Register(nameof(Labels), typeof(TextToolbarStrings), typeof(TextToolbar), new PropertyMetadata(new TextToolbarStrings()));
/// <summary>
/// Identifies the <see cref="UseURIChecker"/> dependency property.
/// </summary>
@ -96,7 +90,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public ButtonMap DefaultButtons
{
get { return (ButtonMap)GetValue(DefaultButtonsProperty); }
private set { SetValue(DefaultButtonsProperty, value); }
private set { SetValue(DefaultButtonsProperty, value); }
}
/// <summary>
@ -117,15 +111,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
set { SetValue(DefaultButtonModificationsProperty, value); }
}
/// <summary>
/// Gets or sets the default string Labels
/// </summary>
public TextToolbarStrings Labels
{
get { return (TextToolbarStrings)GetValue(LabelsProperty); }
set { SetValue(LabelsProperty, value); }
}
/// <summary>
/// Gets the last key pressed using the Editor.
/// </summary>

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

@ -1,299 +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.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Strings for TextToolbar Tooltips and UI.
/// </summary>
public partial class TextToolbarStrings : DependencyObject
{
/// <summary>
/// Identifies the <see cref="BoldLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty BoldLabelProperty =
DependencyProperty.Register(nameof(BoldLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Bold"));
/// <summary>
/// Identifies the <see cref="ItalicsLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty ItalicsLabelProperty =
DependencyProperty.Register(nameof(ItalicsLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Italics"));
/// <summary>
/// Identifies the <see cref="StrikethroughLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty StrikethroughLabelProperty =
DependencyProperty.Register(nameof(StrikethroughLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Strikethrough"));
/// <summary>
/// Identifies the <see cref="QuoteLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty QuoteLabelProperty =
DependencyProperty.Register(nameof(QuoteLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Quote"));
/// <summary>
/// Identifies the <see cref="CodeLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty CodeLabelProperty =
DependencyProperty.Register(nameof(CodeLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Code"));
/// <summary>
/// Identifies the <see cref="ListLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty ListLabelProperty =
DependencyProperty.Register(nameof(ListLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("List"));
/// <summary>
/// Identifies the <see cref="OrderedListLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty OrderedListLabelProperty =
DependencyProperty.Register(nameof(OrderedListLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Ordered List"));
/// <summary>
/// Identifies the <see cref="LinkLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty LinkLabelProperty =
DependencyProperty.Register(nameof(LinkLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Link"));
/// <summary>
/// Identifies the <see cref="CreateLinkLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty CreateLinkLabelProperty =
DependencyProperty.Register(nameof(CreateLinkLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Create Link"));
/// <summary>
/// Identifies the <see cref="UrlLabelProperty"/> dependency property.
/// </summary>
public static readonly DependencyProperty UrlLabelProperty =
DependencyProperty.Register(nameof(UrlLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Url"));
/// <summary>
/// Identifies the <see cref="LabelLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty LabelLabelProperty =
DependencyProperty.Register(nameof(LabelLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Label"));
/// <summary>
/// Identifies the <see cref="OkLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty OkLabelProperty =
DependencyProperty.Register(nameof(OkLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("OK"));
/// <summary>
/// Identifies the <see cref="CancelLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty CancelLabelProperty =
DependencyProperty.Register(nameof(CancelLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Cancel"));
/// <summary>
/// Identifies the <see cref="UnderlineLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty UnderlineLabelProperty =
DependencyProperty.Register(nameof(UnderlineLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Underline"));
/// <summary>
/// Identifies the <see cref="HeaderLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty HeaderLabelProperty =
DependencyProperty.Register(nameof(HeaderLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Header"));
/// <summary>
/// Identifies the <see cref="EmptyTextLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty EmptyTextLabelProperty =
DependencyProperty.Register(nameof(EmptyTextLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Label cannot be Empty"));
/// <summary>
/// Identifies the <see cref="LinkInvalidLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty LinkInvalidLabelProperty =
DependencyProperty.Register(nameof(LinkInvalidLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Link Format is Invaild"));
/// <summary>
/// Identifies the <see cref="WarningLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty WarningLabelProperty =
DependencyProperty.Register(nameof(WarningLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Warning"));
/// <summary>
/// Identifies the <see cref="RelativeLabel"/> dependency property.
/// </summary>
public static readonly DependencyProperty RelativeLabelProperty =
DependencyProperty.Register(nameof(RelativeLabel), typeof(string), typeof(TextToolbarStrings), new PropertyMetadata("Relative"));
/// <summary>
/// Gets or sets the label for Bold
/// </summary>
public string BoldLabel
{
get { return (string)GetValue(BoldLabelProperty); }
set { SetValue(BoldLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Italics
/// </summary>
public string ItalicsLabel
{
get { return (string)GetValue(ItalicsLabelProperty); }
set { SetValue(ItalicsLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Strikethrough
/// </summary>
public string StrikethroughLabel
{
get { return (string)GetValue(StrikethroughLabelProperty); }
set { SetValue(StrikethroughLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Quote
/// </summary>
public string QuoteLabel
{
get { return (string)GetValue(QuoteLabelProperty); }
set { SetValue(QuoteLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Code
/// </summary>
public string CodeLabel
{
get { return (string)GetValue(CodeLabelProperty); }
set { SetValue(CodeLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for List
/// </summary>
public string ListLabel
{
get { return (string)GetValue(ListLabelProperty); }
set { SetValue(ListLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for OrderedList
/// </summary>
public string OrderedListLabel
{
get { return (string)GetValue(OrderedListLabelProperty); }
set { SetValue(OrderedListLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Link
/// </summary>
public string LinkLabel
{
get { return (string)GetValue(LinkLabelProperty); }
set { SetValue(LinkLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for CreateLink
/// </summary>
public string CreateLinkLabel
{
get { return (string)GetValue(CreateLinkLabelProperty); }
set { SetValue(CreateLinkLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Url
/// </summary>
public string UrlLabel
{
get { return (string)GetValue(UrlLabelProperty); }
set { SetValue(UrlLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Label
/// </summary>
public string LabelLabel
{
get { return (string)GetValue(LabelLabelProperty); }
set { SetValue(LabelLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for OK
/// </summary>
public string OkLabel
{
get { return (string)GetValue(OkLabelProperty); }
set { SetValue(OkLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Cancel
/// </summary>
public string CancelLabel
{
get { return (string)GetValue(CancelLabelProperty); }
set { SetValue(CancelLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Underline
/// </summary>
public string UnderlineLabel
{
get { return (string)GetValue(UnderlineLabelProperty); }
set { SetValue(UnderlineLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Header
/// </summary>
public string HeaderLabel
{
get { return (string)GetValue(HeaderLabelProperty); }
set { SetValue(HeaderLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for EmptyTextLabel
/// </summary>
public string EmptyTextLabel
{
get { return (string)GetValue(EmptyTextLabelProperty); }
set { SetValue(EmptyTextLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for LinkInvalid
/// </summary>
public string LinkInvalidLabel
{
get { return (string)GetValue(LinkInvalidLabelProperty); }
set { SetValue(LinkInvalidLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Warning
/// </summary>
public string WarningLabel
{
get { return (string)GetValue(WarningLabelProperty); }
set { SetValue(WarningLabelProperty, value); }
}
/// <summary>
/// Gets or sets the label for Relative
/// </summary>
public string RelativeLabel
{
get { return (string)GetValue(RelativeLabelProperty); }
set { SetValue(RelativeLabelProperty, value); }
}
}
}

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

@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using Microsoft.Toolkit.Uwp.Extensions;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@ -53,13 +54,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
var labelBox = new RichEditBox
{
PlaceholderText = Model.Labels.LabelLabel,
PlaceholderText = StringExtensions.GetLocalized("TextToolbarStrings_LabelLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Margin = new Thickness(0, 0, 0, 5),
AcceptsReturn = false
};
var linkBox = new TextBox
{
PlaceholderText = Model.Labels.UrlLabel
PlaceholderText = StringExtensions.GetLocalized("TextToolbarStrings_UrlLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources")
};
CheckBox relativeBox = null;
@ -77,7 +78,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
{
relativeBox = new CheckBox
{
Content = Model.Labels.RelativeLabel
Content = StringExtensions.GetLocalized("TextToolbarStrings_RelativeLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources")
};
contentPanel.Children.Add(relativeBox);
}
@ -88,10 +89,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
var result = await new ContentDialog
{
Title = Model.Labels.CreateLinkLabel,
Title = StringExtensions.GetLocalized("TextToolbarStrings_CreateLinkLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Content = contentPanel,
PrimaryButtonText = Model.Labels.OkLabel,
SecondaryButtonText = Model.Labels.CancelLabel
PrimaryButtonText = StringExtensions.GetLocalized("TextToolbarStrings_OkLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
SecondaryButtonText = StringExtensions.GetLocalized("TextToolbarStrings_CancelLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources")
}.ShowAsync();
if (result == ContentDialogResult.Primary)
@ -99,11 +100,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
labelBox.Document.GetText(Windows.UI.Text.TextGetOptions.None, out string labelText);
labelBox.Document.GetText(Windows.UI.Text.TextGetOptions.FormatRtf, out string formattedlabelText);
string linkInvalidLabel = StringExtensions.GetLocalized("TextToolbarStrings_LinkInvalidLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources");
string okLabel = StringExtensions.GetLocalized("TextToolbarStrings_OkLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources");
string warningLabel = StringExtensions.GetLocalized("TextToolbarStrings_WarningLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources");
string linkText = linkBox.Text.Trim();
if (string.IsNullOrWhiteSpace(linkText))
{
ShowContentDialog(Model.Labels.WarningLabel, Model.Labels.LinkInvalidLabel, Model.Labels.OkLabel);
ShowContentDialog(warningLabel, linkInvalidLabel, okLabel);
return;
}
@ -112,7 +116,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
var wellFormed = Uri.IsWellFormedUriString(linkText, relativeBox?.IsChecked == true ? UriKind.RelativeOrAbsolute : UriKind.Absolute);
if (!wellFormed)
{
ShowContentDialog(Model.Labels.WarningLabel, Model.Labels.LinkInvalidLabel, Model.Labels.OkLabel);
ShowContentDialog(warningLabel, linkInvalidLabel, okLabel);
return;
}
}

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

@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Toolkit.Uwp.Extensions;
using Windows.System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
@ -16,7 +17,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
{
/// <summary>
/// Initializes a new instance of the <see cref="CommonButtons"/> class. <para/>
/// Requires a TextToolbar Instance to Populate from <see cref="TextToolbarStrings"/> Instance.
/// Requires a TextToolbar Instance />.
/// </summary>
/// <param name="model">TextToolbar Instance</param>
public CommonButtons(TextToolbar model)
@ -36,7 +37,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
return new ToolbarButton
{
Name = TextToolbar.BoldElement,
ToolTip = Model.Labels.BoldLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_BoldLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new SymbolIcon { Symbol = Symbol.Bold },
ShortcutKey = VirtualKey.B,
Activation = MakeBold
@ -54,7 +55,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
return new ToolbarButton
{
Name = TextToolbar.ItalicsElement,
ToolTip = Model.Labels.ItalicsLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_StrikethroughLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new SymbolIcon { Symbol = Symbol.Italic },
ShortcutKey = VirtualKey.I,
Activation = MakeItalics
@ -72,7 +73,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
return new ToolbarButton
{
Name = TextToolbar.StrikethoughElement,
ToolTip = Model.Labels.StrikethroughLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_StrikethroughLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new FontIcon { Glyph = "\u0335a\u0335b\u0335c\u0335", FontFamily = new FontFamily("Segoe UI"), Margin = new Thickness(0, -5, 0, 0) },
Activation = MakeStrike,
ShortcutKey = VirtualKey.Subtract,
@ -91,7 +92,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
return new ToolbarButton
{
Name = TextToolbar.LinkElement,
ToolTip = Model.Labels.LinkLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_LinkLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Icon = new SymbolIcon { Symbol = Symbol.Link },
ShortcutKey = VirtualKey.K,
Activation = OpenLinkCreator,
@ -110,7 +111,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
return new ToolbarButton
{
Name = TextToolbar.ListElement,
ToolTip = Model.Labels.ListLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_ListLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Content = new TextToolbarSymbols.List(),
Activation = MakeList
};
@ -127,7 +128,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls.TextToolbarButtons.Common
return new ToolbarButton
{
Name = TextToolbar.OrderedElement,
ToolTip = Model.Labels.OrderedListLabel,
ToolTip = StringExtensions.GetLocalized("TextToolbarStrings_OrderedListLabel", "Microsoft.Toolkit.Uwp.UI.Controls/Resources"),
Content = new TextToolbarSymbols.NumberedList(),
Activation = MakeOList
};

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

@ -12,17 +12,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
using System.Threading.Tasks;
using Microsoft.Toolkit.Uwp.UI.Animations.Expressions;
using Microsoft.Toolkit.Uwp.UI.Extensions;
using Robmikh.CompositionSurfaceFactory;
using Windows.ApplicationModel;
using Windows.Foundation;
using Windows.Foundation.Metadata;
using Windows.Storage;
using Windows.UI.Composition;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Hosting;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Shapes;
/// <summary>
@ -31,17 +27,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public enum ScrollOrientation
{
/// <summary>
/// Scroll only Horizontaly (and optimize the number of image used)
/// Scroll only Horizontally (and optimize the number of image used)
/// </summary>
Horizontal,
/// <summary>
/// Scroll only Verticaly (and optimize the number of image used)
/// Scroll only Vertically (and optimize the number of image used)
/// </summary>
Vertical,
/// <summary>
/// Scroll both Horizontaly and verticaly
/// Scroll both Horizontally and vertically
/// </summary>
Both
}
@ -79,7 +75,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <summary>
/// A ContentControl that show an image repeated many times.
/// The control can be synchronized with a Scrollviewer and animated easily.
/// The control can be synchronized with a ScrollViewer and animated easily.
/// </summary>
public class TileControl : ContentControl
{
@ -149,69 +145,48 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
public static readonly DependencyProperty AnimationDurationProperty =
DependencyProperty.Register(nameof(AnimationDuration), typeof(double), typeof(TileControl), new PropertyMetadata(30.0, OnAnimationDuration));
private FrameworkElement _rootElement = null;
private Canvas _containerElement = null;
private TranslateTransform _containerTranslate = null;
private ImageBrush _brushXaml = null;
private ContainerVisual _containerVisual = null;
private CompositionSurfaceBrush _brushVisual = null;
private Size _imageSize = Size.Empty;
private UriSurface _uriSurface = null;
private Visual _rootVisual = null;
private DispatcherTimer _timerAnimation = null;
/// <summary>
/// A Scrollviewer used for synchronized the move of the <see cref="TileControl"/>
/// </summary>
private ScrollViewer _scrollviewer = null;
/// <summary>
/// a flag to lock shared method
/// </summary>
private SemaphoreSlim _flag = new SemaphoreSlim(1);
private readonly SemaphoreSlim _flag = new SemaphoreSlim(1);
private List<SpriteVisual> _compositionChildren = new List<SpriteVisual>(50);
private List<Rectangle> _xamlChildren = new List<Rectangle>(50);
private readonly List<SpriteVisual> _compositionChildren = new List<SpriteVisual>(50);
private readonly object _lockerOffset = new object();
private bool _isImageSourceLoaded = false;
private bool _isRootElementSizeChanged = false;
private FrameworkElement _rootElement;
private CompositionPropertySet _propertySetModulo = null;
private object _lockerOffset = new object();
private ContainerVisual _containerVisual;
private CompositionSurfaceBrush _brushVisual;
private LoadedImageSurface _imageSurface;
private double _animationX = 0;
private double _animationY = 0;
private Size _imageSize = Size.Empty;
private enum UIStrategy
{
/// <summary>
/// TileControl is created with XAML
/// </summary>
PureXaml,
private DispatcherTimer _timerAnimation;
/// <summary>
/// TileControl is created with Microsoft Composition
/// </summary>
Composition
}
/// <summary>
/// A ScrollViewer used for synchronized the move of the <see cref="TileControl"/>
/// </summary>
private ScrollViewer _scrollViewer;
private bool _isImageSourceLoaded;
private bool _isRootElementSizeChanged;
private CompositionPropertySet _propertySetModulo;
private double _animationX;
private double _animationY;
/// <summary>
/// The image loaded event.
/// </summary>
public event EventHandler ImageLoaded = null;
public event EventHandler ImageLoaded;
/// <summary>
/// Gets a value indicating whether the platform supports Composition.
/// </summary>
/// <remarks>
/// On platforms not supporting Composition, this <See cref="UIStrategy"/> is automaticaly set to PureXaml.
/// </remarks>
[Obsolete("This property is now obsolete and will be removed in a future version of the Toolkit.")]
public static bool IsCompositionSupported => !DesignTimeHelpers.IsRunningInLegacyDesignerMode &&
ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 3); // SDK >= 14393
ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 3); // SDK >= 14393
/// <summary>
/// Initializes a new instance of the <see cref="TileControl"/> class.
@ -225,7 +200,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <summary>
/// Gets or sets a ScrollViewer or a frameworkElement containing a ScrollViewer.
/// The tile control is synchronized with the offset of the scrollviewer
/// The tile control is synchronized with the offset of the scrollViewer
/// </summary>
public FrameworkElement ScrollViewerContainer
{
@ -254,12 +229,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
if (newScrollViewerContainer != null)
{
// May be the scrollViewerContainer is not completly loaded (and the scrollviewer doesn't exit yet)
// May be the scrollViewerContainer is not completely loaded (and the scrollViewer doesn't exit yet)
// so we need to wait the loaded event to be sure
newScrollViewerContainer.Loaded += ScrollViewerContainer_Loaded;
}
// try to attach a scrollviewer (the null value is valid)
// try to attach a scrollViewer (the null value is valid)
return AttachScrollViewer(newScrollViewerContainer);
}
@ -273,32 +248,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
await AttachScrollViewer(sender as FrameworkElement);
}
/// <summary>
/// Gets how the <see cref="TileControl"/> is rendered
/// The default value is Composition.
/// </summary>
private UIStrategy Strategy
{
get
{
if (currentStrategy == null)
{
if (!IsCompositionSupported)
{
currentStrategy = UIStrategy.PureXaml;
}
else
{
currentStrategy = UIStrategy.Composition;
}
}
return currentStrategy.Value;
}
}
private UIStrategy? currentStrategy = null;
/// <summary>
/// Gets or sets the alignment of the tile when the <see cref="ScrollOrientation"/> is set to Vertical or Horizontal.
/// Valid values are Left or Right for <see cref="ScrollOrientation"/> set to Horizontal and Top or Bottom for <see cref="ScrollOrientation"/> set to Vertical.
@ -316,7 +265,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
}
/// <summary>
/// Attach a scrollviewer to the TileControl (parallax effect)
/// Attach a ScrollViewer to the TileControl (parallax effect)
/// </summary>
/// <param name="scrollViewerContainer">A ScrollViewer or a container of a ScrollViewer</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
@ -327,39 +276,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
return;
}
ScrollViewer newScrollviewer = scrollViewerContainer.FindDescendant<ScrollViewer>();
ScrollViewer newScrollViewer = scrollViewerContainer.FindDescendant<ScrollViewer>();
if (newScrollviewer != _scrollviewer)
if (newScrollViewer != _scrollViewer)
{
var strategy = Strategy;
// Update the expression
await CreateModuloExpression(newScrollViewer);
if (strategy == UIStrategy.Composition)
{
// Update the expression
await CreateModuloExpression(newScrollviewer);
}
else
{
if (_scrollviewer != null)
{
_scrollviewer.ViewChanging -= Scrollviewer_ViewChanging;
}
if (newScrollviewer != null)
{
newScrollviewer.ViewChanging += Scrollviewer_ViewChanging;
}
}
_scrollviewer = newScrollviewer;
_scrollViewer = newScrollViewer;
}
}
private void Scrollviewer_ViewChanging(object sender, ScrollViewerViewChangingEventArgs e)
{
RefreshMove();
}
/// <summary>
/// Gets or sets the uri of the image to load
/// </summary>
@ -372,7 +299,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private static async void OnImageSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as TileControl;
await control.LoadImageBrush(e.NewValue as Uri);
await control.LoadImageBrushAsync(e.NewValue as Uri);
}
/// <summary>
@ -380,28 +307,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// </summary>
/// <param name="uri">the uri of the image to load</param>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
private async Task<bool> LoadImageBrush(Uri uri)
private async Task<bool> LoadImageBrushAsync(Uri uri)
{
if (DesignTimeHelpers.IsRunningInLegacyDesignerMode)
{
return false;
}
var strategy = Strategy;
if (strategy == UIStrategy.Composition)
if (_containerVisual == null || uri == null)
{
if (_containerVisual == null || uri == null)
{
return false;
}
}
else
{
if (uri == null)
{
return false;
}
return false;
}
await _flag.WaitAsync();
@ -412,58 +327,42 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
IsAnimated = false;
if (_isImageSourceLoaded == true)
if (_isImageSourceLoaded)
{
for (int i = 0; i < _compositionChildren.Count; i++)
{
if (strategy == UIStrategy.PureXaml)
{
_xamlChildren[i].Fill = null;
}
else
{
_compositionChildren[i].Brush = null;
}
_compositionChildren[i].Brush = null;
}
if (strategy == UIStrategy.Composition)
{
_brushVisual.Dispose();
_brushVisual = null;
_brushVisual?.Dispose();
_brushVisual = null;
_uriSurface.Dispose();
_uriSurface = null;
}
_imageSurface?.Dispose();
_imageSurface = null;
}
_isImageSourceLoaded = false;
if (strategy == UIStrategy.Composition)
var compositor = _containerVisual.Compositor;
_imageSurface = LoadedImageSurface.StartLoadFromUri(uri);
var loadCompletedSource = new TaskCompletionSource<bool>();
_brushVisual = compositor.CreateSurfaceBrush(_imageSurface);
_imageSurface.LoadCompleted += (s, e) =>
{
var compositor = _containerVisual.Compositor;
var surfaceFactory = SurfaceFactory.GetSharedSurfaceFactoryForCompositor(compositor);
var surfaceUri = await surfaceFactory.CreateUriSurfaceAsync(uri);
_uriSurface = surfaceUri;
_brushVisual = compositor.CreateSurfaceBrush(surfaceUri.Surface);
_imageSize = surfaceUri.Size;
}
else
{
BitmapImage image = new BitmapImage();
var storageFile = await StorageFile.GetFileFromApplicationUriAsync(uri);
using (var stream = await storageFile.OpenReadAsync())
if (e.Status == LoadedImageSourceLoadStatus.Success)
{
image.SetSource(stream);
loadCompletedSource.SetResult(true);
}
else
{
loadCompletedSource.SetException(new ArgumentException("Image loading failed."));
}
};
_brushXaml = new ImageBrush() { ImageSource = image };
_imageSize = new Size(image.PixelWidth, image.PixelHeight);
}
await loadCompletedSource.Task;
_imageSize = _imageSurface.DecodedPhysicalSize;
_isImageSourceLoaded = true;
@ -471,7 +370,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
RefreshImageSize(_imageSize.Width, _imageSize.Height);
if (isAnimated == true)
if (isAnimated)
{
IsAnimated = true;
}
@ -500,17 +399,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
var control = d as TileControl;
await control.RefreshContainerTileLocked();
if (control.Strategy == UIStrategy.Composition)
{
await control.CreateModuloExpression(control._scrollviewer);
}
await control.CreateModuloExpression(control._scrollViewer);
}
/// <inheritdoc/>
protected override async void OnApplyTemplate()
{
var strategy = Strategy;
var rootElement = _rootElement;
if (rootElement != null)
@ -527,33 +421,23 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
rootElement.SizeChanged += RootElement_SizeChanged;
if (strategy == UIStrategy.Composition)
// Get the Visual of the root element
Visual rootVisual = ElementCompositionPreview.GetElementVisual(rootElement);
if (rootVisual != null)
{
// Get the Visual of the root element
Visual rootVisual = ElementCompositionPreview.GetElementVisual(rootElement);
// We create a ContainerVisual to insert SpriteVisual with a brush
var container = rootVisual.Compositor.CreateContainerVisual();
if (rootVisual != null)
{
// We create a ContainerVisual to insert SpriteVisual with a brush
var container = rootVisual.Compositor.CreateContainerVisual();
// the containerVisual is now a child of rootVisual
ElementCompositionPreview.SetElementChildVisual(rootElement, container);
// the containerVisual is now a child of rootVisual
ElementCompositionPreview.SetElementChildVisual(rootElement, container);
_containerVisual = container;
_containerVisual = container;
_rootVisual = rootVisual;
await CreateModuloExpression();
}
}
else
{
_containerElement = rootElement.FindName("ContainerElement") as Canvas;
_containerTranslate = new TranslateTransform();
_containerElement.RenderTransform = _containerTranslate;
await CreateModuloExpression();
}
await LoadImageBrush(ImageSource);
await LoadImageBrushAsync(ImageSource);
}
base.OnApplyTemplate();
@ -612,7 +496,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
return false;
}
double numberSpriteToInstanciate = 0;
double numberSpriteToInstantiate = 0;
int numberImagePerColumn = 1;
int numberImagePerRow = 1;
@ -620,15 +504,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
int offsetHorizontalAlignment = 0;
int offsetVerticalAlignment = 0;
var strategy = Strategy;
if (_containerElement != null)
{
_containerElement.Width = width;
_containerElement.Height = height;
}
var clip = new RectangleGeometry() { Rect = new Rect(0, 0, width, height) };
var clip = new RectangleGeometry { Rect = new Rect(0, 0, width, height) };
_rootElement.Clip = clip;
var imageAlignment = ImageAlignment;
@ -652,7 +528,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
numberImagePerRow = (int)Math.Ceiling(height / imageHeight);
}
numberSpriteToInstanciate = numberImagePerColumn * numberImagePerRow;
numberSpriteToInstantiate = numberImagePerColumn * numberImagePerRow;
break;
case ScrollOrientation.Vertical:
@ -672,60 +548,33 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
numberImagePerColumn = (int)Math.Ceiling(width / imageWidth);
}
numberSpriteToInstanciate = numberImagePerColumn * numberImagePerRow;
numberSpriteToInstantiate = numberImagePerColumn * numberImagePerRow;
break;
case ScrollOrientation.Both:
numberImagePerColumn = (int)Math.Ceiling(width / imageWidth) + 1;
numberImagePerRow = (int)(Math.Ceiling(height / imageHeight) + 1);
numberSpriteToInstanciate = numberImagePerColumn * numberImagePerRow;
numberSpriteToInstantiate = numberImagePerColumn * numberImagePerRow;
break;
}
var count = 0;
var count = _compositionChildren.Count;
if (strategy == UIStrategy.Composition)
// instantiate all elements not created yet
for (int x = 0; x < numberSpriteToInstantiate - count; x++)
{
count = _compositionChildren.Count;
}
else
{
count = _xamlChildren.Count;
}
// instanciate all elements not created yet
for (int x = 0; x < numberSpriteToInstanciate - count; x++)
{
if (strategy == UIStrategy.Composition)
{
var sprite = _containerVisual.Compositor.CreateSpriteVisual();
_containerVisual.Children.InsertAtTop(sprite);
_compositionChildren.Add(sprite);
}
else
{
var rectangle = new Rectangle();
_containerElement.Children.Add(rectangle);
_xamlChildren.Add(rectangle);
}
var sprite = _containerVisual.Compositor.CreateSpriteVisual();
_containerVisual.Children.InsertAtTop(sprite);
_compositionChildren.Add(sprite);
}
// remove elements not used now
for (int x = 0; x < count - numberSpriteToInstanciate; x++)
for (int x = 0; x < count - numberSpriteToInstantiate; x++)
{
if (strategy == UIStrategy.Composition)
{
var element = _containerVisual.Children.FirstOrDefault() as SpriteVisual;
_containerVisual.Children.Remove(element);
_compositionChildren.Remove(element);
}
else
{
var element = _containerElement.Children.FirstOrDefault() as Rectangle;
_containerElement.Children.Remove(element);
_xamlChildren.Remove(element);
}
var element = _containerVisual.Children.FirstOrDefault() as SpriteVisual;
_containerVisual.Children.Remove(element);
_compositionChildren.Remove(element);
}
// Change positions+brush for all actives elements
@ -735,23 +584,10 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
int index = (y * numberImagePerColumn) + x;
if (strategy == UIStrategy.Composition)
{
var sprite = _compositionChildren[index];
sprite.Brush = _brushVisual;
sprite.Offset = new Vector3((float)((x * imageWidth) + offsetVerticalAlignment), (float)((y * imageHeight) + offsetHorizontalAlignment), 0);
sprite.Size = new Vector2((float)imageWidth, (float)imageHeight);
}
else
{
var rectangle = _xamlChildren[index];
rectangle.Fill = _brushXaml;
Canvas.SetLeft(rectangle, (x * imageWidth) + offsetVerticalAlignment);
Canvas.SetTop(rectangle, (y * imageHeight) + offsetHorizontalAlignment);
rectangle.Width = imageWidth;
rectangle.Height = imageHeight;
}
var sprite = _compositionChildren[index];
sprite.Brush = _brushVisual;
sprite.Offset = new Vector3((float)((x * imageWidth) + offsetVerticalAlignment), (float)((y * imageHeight) + offsetHorizontalAlignment), 0);
sprite.Size = new Vector2((float)imageWidth, (float)imageHeight);
}
}
@ -828,11 +664,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <summary>
/// Creation of an expression to manage modulo (positive and negative value)
/// </summary>
/// <param name="scrollviewer">The ScrollViewer to synchonized. A null value is valid</param>
/// <param name="scrollViewer">The ScrollViewer to synchronized. A null value is valid</param>
/// <param name="imageWidth">Width of the image</param>
/// <param name="imageHeight">Height of the image</param>
/// <param name="scrollOrientation">The ScrollOrientation</param>
private void CreateModuloExpression(ScrollViewer scrollviewer, double imageWidth, double imageHeight, ScrollOrientation scrollOrientation)
private void CreateModuloExpression(ScrollViewer scrollViewer, double imageWidth, double imageHeight, ScrollOrientation scrollOrientation)
{
const string offsetXParam = "offsetX";
const string offsetYParam = "offsetY";
@ -840,11 +676,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
const string imageHeightParam = "imageHeight";
const string speedParam = "speed";
if (Strategy == UIStrategy.PureXaml)
{
return;
}
if (_containerVisual == null)
{
return;
@ -855,8 +686,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
// Setup the expression
ExpressionNode expressionX = null;
ExpressionNode expressionY = null;
ExpressionNode expressionXVal = null;
ExpressionNode expressionYVal = null;
ExpressionNode expressionXVal;
ExpressionNode expressionYVal;
var propertySetModulo = compositor.CreatePropertySet();
propertySetModulo.InsertScalar(imageWidthParam, (float)imageWidth);
@ -869,7 +700,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
var imageHeightNode = propertySetNodeModulo.GetScalarProperty(imageHeightParam);
var imageWidthNode = propertySetNodeModulo.GetScalarProperty(imageWidthParam);
if (scrollviewer == null)
if (scrollViewer == null)
{
var offsetXNode = ExpressionFunctions.Ceil(propertySetNodeModulo.GetScalarProperty(offsetXParam));
var offsetYNode = ExpressionFunctions.Ceil(propertySetNodeModulo.GetScalarProperty(offsetYParam));
@ -894,7 +725,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
else
{
// expressions are created to simulate a positive and negative modulo with the size of the image and the offset and the ScrollViewer offset (Translation)
var scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollviewer);
var scrollProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
var scrollPropSet = scrollProperties.GetSpecializedReference<ManipulationPropertySetReferenceNode>();
var speed = propertySetNodeModulo.GetScalarProperty(speedParam);
@ -962,53 +793,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
lock (_lockerOffset)
{
if (Strategy == UIStrategy.Composition)
if (_propertySetModulo == null)
{
if (_propertySetModulo == null)
{
return;
}
_propertySetModulo.InsertScalar("offsetX", (float)x);
_propertySetModulo.InsertScalar("offsetY", (float)y);
return;
}
else
{
var orientation = ScrollOrientation;
var scrollviewer = _scrollviewer;
double scrollX = 0;
double scrollY = 0;
if (scrollviewer != null)
{
var speedRatio = ParallaxSpeedRatio;
scrollX = -((scrollviewer.HorizontalOffset * scrollviewer.ActualWidth) / scrollviewer.ViewportWidth) * speedRatio;
scrollY = -((scrollviewer.VerticalOffset * scrollviewer.ActualHeight) / scrollviewer.ViewportHeight) * speedRatio;
}
if (orientation == ScrollOrientation.Both || orientation == ScrollOrientation.Horizontal)
{
_containerTranslate.X = GetOffsetModulo(x + scrollX, _imageSize.Width);
if (orientation == ScrollOrientation.Horizontal)
{
_containerTranslate.Y = 0;
}
}
if (orientation == ScrollOrientation.Both || orientation == ScrollOrientation.Vertical)
{
_containerTranslate.Y = GetOffsetModulo(y + scrollY, _imageSize.Height);
if (orientation == ScrollOrientation.Vertical)
{
_containerTranslate.X = 0;
}
}
}
_propertySetModulo.InsertScalar("offsetX", (float)x);
_propertySetModulo.InsertScalar("offsetY", (float)y);
}
}
@ -1031,10 +822,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
return -(Math.Abs(offsetCeil - (Math.Ceiling(offsetCeil / size) * size)) % size);
}
else
{
return -(size - (offsetCeil % size));
}
return -(size - (offsetCeil % size));
}
private void RefreshImageSize(double width, double height)
@ -1050,12 +839,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private void RefreshScrollSpeedRatio(double speedRatio)
{
if (_propertySetModulo == null)
{
return;
}
_propertySetModulo.InsertScalar("speed", (float)speedRatio);
_propertySetModulo?.InsertScalar("speed", (float)speedRatio);
}
/// <summary>
@ -1071,7 +855,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
{
var c = d as TileControl;
if ((bool)e.NewValue == true)
if ((bool)e.NewValue)
{
c._timerAnimation.Start();
}
@ -1100,9 +884,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
private void Timer_Tick(object sender, object e)
{
var strategy = Strategy;
if (strategy == UIStrategy.Composition && _containerVisual == null)
if (_containerVisual == null)
{
return;
}

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

@ -0,0 +1,22 @@
// 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 Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// Options for how to calculate the layout of <see cref="Windows.UI.Xaml.Controls.WrapGrid"/> items.
/// </summary>
public enum StretchChild
{
/// <summary>
/// Don't apply any additional stretching logic
/// </summary>
None,
/// <summary>
/// Make the last child stretch to fill the available space
/// </summary>
Last
}
}

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

@ -99,6 +99,26 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
typeof(WrapPanel),
new PropertyMetadata(default(Thickness), LayoutPropertyChanged));
/// <summary>
/// Gets or sets a value indicating how to arrange child items
/// </summary>
public StretchChild StretchChild
{
get { return (StretchChild)GetValue(StretchChildProperty); }
set { SetValue(StretchChildProperty, value); }
}
/// <summary>
/// Identifies the <see cref="StretchChild"/> dependency property.
/// </summary>
/// <returns>The identifier for the <see cref="StretchChild"/> dependency property.</returns>
public static readonly DependencyProperty StretchChildProperty =
DependencyProperty.Register(
nameof(StretchChild),
typeof(StretchChild),
typeof(WrapPanel),
new PropertyMetadata(StretchChild.None, LayoutPropertyChanged));
private static void LayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is WrapPanel wp)
@ -121,12 +141,19 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
foreach (var child in Children)
{
child.Measure(availableSize);
var currentMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
if (parentMeasure.U >= currentMeasure.U + lineMeasure.U + spacingMeasure.U)
if (currentMeasure.U == 0)
{
lineMeasure.U += currentMeasure.U + spacingMeasure.U;
continue; // ignore collapsed items
}
// if this is the first item, do not add spacing. Spacing is added to the "left"
double uChange = lineMeasure.U == 0
? currentMeasure.U
: currentMeasure.U + spacingMeasure.U;
if (parentMeasure.U >= uChange + lineMeasure.U)
{
lineMeasure.U += uChange;
lineMeasure.V = Math.Max(lineMeasure.V, currentMeasure.V);
}
else
@ -172,37 +199,59 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
/// <inheritdoc />
protected override Size ArrangeOverride(Size finalSize)
{
var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top);
var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
var position = new UvMeasure(Orientation, Padding.Left, Padding.Top);
double currentV = 0;
foreach (var child in Children)
if (Children.Count > 0)
{
var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
var parentMeasure = new UvMeasure(Orientation, finalSize.Width, finalSize.Height);
var spacingMeasure = new UvMeasure(Orientation, HorizontalSpacing, VerticalSpacing);
var paddingStart = new UvMeasure(Orientation, Padding.Left, Padding.Top);
var paddingEnd = new UvMeasure(Orientation, Padding.Right, Padding.Bottom);
var position = new UvMeasure(Orientation, Padding.Left, Padding.Top);
double currentV = 0;
void arrange(UIElement child, bool isLast = false)
{
// next row!
position.U = paddingStart.U;
position.V += currentV + spacingMeasure.V;
currentV = 0;
var desiredMeasure = new UvMeasure(Orientation, child.DesiredSize.Width, child.DesiredSize.Height);
if (desiredMeasure.U == 0)
{
return; // if an item is collapsed, avoid adding the spacing
}
if ((desiredMeasure.U + position.U + paddingEnd.U) > parentMeasure.U)
{
// next row!
position.U = paddingStart.U;
position.V += currentV + spacingMeasure.V;
currentV = 0;
}
// Stretch the last item to fill the available space
if (isLast)
{
desiredMeasure.U = parentMeasure.U - position.U;
}
// place the item
if (Orientation == Orientation.Horizontal)
{
child.Arrange(new Rect(position.U, position.V, desiredMeasure.U, desiredMeasure.V));
}
else
{
child.Arrange(new Rect(position.V, position.U, desiredMeasure.V, desiredMeasure.U));
}
// adjust the location for the next items
position.U += desiredMeasure.U + spacingMeasure.U;
currentV = Math.Max(desiredMeasure.V, currentV);
}
// Place the item
if (Orientation == Orientation.Horizontal)
var lastIndex = Children.Count - 1;
for (var i = 0; i < lastIndex; i++)
{
child.Arrange(new Rect(position.U, position.V, child.DesiredSize.Width, child.DesiredSize.Height));
}
else
{
child.Arrange(new Rect(position.V, position.U, child.DesiredSize.Width, child.DesiredSize.Height));
arrange(Children[i]);
}
// adjust the location for the next items
position.U += desiredMeasure.U + spacingMeasure.U;
currentV = Math.Max(desiredMeasure.V, currentV);
arrange(Children[lastIndex], StretchChild == StretchChild.Last);
}
return finalSize;

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

@ -32,7 +32,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Converters
return value;
}
return string.Format((string)parameter, value);
try
{
return string.Format((string)parameter, value);
}
catch
{
}
return value;
}
/// <summary>

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

@ -0,0 +1,87 @@
// 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.Concurrent;
using Windows.UI.Xaml;
namespace Microsoft.Toolkit.Uwp.UI.Extensions
{
/// <summary>
/// Set of extention methods for using <see cref="DispatcherTimer"/>.
/// </summary>
public static class DispatcherTimerExtensions
{
private static ConcurrentDictionary<DispatcherTimer, Action> _debounceInstances = new ConcurrentDictionary<DispatcherTimer, Action>();
/// <summary>
/// <para>Used to debounce (rate-limit) an event. The action will be postponed and executed after the interval has elapsed. At the end of the interval, the function will be called with the arguments that were passed most recently to the debounced function.</para>
/// <para>Use this method to control the timer instead of calling Start/Interval/Stop manually.</para>
/// <para>A scheduled debounce can still be stopped by calling the stop method on the timer instance.</para>
/// <para>Each timer can only have one debounced function limited at a time.</para>
/// </summary>
/// <param name="timer">Timer instance, only one debounced function can be used per timer.</param>
/// <param name="action">Action to execute at the end of the interval.</param>
/// <param name="interval">Interval to wait before executing the action.</param>
/// <param name="immediate">Determines if the action execute on the leading edge instead of trailing edge.</param>
/// <example>
/// <code>
/// private DispatcherTimer _typeTimer = new DispatcherTimer();
///
/// _typeTimer.Debounce(async () =>
/// {
/// // Only executes this code after 0.3 seconds have elapsed since last trigger.
/// }, TimeSpan.FromSeconds(0.3));
/// </code>
/// </example>
public static void Debounce(this DispatcherTimer timer, Action action, TimeSpan interval, bool immediate = false)
{
// Check and stop any existing timer
var timeout = timer.IsEnabled;
if (timeout)
{
timer.Stop();
}
// Reset timer parameters
timer.Tick -= Timer_Tick;
timer.Interval = interval;
if (immediate)
{
// If we're in immediate mode then we only execute if the timer wasn't running beforehand
if (!timeout)
{
action.Invoke();
}
}
else
{
// If we're not in immediate mode, then we'll execute when the current timer expires.
timer.Tick += Timer_Tick;
// Store/Update function
_debounceInstances.AddOrUpdate(timer, action, (k, v) => v);
}
// Start the timer to keep track of the last call here.
timer.Start();
}
private static void Timer_Tick(object sender, object e)
{
// This event is only registered/run if we weren't in immediate mode above
if (sender is DispatcherTimer timer)
{
timer.Tick -= Timer_Tick;
timer.Stop();
if (_debounceInstances.TryRemove(timer, out Action action))
{
action?.Invoke();
}
}
}
}
}

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

@ -74,7 +74,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Extensions
/// <param name="value">A value indicating if the Text is valid according to the Regex property.</param>
public static void SetIsValid(TextBox textBox, bool value)
{
textBox.SetValue(ValidationModeProperty, value);
textBox.SetValue(IsValidProperty, value);
}
/// <summary>

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

@ -3,10 +3,58 @@
<PropertyGroup>
<TargetFramework>uap10.0.16299</TargetFramework>
<Title>Windows Community Toolkit UI</Title>
<Description>This library provides UI components, such as XAML extensions, helpers, brushes, converters and more. It is part of the Windows Community Toolkit.</Description>
<Description>
This library provides UI components, such as XAML extensions, helpers, brushes, converters and more. It is part of the Windows Community Toolkit.
AdvancedCollectionView: It's a collection view implementation that support filtering, sorting and incremental loading. It's meant to be used in a viewmodel.
CacheBase: Provides methods and tools to cache files in a folder.
Converters: Commonly used converters that allow the data to be modified as it passes through the binding engine.
Extensions:
- ApplicationViewExtensions: Provides attached properties for interacting with the ApplicationView on a window (app view).
- FrameworkElementExtensions: Provides attached dependency properties for the FrameworkElement.
- ListViewExtensions: Provides attached dependency properties for the ListViewBase
- LogicalTree: Defines a collection of extensions methods for UI.
- MatrixExtensions: Provides a set of extensions to the Matrix struct.
- MatrixHelperEx: Static helper methods for Matrix.
- Mouse: Helper class for easily changing the mouseover cursor type.
- NullableBool: Custom MarkupExtension which can provide nullable bool values.
- RotateTransformExtensions: Extension methods for RotateTransform.
- ScaleTransformExtensions: Extension methods for ScaleTransform.
- ScrollViewerExtensions: Provides attached dependency properties for the ListViewBase
- SkewTransformExtensions: Extension methods for SkewTransform.
- StatusBarExtensions: Provides attached dependency properties for interacting with the StatusBar on a window (app view).
- SurfaceDialTextbox: Helper class that provides attached properties to enable any TextBox with the Surface Dial.
- TextBoxMask: TextBox mask property allows a user to more easily enter fixed width text in TextBox control.
- TextBoxRegex: TextBoxRegex allows text validation using a regular expression.
- TitleBarExtensions: Provides attached dependency properties for interacting with the ApplicationViewTitleBar on a window (app view).
- TranslateTransformExtensions: Extension methods for TranslateTransform.
- VisualExtensions: Extension methods and attached properties for Visual objects
- VisualTree: Defines a collection of extensions methods for UI.
Helpers:
- BindableValueHolder: Holds the value. Can be used to change several objects' properties at a time.
- DependencyPropertyWatcher: Used to Track Changes of a Dependency Property
- ThemeListener: Class which listens for changes to Application Theme or High Contrast Modes and Signals an Event when they occur.
Media:
- BackdropBlurBrush: The BackdropBlurBrush is a Brush that blurs whatever is behind it in the application.
- BackdropGammaTransferBrush: A brush which alters the colors of whatever is behind it in the application by applying a per-channel gamma transfer function.
- BackdropInvertBrush: The BackdropInvertBrush is a Brush which inverts whatever is behind it in the application.
- BackdropSaturationBrush: Brush which applies a SaturationEffect to the Backdrop.
- BackdropSepiaBrush: Brush which applies a SepiaEffect to the Backdrop.
- CanvasBrushBase: Helper Brush class to interop with Win2D Canvas calls.
- ImageBlendBrush: Brush which blends a BitmapImage to the Backdrop in a given mode.
- RadialGradientBrush: This GradientBrush defines its Gradient as an interpolation within an Ellipse.
</Description>
<PackageTags>UWP Toolkit Windows UI Converters XAML extensions helpers brushes blur</PackageTags>
<UseWindowsDesktopSdk>true</UseWindowsDesktopSdk>
<!-- For StatusBar -->
<UseWindowsMobileSdk>true</UseWindowsMobileSdk>
</PropertyGroup>
@ -17,6 +65,6 @@
<ItemGroup>
<ProjectReference Include="..\Microsoft.Toolkit.Uwp\Microsoft.Toolkit.Uwp.csproj" />
</ItemGroup>
</ItemGroup>
</Project>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше