Windows 10 future version - February 2018 Update
This commit is contained in:
Коммит
64b49a8381
|
@ -11,7 +11,7 @@
|
|||
<Properties>
|
||||
<DisplayName>360 Video Playback C++ Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
<Logo>Assets\StoreLogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.16299.0"/>
|
||||
|
|
|
@ -66,12 +66,12 @@ namespace _360VideoPlayback.Common
|
|||
|
||||
// Initialize Direct2D resources.
|
||||
var debugLevel = SharpDX.Direct2D1.DebugLevel.None;
|
||||
//#if DEBUG
|
||||
#if DEBUG
|
||||
if (DirectXHelper.SdkLayersAvailable())
|
||||
{
|
||||
debugLevel = SharpDX.Direct2D1.DebugLevel.Information;
|
||||
}
|
||||
//#endif
|
||||
#endif
|
||||
|
||||
// Initialize the Direct2D Factory.
|
||||
d2dFactory = this.ToDispose(
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<Properties>
|
||||
<DisplayName>360 Video Playback C# Sample</DisplayName>
|
||||
<PublisherDisplayName>Microsoft Corporation</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
<Logo>Assets\StoreLogo-sdk.png</Logo>
|
||||
</Properties>
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.16299.0"/>
|
||||
|
|
|
@ -64,7 +64,7 @@ For more information on network capabilities, see [How to set network capabiliti
|
|||
|
||||
**Client:** Windows 10
|
||||
|
||||
**Server:** Windows Server 2016 Technical Preview
|
||||
**Server:** Windows Server 2016
|
||||
|
||||
**Phone:** Windows 10
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.17069.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.17069.0</WindowsTargetPlatformMinVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
|
@ -163,6 +163,9 @@
|
|||
<ClInclude Include="Scenario6_RecoverableErrors.xaml.h">
|
||||
<DependentUpon>..\..\shared\Scenario6_RecoverableErrors.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Scenario7_DownloadReordering.xaml.h">
|
||||
<DependentUpon>..\..\shared\Scenario7_DownloadReordering.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="..\..\..\..\SharedContent\xaml\App.xaml">
|
||||
|
@ -177,6 +180,7 @@
|
|||
<Page Include="..\..\shared\Scenario4_CompletionGroups.xaml" />
|
||||
<Page Include="..\..\shared\Scenario5_RandomAccess.xaml" />
|
||||
<Page Include="..\..\shared\Scenario6_RecoverableErrors.xaml" />
|
||||
<Page Include="..\..\shared\Scenario7_DownloadReordering.xaml" />
|
||||
<Page Include="..\..\..\..\SharedContent\xaml\Styles.xaml">
|
||||
<Link>Styles\Styles.xaml</Link>
|
||||
</Page>
|
||||
|
@ -220,6 +224,9 @@
|
|||
<ClCompile Include="Scenario6_RecoverableErrors.xaml.cpp">
|
||||
<DependentUpon>..\..\shared\Scenario6_RecoverableErrors.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Scenario7_DownloadReordering.xaml.cpp">
|
||||
<DependentUpon>..\..\shared\Scenario7_DownloadReordering.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
<ClCompile Include="Scenario4_CompletionGroups.xaml.cpp" />
|
||||
<ClCompile Include="Scenario5_RandomAccess.xaml.cpp" />
|
||||
<ClCompile Include="Scenario6_RecoverableErrors.xaml.cpp" />
|
||||
<ClCompile Include="Scenario7_DownloadReordering.xaml.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
|
@ -35,6 +36,7 @@
|
|||
<ClInclude Include="Scenario4_CompletionGroups.xaml.h" />
|
||||
<ClInclude Include="Scenario5_RandomAccess.xaml.h" />
|
||||
<ClInclude Include="Scenario6_RecoverableErrors.xaml.h" />
|
||||
<ClInclude Include="Scenario7_DownloadReordering.xaml.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest" />
|
||||
|
@ -50,6 +52,7 @@
|
|||
<Page Include="..\..\shared\Scenario4_CompletionGroups.xaml" />
|
||||
<Page Include="..\..\shared\Scenario5_RandomAccess.xaml" />
|
||||
<Page Include="..\..\shared\Scenario6_RecoverableErrors.xaml" />
|
||||
<Page Include="..\..\shared\Scenario7_DownloadReordering.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="..\..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.16299.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17069.0" MaxVersionTested="10.0.17069.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
|
|
@ -23,4 +23,5 @@ Platform::Array<Scenario>^ MainPage::scenariosInner = ref new Platform::Array<Sc
|
|||
{ "Completion Groups", "SDKTemplate.Scenario4_CompletionGroups" },
|
||||
{ "Random Access Downloads", "SDKTemplate.Scenario5_RandomAccess" },
|
||||
{ "Recoverable Errors", "SDKTemplate.Scenario6_RecoverableErrors" },
|
||||
{ "Download Reordering", "SDKTemplate.Scenario7_DownloadReordering" },
|
||||
};
|
||||
|
|
|
@ -177,7 +177,7 @@ void Scenario1_Download::StartDownload(BackgroundTransferPriority priority)
|
|||
// validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling TryGetUri() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require the
|
||||
// "Home or Work Networking" capability.
|
||||
// "Private Networks (Client and Server)" capability.
|
||||
Uri^ source;
|
||||
if (!rootPage->TryGetUri(serverAddressField->Text, &source))
|
||||
{
|
||||
|
|
|
@ -96,7 +96,7 @@ void Scenario2_Upload::StartUpload_Click(Object^ sender, RoutedEventArgs^ e)
|
|||
// Validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling TryGetUri() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require the
|
||||
// "Home or Work Networking" capability.
|
||||
// "Private Networks (Client and Server)" capability.
|
||||
Uri^ uri;
|
||||
if (!rootPage->TryGetUri(serverAddressField->Text, &uri))
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ void Scenario2_Upload::StartMultipartUpload_Click(Object^ sender, RoutedEventArg
|
|||
// Validating the URI is required (like TryGetUri) since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling TryGetUri() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require the
|
||||
// "Home or Work Networking" capability.
|
||||
// "Private Networks (Client and Server)" capability.
|
||||
Uri^ uri;
|
||||
if (!rootPage->TryGetUri(serverAddressField->Text, &uri))
|
||||
{
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#include "pch.h"
|
||||
#include "Scenario7_DownloadReordering.xaml.h"
|
||||
|
||||
using namespace SDKTemplate;
|
||||
|
||||
using namespace Concurrency;
|
||||
using namespace Windows::Networking;
|
||||
using namespace Windows::Networking::BackgroundTransfer;
|
||||
using namespace Windows::Foundation::Collections;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Web;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
using namespace Windows::UI::Xaml::Navigation;
|
||||
using namespace Windows::UI::Xaml::Data;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Core;
|
||||
using namespace Windows::Storage;
|
||||
using namespace Platform::Collections;
|
||||
using namespace Platform;
|
||||
|
||||
DownloadOperationItem::DownloadOperationItem(DownloadOperation^ download)
|
||||
{
|
||||
_download = download;
|
||||
_percentComplete = 0;
|
||||
_stateText = "Idle";
|
||||
}
|
||||
|
||||
DownloadOperation^ DownloadOperationItem::download::get()
|
||||
{
|
||||
return _download;
|
||||
}
|
||||
|
||||
int DownloadOperationItem::percentComplete::get()
|
||||
{
|
||||
return _percentComplete;
|
||||
}
|
||||
|
||||
void DownloadOperationItem::percentComplete::set(int value)
|
||||
{
|
||||
if (_percentComplete != value)
|
||||
{
|
||||
_percentComplete = value;
|
||||
PropertyChanged(this, ref new PropertyChangedEventArgs("percentComplete"));
|
||||
}
|
||||
}
|
||||
|
||||
String^ DownloadOperationItem::stateText::get()
|
||||
{
|
||||
return _stateText;
|
||||
}
|
||||
|
||||
void DownloadOperationItem::stateText::set(String^ value)
|
||||
{
|
||||
if (_stateText != value)
|
||||
{
|
||||
_stateText = value;
|
||||
PropertyChanged(this, ref new PropertyChangedEventArgs("stateText"));
|
||||
}
|
||||
}
|
||||
|
||||
Scenario7_DownloadReordering::Scenario7_DownloadReordering()
|
||||
{
|
||||
reorderGroup = BackgroundTransferGroup::CreateGroup("{7421B969-18D4-4532-B6BD-22BDABF71C08}");
|
||||
reorderGroup->TransferBehavior = BackgroundTransferBehavior::Serialized;
|
||||
_downloadCollection = ref new Vector<DownloadOperationItem^>();
|
||||
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
IObservableVector<DownloadOperationItem^>^ Scenario7_DownloadReordering::downloadCollection::get()
|
||||
{
|
||||
return _downloadCollection;
|
||||
}
|
||||
|
||||
void Scenario7_DownloadReordering::OnNavigatedTo(NavigationEventArgs^ e)
|
||||
{
|
||||
rootPage = MainPage::Current;
|
||||
CancelActiveDownloadsAsync().then([this](task<std::vector<DownloadOperation^>> previousTask)
|
||||
{
|
||||
try
|
||||
{
|
||||
previousTask.get();
|
||||
}
|
||||
catch (Exception^ ex)
|
||||
{
|
||||
if (!IsWebException("Discovery error", ex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
task<std::vector<DownloadOperation^>> Scenario7_DownloadReordering::CancelActiveDownloadsAsync()
|
||||
{
|
||||
// Only the downloads that belong to the transfer group used by this sample scenario will be
|
||||
// canceled.
|
||||
return create_task(BackgroundDownloader::GetCurrentDownloadsForTransferGroupAsync(reorderGroup))
|
||||
.then([this](IVectorView<DownloadOperation^>^ downloads)
|
||||
{
|
||||
std::vector<task<DownloadOperation^>> tasks;
|
||||
|
||||
// If previous instances of this scenario started transfers that haven't completed yet,
|
||||
// cancel them now so that we can start this scenario cleanly.
|
||||
if (downloads->Size > 0)
|
||||
{
|
||||
cancellation_token_source cancellationToken;
|
||||
|
||||
for (DownloadOperation^ download : downloads) {
|
||||
tasks.push_back(create_task(download->AttachAsync(), cancellationToken.get_token()));
|
||||
}
|
||||
|
||||
cancellationToken.cancel();
|
||||
}
|
||||
|
||||
return when_all(tasks.begin(), tasks.end());
|
||||
});
|
||||
}
|
||||
|
||||
void Scenario7_DownloadReordering::StartDownload_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
Button^ startButton = safe_cast<Button^>(sender);
|
||||
startButton->IsEnabled = false;
|
||||
|
||||
// Create and start downloads.
|
||||
RunDownloadsAsync().then([this, startButton]()
|
||||
{
|
||||
// After all downloads are complete, let the user start new ones again.
|
||||
startButton->IsEnabled = true;
|
||||
}, task_continuation_context::use_current());
|
||||
}
|
||||
|
||||
void Scenario7_DownloadReordering::MakeCurrent_Click(Object^ sender, RoutedEventArgs e)
|
||||
{
|
||||
Button^ button = safe_cast<Button^>(sender);
|
||||
DownloadOperationItem^ item = safe_cast<DownloadOperationItem^>(button->DataContext);
|
||||
|
||||
// Make the selected operation current.
|
||||
item->download->MakeCurrentInTransferGroup();
|
||||
}
|
||||
|
||||
task<void> Scenario7_DownloadReordering::RunDownloadsAsync()
|
||||
{
|
||||
// Create a downloader and associate all its downloads with the transfer group used for this
|
||||
// scenario.
|
||||
BackgroundDownloader^ downloader = ref new BackgroundDownloader();
|
||||
downloader->TransferGroup = reorderGroup;
|
||||
|
||||
// Validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling rootPage->TryGetUri() that will return 'false' for strings
|
||||
// that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intranet that
|
||||
// require the "Private Networks (Client and Server)" capability.
|
||||
String^ remoteAddress = StringTrimmer::Trim(remoteAddressField->Text);
|
||||
Uri^ tmpUri;
|
||||
if (!rootPage->TryGetUri(remoteAddress, &tmpUri))
|
||||
{
|
||||
return task_from_result();
|
||||
}
|
||||
|
||||
String^ fileName = StringTrimmer::Trim(fileNameField->Text);
|
||||
if (fileName->IsEmpty())
|
||||
{
|
||||
rootPage->NotifyUser("A local file name is required.", NotifyType::ErrorMessage);
|
||||
return task_from_result();
|
||||
}
|
||||
|
||||
// Try to create some downloads.
|
||||
std::vector<task<DownloadOperation^>> createDownloadTasks;
|
||||
for (int i = 0; i < NumDownloads; i++)
|
||||
{
|
||||
String^ currRemoteAddress = remoteAddress + "?id=" + i.ToString();
|
||||
String^ currFileName = i.ToString() + "." + fileName;
|
||||
createDownloadTasks.push_back(CreateDownloadAsync(downloader, currRemoteAddress, currFileName));
|
||||
}
|
||||
|
||||
return when_all(createDownloadTasks.begin(), createDownloadTasks.end())
|
||||
.then([this](std::vector<DownloadOperation^> downloads)
|
||||
{
|
||||
// Once all downloads have been created, start them.
|
||||
_downloadCollection->Clear();
|
||||
std::vector<task<void>> downloadTasks;
|
||||
for (DownloadOperation^ download : downloads)
|
||||
{
|
||||
DownloadOperationItem^ item = ref new DownloadOperationItem(download);
|
||||
downloadTasks.push_back(DownloadAsync(item));
|
||||
_downloadCollection->Append(item);
|
||||
}
|
||||
return when_all(downloadTasks.begin(), downloadTasks.end());
|
||||
});
|
||||
}
|
||||
|
||||
task<DownloadOperation^> Scenario7_DownloadReordering::CreateDownloadAsync(
|
||||
BackgroundDownloader^ downloader,
|
||||
String^ remoteAddress,
|
||||
String^ fileName)
|
||||
{
|
||||
return create_task(KnownFolders::PicturesLibrary->CreateFileAsync(
|
||||
fileName,
|
||||
CreationCollisionOption::GenerateUniqueName))
|
||||
.then([this, downloader, remoteAddress](StorageFile^ destinationFile)
|
||||
{
|
||||
Uri^ source = ref new Uri(remoteAddress);
|
||||
return downloader->CreateDownload(source, destinationFile);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
task<void> Scenario7_DownloadReordering::DownloadAsync(DownloadOperationItem^ item)
|
||||
{
|
||||
IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ async = item->download->StartAsync();
|
||||
async->Progress = ref new AsyncOperationProgressHandler<DownloadOperation^, DownloadOperation^>(
|
||||
[this, item](
|
||||
IAsyncOperationWithProgress<DownloadOperation^, DownloadOperation^>^ operation,
|
||||
DownloadOperation^ download)
|
||||
{
|
||||
DownloadProgress(item);
|
||||
});
|
||||
return create_task(async).then([this, item](DownloadOperation^ download)
|
||||
{
|
||||
item->stateText = item->download->Progress.Status.ToString();
|
||||
rootPage->NotifyUser(
|
||||
"Downloading " + item->download->ResultFile->Name + " completed.",
|
||||
NotifyType::StatusMessage);
|
||||
}).then([this, item](task<void> previousTask)
|
||||
{
|
||||
try
|
||||
{
|
||||
previousTask.get();
|
||||
}
|
||||
catch (Exception^ ex)
|
||||
{
|
||||
// Ignore canceled downloads since they are not displayed.
|
||||
if (item->download->Progress.Status != BackgroundTransferStatus::Canceled)
|
||||
{
|
||||
// Ensure that we reach 100% even for errors.
|
||||
item->percentComplete = 100;
|
||||
item->stateText = item->download->Progress.Status.ToString();
|
||||
if (!IsWebException("Execution error", ex, item->download))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Scenario7_DownloadReordering::DownloadProgress(DownloadOperationItem^ item)
|
||||
{
|
||||
BackgroundDownloadProgress currentProgress = item->download->Progress;
|
||||
BackgroundTransferStatus status = currentProgress.Status;
|
||||
int percentComplete = 0;
|
||||
|
||||
if (currentProgress.TotalBytesToReceive > 0)
|
||||
{
|
||||
percentComplete = (int)((currentProgress.BytesReceived * 100) / currentProgress.TotalBytesToReceive);
|
||||
}
|
||||
|
||||
Dispatcher->RunAsync(CoreDispatcherPriority::Normal, ref new DispatchedHandler(
|
||||
[this, item, status, percentComplete]()
|
||||
{
|
||||
item->stateText = status.ToString();
|
||||
item->percentComplete = percentComplete;
|
||||
}));
|
||||
}
|
||||
|
||||
bool Scenario7_DownloadReordering::IsWebException(String^ title, Exception^ ex, DownloadOperation^ download)
|
||||
{
|
||||
WebErrorStatus error = BackgroundTransferError::GetStatus(ex->HResult);
|
||||
bool result = (error != WebErrorStatus::Unknown);
|
||||
String^ message = result ? error.ToString() : ex->Message;
|
||||
|
||||
if (download == nullptr)
|
||||
{
|
||||
rootPage->NotifyUser(title + ": " + message, NotifyType::ErrorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage->NotifyUser(download->ResultFile->Name + " - " + title + ": " + message, NotifyType::ErrorMessage);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include "Scenario7_DownloadReordering.g.h"
|
||||
#include "MainPage.xaml.h"
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
// Class for each download and its row in the UI.
|
||||
public ref class DownloadOperationItem sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged
|
||||
{
|
||||
public:
|
||||
DownloadOperationItem(Windows::Networking::BackgroundTransfer::DownloadOperation^ download);
|
||||
|
||||
virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
|
||||
|
||||
property Windows::Networking::BackgroundTransfer::DownloadOperation^ download
|
||||
{
|
||||
Windows::Networking::BackgroundTransfer::DownloadOperation^ get();
|
||||
}
|
||||
|
||||
property int percentComplete
|
||||
{
|
||||
int get();
|
||||
void set(int value);
|
||||
}
|
||||
|
||||
property Platform::String^ stateText
|
||||
{
|
||||
Platform::String^ get();
|
||||
void set(Platform::String^ value);
|
||||
}
|
||||
|
||||
private:
|
||||
Windows::Networking::BackgroundTransfer::DownloadOperation^ _download;
|
||||
int _percentComplete;
|
||||
Platform::String^ _stateText;
|
||||
};
|
||||
|
||||
[Windows::Foundation::Metadata::WebHostHidden]
|
||||
public ref class Scenario7_DownloadReordering sealed
|
||||
{
|
||||
public:
|
||||
Scenario7_DownloadReordering();
|
||||
|
||||
property Windows::Foundation::Collections::IObservableVector<DownloadOperationItem^>^ downloadCollection
|
||||
{
|
||||
Windows::Foundation::Collections::IObservableVector<DownloadOperationItem^>^ get();
|
||||
}
|
||||
protected:
|
||||
virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
|
||||
|
||||
private:
|
||||
Concurrency::task<std::vector<Windows::Networking::BackgroundTransfer::DownloadOperation^>>
|
||||
CancelActiveDownloadsAsync();
|
||||
void StartDownload_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
|
||||
void MakeCurrent_Click(Object^ sender, Windows::UI::Xaml::RoutedEventArgs e);
|
||||
Concurrency::task<void> RunDownloadsAsync();
|
||||
Concurrency::task<Windows::Networking::BackgroundTransfer::DownloadOperation^> CreateDownloadAsync(
|
||||
Windows::Networking::BackgroundTransfer::BackgroundDownloader^ downloader,
|
||||
Platform::String^ remoteAddress,
|
||||
Platform::String^ fileName);
|
||||
Concurrency::task<void> DownloadAsync(DownloadOperationItem^ item);
|
||||
void DownloadProgress(DownloadOperationItem^ item);
|
||||
bool Scenario7_DownloadReordering::IsWebException(
|
||||
Platform::String^ title,
|
||||
Platform::Exception^ ex,
|
||||
Windows::Networking::BackgroundTransfer::DownloadOperation^ download = nullptr);
|
||||
|
||||
const int NumDownloads = 5;
|
||||
|
||||
MainPage^ rootPage;
|
||||
Windows::Networking::BackgroundTransfer::BackgroundTransferGroup^ reorderGroup;
|
||||
Windows::Foundation::Collections::IObservableVector<DownloadOperationItem^>^ _downloadCollection;
|
||||
};
|
||||
}
|
|
@ -36,8 +36,8 @@
|
|||
<AppContainerApplication>true</AppContainerApplication>
|
||||
<ApplicationType>Windows Store</ApplicationType>
|
||||
<ApplicationTypeRevision>10.0</ApplicationTypeRevision>
|
||||
<WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.16299.0</WindowsTargetPlatformMinVersion>
|
||||
<WindowsTargetPlatformVersion>10.0.17069.0</WindowsTargetPlatformVersion>
|
||||
<WindowsTargetPlatformMinVersion>10.0.17069.0</WindowsTargetPlatformMinVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<AssemblyName>BackgroundTransfer</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformVersion>10.0.17069.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17069.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
|
@ -121,6 +121,9 @@
|
|||
<Compile Include="Scenario6_RecoverableErrors.xaml.cs">
|
||||
<DependentUpon>Scenario6_RecoverableErrors.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Scenario7_DownloadReordering.xaml.cs">
|
||||
<DependentUpon>Scenario7_DownloadReordering.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
|
@ -168,6 +171,11 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="..\..\shared\Scenario7_DownloadReordering.xaml">
|
||||
<Link>Scenario7_DownloadReordering.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="..\..\..\..\SharedContent\xaml\Styles.xaml">
|
||||
<Link>Styles\Styles.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.16299.0" MaxVersionTested="10.0.16299.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17069.0" MaxVersionTested="10.0.17069.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
|
|
@ -26,7 +26,8 @@ namespace SDKTemplate
|
|||
new Scenario() { Title="Completion Notifications", ClassType=typeof(Scenario3_Notifications)},
|
||||
new Scenario() { Title="Completion Groups", ClassType=typeof(Scenario4_CompletionGroups)},
|
||||
new Scenario() { Title="Random Access Downloads", ClassType=typeof(Scenario5_RandomAccess)},
|
||||
new Scenario() { Title="Recoverable Errors", ClassType=typeof(Scenario6_RecoverableErrors)}
|
||||
new Scenario() { Title="Recoverable Errors", ClassType=typeof(Scenario6_RecoverableErrors)},
|
||||
new Scenario() { Title="Download Reordering", ClassType=typeof(Scenario7_DownloadReordering)},
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ namespace SDKTemplate
|
|||
// Validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
// the "Home or Work Networking" capability.
|
||||
// the "Private Networks (Client and Server)" capability.
|
||||
Uri source;
|
||||
if (!Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, out source))
|
||||
{
|
||||
|
|
|
@ -115,7 +115,7 @@ namespace SDKTemplate
|
|||
// Validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
// the "Home or Work Networking" capability.
|
||||
// the "Private Networks (Client and Server)" capability.
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, out uri))
|
||||
{
|
||||
|
@ -163,7 +163,7 @@ namespace SDKTemplate
|
|||
// box validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
// the "Home or Work Networking" capability.
|
||||
// the "Private Networks (Client and Server)" capability.
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, out uri))
|
||||
{
|
||||
|
|
|
@ -188,7 +188,7 @@ namespace SDKTemplate
|
|||
// Validating the URI is required since it was received from an untrusted source (user input).
|
||||
// The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
// the "Home or Work Networking" capability.
|
||||
// the "Private Networks (Client and Server)" capability.
|
||||
if (!Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, out baseUri))
|
||||
{
|
||||
rootPage.NotifyUser("Invalid URI.", NotifyType.ErrorMessage);
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Networking.BackgroundTransfer;
|
||||
using Windows.Storage;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Web;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
// Class for each download and its row in the UI.
|
||||
public class DownloadOperationItem : INotifyPropertyChanged
|
||||
{
|
||||
public DownloadOperationItem(DownloadOperation download)
|
||||
{
|
||||
_download = download;
|
||||
_percentComplete = 0;
|
||||
_stateText = "Idle";
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
public DownloadOperation download
|
||||
{
|
||||
get
|
||||
{
|
||||
return _download;
|
||||
}
|
||||
}
|
||||
|
||||
public int percentComplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return _percentComplete;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_percentComplete = value;
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs("percentComplete"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string stateText
|
||||
{
|
||||
get
|
||||
{
|
||||
return _stateText;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
_stateText = value;
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs("stateText"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DownloadOperation _download;
|
||||
private int _percentComplete;
|
||||
private string _stateText;
|
||||
}
|
||||
|
||||
public sealed partial class Scenario7_DownloadReordering : Page
|
||||
{
|
||||
private const int NumDownloads = 5;
|
||||
|
||||
private MainPage rootPage;
|
||||
private BackgroundTransferGroup reorderGroup;
|
||||
public ObservableCollection<DownloadOperationItem> downloadCollection { get; } =
|
||||
new ObservableCollection<DownloadOperationItem>();
|
||||
|
||||
public Scenario7_DownloadReordering()
|
||||
{
|
||||
reorderGroup = BackgroundTransferGroup.CreateGroup("{7421B969-18D4-4532-B6BD-22BDABF71C08}");
|
||||
reorderGroup.TransferBehavior = BackgroundTransferBehavior.Serialized;
|
||||
this.DataContext = this;
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected async override void OnNavigatedTo(NavigationEventArgs e)
|
||||
{
|
||||
rootPage = MainPage.Current;
|
||||
await CancelActiveDownloadsAsync();
|
||||
}
|
||||
|
||||
private async Task CancelActiveDownloadsAsync()
|
||||
{
|
||||
// Only the downloads that belong to the transfer group used by this sample scenario
|
||||
// will be canceled.
|
||||
IReadOnlyList<DownloadOperation> downloads = null;
|
||||
try
|
||||
{
|
||||
downloads = await BackgroundDownloader.GetCurrentDownloadsForTransferGroupAsync(reorderGroup);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!IsWebException("Discovery error", ex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If previous instances of this scenario started transfers that haven't completed yet,
|
||||
// cancel them now so that we can start this scenario cleanly.
|
||||
if (downloads.Count > 0)
|
||||
{
|
||||
CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
||||
cancellationToken.Cancel();
|
||||
|
||||
Task[] tasks = new Task[downloads.Count];
|
||||
for (int i = 0; i < downloads.Count; i++)
|
||||
{
|
||||
tasks[i] = downloads[i].AttachAsync().AsTask(cancellationToken.Token);
|
||||
}
|
||||
|
||||
// Cancel each download and ignore the cancellation exception.
|
||||
try
|
||||
{
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void StartDownload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
startDownloadButton.IsEnabled = false;
|
||||
|
||||
// Create and start downloads.
|
||||
await RunDownloadsAsync();
|
||||
|
||||
// After all downloads are complete, let the user start new ones again.
|
||||
startDownloadButton.IsEnabled = true;
|
||||
}
|
||||
|
||||
private void MakeCurrent_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Button button = sender as Button;
|
||||
DownloadOperationItem item = button.DataContext as DownloadOperationItem;
|
||||
|
||||
// Make the selected operation current.
|
||||
item.download.MakeCurrentInTransferGroup();
|
||||
}
|
||||
|
||||
private async Task RunDownloadsAsync()
|
||||
{
|
||||
// Create a downloader and associate all its downloads with the transfer group used for
|
||||
// this scenario.
|
||||
BackgroundDownloader downloader = new BackgroundDownloader();
|
||||
downloader.TransferGroup = reorderGroup;
|
||||
|
||||
// Validating the URI is required since it was received from an untrusted source (user
|
||||
// input).
|
||||
// The URI is validated by calling Uri.TryCreate() that will return 'false' for strings
|
||||
// that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the
|
||||
// intranet that require the "Private Networks (Client and Server)" capability.
|
||||
string remoteAddress = remoteAddressField.Text.Trim();
|
||||
Uri tmpUri;
|
||||
if (!Uri.TryCreate(remoteAddress, UriKind.Absolute, out tmpUri))
|
||||
{
|
||||
rootPage.NotifyUser("Invalid URI.", NotifyType.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
string fileName = fileNameField.Text.Trim();
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
rootPage.NotifyUser("A local file name is required.", NotifyType.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to create some downloads.
|
||||
DownloadOperation[] downloads = new DownloadOperation[NumDownloads];
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < NumDownloads; i++)
|
||||
{
|
||||
string currRemoteAddress = $"{remoteAddress}?id={i}";
|
||||
string currFileName = $"{i}.{fileName}";
|
||||
downloads[i] = await CreateDownload(downloader, currRemoteAddress, currFileName);
|
||||
}
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
rootPage.NotifyUser($"Error while creating file: {ex.Message}", NotifyType.ErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
// Once all downloads have been created, start them.
|
||||
Task[] downloadTasks = new Task[downloads.Length];
|
||||
downloadCollection.Clear();
|
||||
for (int i = 0; i < downloads.Length; i++)
|
||||
{
|
||||
DownloadOperationItem item = new DownloadOperationItem(downloads[i]);
|
||||
downloadTasks[i] = DownloadAsync(item);
|
||||
downloadCollection.Add(item);
|
||||
}
|
||||
|
||||
await Task.WhenAll(downloadTasks);
|
||||
}
|
||||
|
||||
private async Task<DownloadOperation> CreateDownload(
|
||||
BackgroundDownloader downloader,
|
||||
string remoteAddress,
|
||||
string fileName)
|
||||
{
|
||||
Uri source = new Uri(remoteAddress);
|
||||
|
||||
StorageFile destinationFile;
|
||||
try
|
||||
{
|
||||
destinationFile = await KnownFolders.PicturesLibrary.CreateFileAsync(
|
||||
fileName,
|
||||
CreationCollisionOption.GenerateUniqueName);
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
rootPage.NotifyUser($"Error while creating file: {ex.Message}", NotifyType.ErrorMessage);
|
||||
throw;
|
||||
}
|
||||
|
||||
return downloader.CreateDownload(source, destinationFile);
|
||||
}
|
||||
|
||||
private async Task DownloadAsync(DownloadOperationItem item)
|
||||
{
|
||||
Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(
|
||||
(operation) => DownloadProgress(item));
|
||||
|
||||
try
|
||||
{
|
||||
await item.download.StartAsync().AsTask(progressCallback);
|
||||
|
||||
item.stateText = item.download.Progress.Status.ToString();
|
||||
rootPage.NotifyUser(
|
||||
$"Downloading {item.download.ResultFile.Name} completed.",
|
||||
NotifyType.StatusMessage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// Ignore canceled downloads since they are not displayed.
|
||||
if (item.download.Progress.Status != BackgroundTransferStatus.Canceled)
|
||||
{
|
||||
// Ensure that we reach 100% even for errors.
|
||||
item.percentComplete = 100;
|
||||
item.stateText = item.download.Progress.Status.ToString();
|
||||
if (!IsWebException("Execution error", ex, item.download))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadProgress(DownloadOperationItem item)
|
||||
{
|
||||
BackgroundDownloadProgress currentProgress = item.download.Progress;
|
||||
BackgroundTransferStatus status = currentProgress.Status;
|
||||
int percentComplete = 0;
|
||||
|
||||
if (currentProgress.TotalBytesToReceive > 0)
|
||||
{
|
||||
percentComplete = (int)((currentProgress.BytesReceived * 100) / currentProgress.TotalBytesToReceive);
|
||||
}
|
||||
|
||||
var ignore = this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
item.stateText = status.ToString();
|
||||
item.percentComplete = percentComplete;
|
||||
});
|
||||
}
|
||||
|
||||
private bool IsWebException(string title, Exception ex, DownloadOperation download = null)
|
||||
{
|
||||
WebErrorStatus error = BackgroundTransferError.GetStatus(ex.HResult);
|
||||
bool result = (error != WebErrorStatus.Unknown);
|
||||
string message = result ? error.ToString() : ex.Message;
|
||||
|
||||
if (download == null)
|
||||
{
|
||||
rootPage.NotifyUser($"{title}: {message}", NotifyType.ErrorMessage);
|
||||
}
|
||||
else
|
||||
{
|
||||
rootPage.NotifyUser($"{download.ResultFile.Name} - {title}: {message}", NotifyType.ErrorMessage);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,8 +11,8 @@
|
|||
<AssemblyName>Tasks</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformVersion>10.0.17069.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17069.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\$(WMSJSProjectDirectory)\Microsoft.VisualStudio.$(WMSJSProject).props" />
|
||||
<PropertyGroup>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformVersion>10.0.17069.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17069.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>$(VersionNumberMajor).$(VersionNumberMinor)</MinimumVisualStudioVersion>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
</PropertyGroup>
|
||||
|
@ -87,6 +87,7 @@
|
|||
<Content Include="html\scenario4_CompletionGroups.html" />
|
||||
<Content Include="html\scenario5_RandomAccess.html" />
|
||||
<Content Include="html\scenario6_RecoverableErrors.html" />
|
||||
<Content Include="html\scenario7_DownloadReordering.html" />
|
||||
<Content Include="js\completionGroupBackgroundTask.js" />
|
||||
<Content Include="js\sample-configuration.js" />
|
||||
<Content Include="js\scenario1_Download.js" />
|
||||
|
@ -95,6 +96,7 @@
|
|||
<Content Include="js\scenario4_CompletionGroups.js" />
|
||||
<Content Include="js\scenario5_RandomAccess.js" />
|
||||
<Content Include="js\scenario6_RecoverableErrors.js" />
|
||||
<Content Include="js\scenario7_DownloadReordering.js" />
|
||||
<Content Include="..\..\..\SharedContent\js\Microsoft.WinJS\css\ui-dark.css">
|
||||
<Link>Microsoft.WinJS.4.0\css\ui-dark.css</Link>
|
||||
</Content>
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script src="/js/scenario7_DownloadReordering.js"></script>
|
||||
</head>
|
||||
<body class="win-type-body">
|
||||
<h2 id="sampleHeader" class="win-type-subheader">Description:</h2>
|
||||
<div id="scenarioDescription">Download reordering</div>
|
||||
<p>
|
||||
Transfers which belong to the same transfer group can be reordered after they have been started.
|
||||
</p>
|
||||
<p>
|
||||
<label for="remoteAddressField">Remote address: </label>
|
||||
<input type="text" class="win-textbox" id="remoteAddressField" value="http://localhost/BackgroundTransferSample/download.aspx" />
|
||||
</p>
|
||||
<p>
|
||||
<label for="fileNameField">Local file name: </label>
|
||||
<input type="text" class="win-textbox" id="fileNameField" value="DownloadReordering.txt" />
|
||||
</p>
|
||||
<p>
|
||||
<button class="win-button" id="startDownloadButton">Start Download</button>
|
||||
</p>
|
||||
<p>
|
||||
Select a pending transfer to reorder the downloads.
|
||||
</p>
|
||||
<p>
|
||||
<button class="win-button" id="makeCurrentButton0" disabled>Make Current</button>
|
||||
<input id="percentCompleteInput0" type="range" min="0" max="100" step="1" value="0" />
|
||||
<span id="stateTextSpan0">idle</span>
|
||||
</p>
|
||||
<p>
|
||||
<button class="win-button" id="makeCurrentButton1" disabled>Make Current</button>
|
||||
<input id="percentCompleteInput1" type="range" min="0" max="100" step="1" value="0" />
|
||||
<span id="stateTextSpan1">idle</span>
|
||||
</p>
|
||||
<p>
|
||||
<button class="win-button" id="makeCurrentButton2" disabled>Make Current</button>
|
||||
<input id="percentCompleteInput2" type="range" min="0" max="100" step="1" value="0" />
|
||||
<span id="stateTextSpan2">idle</span>
|
||||
</p>
|
||||
<p>
|
||||
<button class="win-button" id="makeCurrentButton3" disabled>Make Current</button>
|
||||
<input id="percentCompleteInput3" type="range" min="0" max="100" step="1" value="0" />
|
||||
<span id="stateTextSpan3">idle</span>
|
||||
</p>
|
||||
<p>
|
||||
<button class="win-button" id="makeCurrentButton4" disabled>Make Current</button>
|
||||
<input id="percentCompleteInput4" type="range" min="0" max="100" step="1" value="0" />
|
||||
<span id="stateTextSpan4">idle</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -19,7 +19,8 @@
|
|||
{ url: "/html/scenario3_Notifications.html", title: "Completion Notifications" },
|
||||
{ url: "/html/scenario4_CompletionGroups.html", title: "Completion Groups" },
|
||||
{ url: "/html/scenario5_RandomAccess.html", title: "Random Access" },
|
||||
{ url: "/html/scenario6_RecoverableErrors.html", title: "Recoverable Errors" }
|
||||
{ url: "/html/scenario6_RecoverableErrors.html", title: "Recoverable Errors" },
|
||||
{ url: "/html/scenario7_DownloadReordering.html", title: "Download Reordering" }
|
||||
];
|
||||
|
||||
// Look up the name for an enumeration member.
|
||||
|
|
|
@ -44,32 +44,6 @@
|
|||
// Global array used to persist operations.
|
||||
var downloadOperations = [];
|
||||
|
||||
function backgroundTransferStatusToString(transferStatus) {
|
||||
switch (transferStatus)
|
||||
{
|
||||
case BackgroundTransfer.BackgroundTransferStatus.idle:
|
||||
return "Idle";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.running:
|
||||
return "Running";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedByApplication:
|
||||
return "PausedByApplication";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedCostedNetwork:
|
||||
return "PausedCostedNetwork";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedNoNetwork:
|
||||
return "PausedNoNetwork";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.completed:
|
||||
return "Completed";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.canceled:
|
||||
return "Canceled";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.error:
|
||||
return "Error";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedSystemPolicy:
|
||||
return "PausedSystemPolicy";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Class associated with each download.
|
||||
function DownloadOperation() {
|
||||
var download = null;
|
||||
|
@ -100,7 +74,8 @@
|
|||
this.load = function (loadedDownload) {
|
||||
download = loadedDownload;
|
||||
printLog("Discovered background download: " + download.guid + ", Status: " +
|
||||
backgroundTransferStatusToString(download.progress.status) + "<br/>");
|
||||
SdkSample.lookupEnumName(BackgroundTransfer.BackgroundTransferStatus, download.progress.status) +
|
||||
"<br/>");
|
||||
promise = download.attachAsync().then(complete, error, progress);
|
||||
};
|
||||
|
||||
|
@ -128,7 +103,8 @@
|
|||
printLog("Resumed: " + download.guid + "<br/>");
|
||||
} else {
|
||||
printLog("Skipped: " + download.guid + ", Status: " +
|
||||
backgroundTransferStatusToString(currentProgress.status) + "<br/>");
|
||||
SdkSample.lookupEnumName(BackgroundTransfer.BackgroundTransferStatus, currentProgress.status) +
|
||||
"<br/>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -146,7 +122,8 @@
|
|||
printLog("Paused: " + download.guid + "<br/>");
|
||||
} else {
|
||||
printLog("Skipped: " + download.guid + ", Status: " +
|
||||
backgroundTransferStatusToString(currentProgress.status) + "<br/>");
|
||||
SdkSample.lookupEnumName(BackgroundTransfer.BackgroundTransferStatus, currentProgress.status) +
|
||||
"<br/>");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -173,7 +150,8 @@
|
|||
var currentProgress = download.progress;
|
||||
|
||||
printLog("Progress: " + download.guid + ", Status: " +
|
||||
backgroundTransferStatusToString(currentProgress.status) + "<br/>");
|
||||
SdkSample.lookupEnumName(BackgroundTransfer.BackgroundTransferStatus, currentProgress.status) +
|
||||
"<br/>");
|
||||
|
||||
var percent = 100;
|
||||
if (currentProgress.totalBytesToReceive > 0) {
|
||||
|
|
|
@ -61,31 +61,6 @@
|
|||
|
||||
var maxUploadFileSize = 100 * 1024 * 1024; // 100 MB (arbitrary limit chosen for this sample)
|
||||
|
||||
function backgroundTransferStatusToString(transferStatus) {
|
||||
switch (transferStatus) {
|
||||
case BackgroundTransfer.BackgroundTransferStatus.idle:
|
||||
return "Idle";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.running:
|
||||
return "Running";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedByApplication:
|
||||
return "PausedByApplication";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedCostedNetwork:
|
||||
return "PausedCostedNetwork";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedNoNetwork:
|
||||
return "PausedNoNetwork";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.completed:
|
||||
return "Completed";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.canceled:
|
||||
return "Canceled";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.error:
|
||||
return "Error";
|
||||
case BackgroundTransfer.BackgroundTransferStatus.pausedSystemPolicy:
|
||||
return "PausedSystemPolicy";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
// Class associated with each upload.
|
||||
function UploadOperation() {
|
||||
var upload = null;
|
||||
|
@ -132,7 +107,8 @@
|
|||
this.load = function (loadedUpload) {
|
||||
upload = loadedUpload;
|
||||
printLog("Discovered background upload: " + upload.guid + " , Status: " +
|
||||
backgroundTransferStatusToString(upload.progress.status) + "<br/>");
|
||||
SdkSample.lookupEnumName(BackgroundTransfer.BackgroundTransferStatus, upload.progress.status) +
|
||||
"<br/>");
|
||||
promise = upload.attachAsync().then(complete, error, progress);
|
||||
};
|
||||
|
||||
|
@ -169,7 +145,8 @@
|
|||
var currentProgress = upload.progress;
|
||||
|
||||
printLog("Progress: " + upload.guid + ", Status: " +
|
||||
backgroundTransferStatusToString(currentProgress.status) + "<br/>");
|
||||
SdkSample.lookupEnumName(BackgroundTransfer.BackgroundTransferStatus, currentProgress.status) +
|
||||
"<br/>");
|
||||
|
||||
var percent = 100;
|
||||
if (currentProgress.totalBytesToSend > 0) {
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var BackgroundTransfer = Windows.Networking.BackgroundTransfer;
|
||||
|
||||
// Class for each download and its row in the UI.
|
||||
function DownloadCollectionItem(i) {
|
||||
var makeCurrentButton = document.getElementById("makeCurrentButton" + i);
|
||||
var percentCompleteInput = document.getElementById("percentCompleteInput" + i);
|
||||
var stateTextSpan = document.getElementById("stateTextSpan" + i);
|
||||
var download = null;
|
||||
|
||||
this.startAsync = function (dl) {
|
||||
download = dl;
|
||||
|
||||
makeCurrentButton.addEventListener("click", makeCurrent_click);
|
||||
makeCurrentButton.disabled = false;
|
||||
percentCompleteInput.value = 0;
|
||||
stateTextSpan.innerText = "idle";
|
||||
|
||||
return download.startAsync().then(complete, error, progress);
|
||||
}
|
||||
|
||||
this.reset = function () {
|
||||
makeCurrentButton.disabled = true;
|
||||
download = null;
|
||||
}
|
||||
|
||||
function makeCurrent_click() {
|
||||
// Make the selected operation current.
|
||||
download.makeCurrentInTransferGroup();
|
||||
}
|
||||
|
||||
function complete() {
|
||||
stateTextSpan.innerText = SdkSample.lookupEnumName(
|
||||
BackgroundTransfer.BackgroundTransferStatus,
|
||||
download.progress.status);
|
||||
WinJS.log(`Downloading ${download.resultFile.name} completed.`, "sample", "status");
|
||||
};
|
||||
|
||||
function error(err) {
|
||||
// Ignore canceled downloads since they are not displayed.
|
||||
if (download.progress.status != BackgroundTransfer.BackgroundTransferStatus.canceled) {
|
||||
// Ensure that we reach 100% even for errors.
|
||||
percentCompleteInput.value = 100;
|
||||
stateTextSpan.innerText = SdkSample.lookupEnumName(
|
||||
BackgroundTransfer.BackgroundTransferStatus,
|
||||
download.progress.status);
|
||||
if (!isWebException("Execution error", err, download)) {
|
||||
return WinJS.Promise.wrapError(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function progress() {
|
||||
var currentProgress = download.progress;
|
||||
var percentComplete = 0;
|
||||
|
||||
if (currentProgress.totalBytesToReceive > 0) {
|
||||
percentComplete = Math.floor(
|
||||
(currentProgress.bytesReceived * 100) / currentProgress.totalBytesToReceive);
|
||||
}
|
||||
|
||||
percentCompleteInput.value = percentComplete;
|
||||
stateTextSpan.innerText = SdkSample.lookupEnumName(
|
||||
BackgroundTransfer.BackgroundTransferStatus,
|
||||
currentProgress.status);
|
||||
}
|
||||
}
|
||||
|
||||
const NumDownloads = 5;
|
||||
|
||||
var remoteAddressField;
|
||||
var fileNameField;
|
||||
var startDownloadButton;
|
||||
|
||||
var reorderGroup;
|
||||
var downloadCollection;
|
||||
|
||||
var page = WinJS.UI.Pages.define("/html/scenario7_DownloadReordering.html", {
|
||||
ready: function (element, options) {
|
||||
remoteAddressField = document.getElementById("remoteAddressField");
|
||||
fileNameField = document.getElementById("fileNameField");
|
||||
startDownloadButton = document.getElementById("startDownloadButton");
|
||||
startDownloadButton.addEventListener("click", startDownload_click);
|
||||
|
||||
reorderGroup = BackgroundTransfer.BackgroundTransferGroup.createGroup(
|
||||
"{7421B969-18D4-4532-B6BD-22BDABF71C08}");
|
||||
reorderGroup.transferBehavior = BackgroundTransfer.BackgroundTransferBehavior.serialized;
|
||||
downloadCollection = [];
|
||||
for (var i = 0; i < NumDownloads; i++) {
|
||||
downloadCollection.push(new DownloadCollectionItem(i));
|
||||
}
|
||||
|
||||
cancelActiveDownloadsAsync().done();
|
||||
}
|
||||
});
|
||||
|
||||
function cancelActiveDownloadsAsync() {
|
||||
// Only the downloads that belong to the transfer group used by this sample scenario will be
|
||||
// canceled.
|
||||
return BackgroundTransfer.BackgroundDownloader.getCurrentDownloadsForTransferGroupAsync(reorderGroup)
|
||||
.then(function (downloads) {
|
||||
// If previous sample instances/scenarios started transfers that haven't completed yet,
|
||||
// cancel them now so that we can start this scenario cleanly.
|
||||
if (downloads.length > 0) {
|
||||
var promises = downloads.map(function (download) {
|
||||
// Cancel each download and ignore the cancellation exception.
|
||||
var downloadPromise = download.attachAsync();
|
||||
downloadPromise.cancel();
|
||||
return downloadPromise.then(null, function (err) {
|
||||
if (download.progress.status != BackgroundTransfer.BackgroundTransferStatus.canceled) {
|
||||
if (!isWebException("Discovery error", err, null)) {
|
||||
return WinJS.Promise.wrapError(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
return WinJS.Promise.join(promises);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function startDownload_click() {
|
||||
startDownloadButton.disabled = true;
|
||||
|
||||
// Create and start downloads.
|
||||
runDownloadAsync(function () {
|
||||
// After all downloads are complete, disable the downloads and let the user start new
|
||||
// ones again.
|
||||
downloadCollection.forEach(function (downloadCollectionItem) {
|
||||
downloadCollectionItem.reset();
|
||||
});
|
||||
startDownloadButton.disabled = false;
|
||||
});
|
||||
}
|
||||
|
||||
function runDownloadAsync(done_callback) {
|
||||
// Create a downloader and associate all its downloads with the transfer group used for this
|
||||
// scenario.
|
||||
var downloader = new BackgroundTransfer.BackgroundDownloader();
|
||||
downloader.transferGroup = reorderGroup;
|
||||
|
||||
// Validating the URI is required since it was received from an untrusted source (user
|
||||
// input).
|
||||
// The URI is validated by calling Windows.Foundation.Uri that will throw an exception for
|
||||
// strings that are not valid URIs.
|
||||
// Note that when enabling the text box users may provide URIs to machines on the intranet
|
||||
// that require the "Private Networks (Client and Server)" capability.
|
||||
var remoteAddress = remoteAddressField.value.trim();
|
||||
try {
|
||||
var uri = new Windows.Foundation.Uri(remoteAddress);
|
||||
}
|
||||
catch (error) {
|
||||
WinJS.log("Invalid URI.", "sample", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = fileNameField.value.trim();
|
||||
if (fileName == "") {
|
||||
WinJS.log("A local file name is required.", "sample", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to create some downloads.
|
||||
var createDownloadPromises = [];
|
||||
for (var i = 0; i < NumDownloads; i++) {
|
||||
createDownloadPromises.push(
|
||||
createDownloadAsync(downloader, remoteAddress + "?id=" + i, i + "." + fileName));
|
||||
}
|
||||
|
||||
return WinJS.Promise.join(createDownloadPromises).then(function (downloads) {
|
||||
// Once all downloads have been created, start them.
|
||||
var downloadPromises = [];
|
||||
for (var i = 0; i < downloads.length; i++) {
|
||||
var downloadCollectionItem = downloadCollection[i];
|
||||
downloadPromises.push(downloadCollectionItem.startAsync(downloads[i]));
|
||||
}
|
||||
|
||||
WinJS.Promise.join(downloadPromises).done(done_callback);
|
||||
});
|
||||
}
|
||||
|
||||
function createDownloadAsync(downloader, remoteAddress, fileName) {
|
||||
return Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(
|
||||
fileName,
|
||||
Windows.Storage.CreationCollisionOption.generateUniqueName).then(function (destinationFile) {
|
||||
var source = new Windows.Foundation.Uri(remoteAddress);
|
||||
return downloader.createDownload(source, destinationFile);
|
||||
}, function (e) {
|
||||
WinJS.log(`Error while creating file: ${e.message}`, "sample", "error");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function isWebException(title, ex, download) {
|
||||
var error = BackgroundTransfer.BackgroundTransferError.getStatus(ex.number);
|
||||
var result = (error != Windows.Web.WebErrorStatus.unknown);
|
||||
var message = result ? SdkSample.lookupEnumName(Windows.Web.WebErrorStatus, error) : ex.message;
|
||||
|
||||
if (download == null) {
|
||||
WinJS.log(`${title}: ${message}`, "sample", "error");
|
||||
} else {
|
||||
WinJS.log(`${download.resultFile.name} - ${title}: ${message}`, "sample", "error");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
})();
|
|
@ -19,7 +19,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.16299.0" MaxVersionTested="10.0.16299.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17069.0" MaxVersionTested="10.0.17069.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page x:Class="SDKTemplate.Scenario7_DownloadReordering" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="using:SDKTemplate" mc:Ignorable="d">
|
||||
<ScrollViewer HorizontalScrollMode="Disabled" VerticalScrollMode="Enabled" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel x:Name="LayoutRoot">
|
||||
<TextBlock x:Name="InputTextBlock1" TextWrapping="Wrap" Grid.Row="0" Style="{StaticResource BasicTextStyle}">
|
||||
Transfers which belong to the same transfer group can be reordered after they have been started.
|
||||
</TextBlock>
|
||||
<TextBlock Text="Remote address: " Style="{StaticResource BasicTextStyle}" Margin="0,8,10,0" />
|
||||
<TextBox x:Name="remoteAddressField" InputScope="Url" Text="http://localhost/BackgroundTransferSample/download.aspx" />
|
||||
<TextBlock Text="Local file name: " Style="{StaticResource BasicTextStyle}" Margin="0,8,17,0" />
|
||||
<TextBox x:Name="fileNameField" Text="DownloadReordering.txt" />
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<Button x:Name="startDownloadButton" Content="Start Download" Margin="0,0,10,0" Click="StartDownload_Click" />
|
||||
</StackPanel>
|
||||
<TextBlock Text="Select a pending transfer to reorder the downloads." Style="{StaticResource BasicTextStyle}" Margin="0,8,17,0" />
|
||||
|
||||
<ListView ItemsSource="{x:Bind downloadCollection, Mode=OneWay}">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate x:DataType="local:DownloadOperationItem">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Content="Make Current" Click="MakeCurrent_Click" />
|
||||
<ProgressBar Margin="10,0,0,0" Height="30" Width="200" Minimum="0" Maximum="100" Value="{x:Bind percentComplete, Mode=OneWay}" Foreground="Green" />
|
||||
<TextBlock Margin="10,0,0,0" Text="{x:Bind stateText, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
</ListView>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Page>
|
|
@ -92,7 +92,7 @@ Namespace Global.BackgroundTransfer
|
|||
' Validating the URI is required since it was received from an untrusted source (user input).
|
||||
' The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
' Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
' the "Home or Work Networking" capability.
|
||||
' the "Private Networks (Client and Server)" capability.
|
||||
Dim source As Uri = Nothing
|
||||
If Not Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, source) Then
|
||||
rootPage.NotifyUser("Invalid URI.", NotifyType.ErrorMessage)
|
||||
|
|
|
@ -93,7 +93,7 @@ Namespace Global.BackgroundTransfer
|
|||
' Validating the URI is required since it was received from an untrusted source (user input).
|
||||
' The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
' Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
' the "Home or Work Networking" capability.
|
||||
' the "Private Networks (Client and Server)" capability.
|
||||
Dim uri As Uri = Nothing
|
||||
If Not Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, uri) Then
|
||||
rootPage.NotifyUser("Invalid URI.", NotifyType.ErrorMessage)
|
||||
|
@ -129,7 +129,7 @@ Namespace Global.BackgroundTransfer
|
|||
' box validating the URI is required since it was received from an untrusted source (user input).
|
||||
' The URI is validated by calling Uri.TryCreate() that will return 'false' for strings that are not valid URIs.
|
||||
' Note that when enabling the text box users may provide URIs to machines on the intrAnet that require
|
||||
' the "Home or Work Networking" capability.
|
||||
' the "Private Networks (Client and Server)" capability.
|
||||
Dim uri As Uri = Nothing
|
||||
If Not Uri.TryCreate(serverAddressField.Text.Trim(), UriKind.Absolute, uri) Then
|
||||
rootPage.NotifyUser("Invalid URI.", NotifyType.ErrorMessage)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -46,4 +46,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.Devices.Enumeration;
|
||||
|
@ -63,6 +64,7 @@ namespace CameraGetPreviewFrame
|
|||
private MediaCapture _mediaCapture;
|
||||
private bool _isInitialized = false;
|
||||
private bool _isPreviewing = false;
|
||||
private static readonly SemaphoreSlim _mediaCaptureLifeLock = new SemaphoreSlim(1);
|
||||
|
||||
// Information about the camera device
|
||||
private bool _mirroringPreview = false;
|
||||
|
@ -93,7 +95,7 @@ namespace CameraGetPreviewFrame
|
|||
await CleanupCameraAsync();
|
||||
|
||||
_displayInformation.OrientationChanged -= DisplayInformation_OrientationChanged;
|
||||
|
||||
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +215,8 @@ namespace CameraGetPreviewFrame
|
|||
{
|
||||
Debug.WriteLine("InitializeCameraAsync");
|
||||
|
||||
await _mediaCaptureLifeLock.WaitAsync();
|
||||
|
||||
if (_mediaCapture == null)
|
||||
{
|
||||
// Attempt to get the back camera if one is available, but use any camera device if not
|
||||
|
@ -221,6 +225,7 @@ namespace CameraGetPreviewFrame
|
|||
if (cameraDevice == null)
|
||||
{
|
||||
Debug.WriteLine("No camera device found!");
|
||||
_mediaCaptureLifeLock.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -242,6 +247,10 @@ namespace CameraGetPreviewFrame
|
|||
{
|
||||
Debug.WriteLine("The app was denied access to the camera");
|
||||
}
|
||||
finally
|
||||
{
|
||||
_mediaCaptureLifeLock.Release();
|
||||
}
|
||||
|
||||
// If initialization succeeded, start the preview
|
||||
if (_isInitialized)
|
||||
|
@ -260,7 +269,7 @@ namespace CameraGetPreviewFrame
|
|||
// Only mirror the preview if the camera is on the front panel
|
||||
_mirroringPreview = (cameraDevice.EnclosureLocation.Panel == Windows.Devices.Enumeration.Panel.Front);
|
||||
}
|
||||
|
||||
|
||||
await StartPreviewAsync();
|
||||
|
||||
var picturesLibrary = await StorageLibrary.GetLibraryAsync(KnownLibraryId.Pictures);
|
||||
|
@ -268,6 +277,10 @@ namespace CameraGetPreviewFrame
|
|||
_captureFolder = picturesLibrary.SaveFolder ?? ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_mediaCaptureLifeLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -436,24 +449,33 @@ namespace CameraGetPreviewFrame
|
|||
/// <returns></returns>
|
||||
private async Task CleanupCameraAsync()
|
||||
{
|
||||
if (_isInitialized)
|
||||
await _mediaCaptureLifeLock.WaitAsync();
|
||||
|
||||
try
|
||||
{
|
||||
if (_isPreviewing)
|
||||
if (_isInitialized)
|
||||
{
|
||||
// The call to stop the preview is included here for completeness, but can be
|
||||
// safely removed if a call to MediaCapture.Dispose() is being made later,
|
||||
// as the preview will be automatically stopped at that point
|
||||
await StopPreviewAsync();
|
||||
if (_isPreviewing)
|
||||
{
|
||||
// The call to stop the preview is included here for completeness, but can be
|
||||
// safely removed if a call to MediaCapture.Dispose() is being made later,
|
||||
// as the preview will be automatically stopped at that point
|
||||
await StopPreviewAsync();
|
||||
}
|
||||
|
||||
_isInitialized = false;
|
||||
}
|
||||
|
||||
_isInitialized = false;
|
||||
if (_mediaCapture != null)
|
||||
{
|
||||
_mediaCapture.Failed -= MediaCapture_Failed;
|
||||
_mediaCapture.Dispose();
|
||||
_mediaCapture = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (_mediaCapture != null)
|
||||
finally
|
||||
{
|
||||
_mediaCapture.Failed -= MediaCapture_Failed;
|
||||
_mediaCapture.Dispose();
|
||||
_mediaCapture = null;
|
||||
_mediaCaptureLifeLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,13 @@
|
|||
#include "MainPage.xaml.h"
|
||||
#include "SampleConfiguration.h"
|
||||
|
||||
using namespace Concurrency;
|
||||
using namespace SDKTemplate;
|
||||
using namespace Windows::Devices;
|
||||
using namespace Windows::Devices::Enumeration;
|
||||
using namespace Windows::Media::Capture;
|
||||
using namespace Windows::Media::MediaProperties;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
|
||||
Platform::Array<Scenario>^ MainPage::scenariosInner = ref new Platform::Array<Scenario>
|
||||
{
|
||||
|
@ -21,3 +27,23 @@ Platform::Array<Scenario>^ MainPage::scenariosInner = ref new Platform::Array<Sc
|
|||
{ "Change preview and photo settings", "SDKTemplate.Scenario2_PhotoSettings" },
|
||||
{ "Match aspect ratios", "SDKTemplate.Scenario3_AspectRatio" }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Sets encoding properties on a camera stream. Ensures CaptureElement and preview stream are stopped before setting properties.
|
||||
/// </summary>
|
||||
task<void> MainPage::SetMediaStreamPropertiesAsync(MediaCapture^ mediaCapture, CaptureElement^ previewControl, MediaStreamType streamType, IMediaEncodingProperties^ encodingProperties)
|
||||
{
|
||||
// Stop preview and unlink the CaptureElement from the MediaCapture object
|
||||
return create_task(mediaCapture->StopPreviewAsync())
|
||||
.then([this, mediaCapture, previewControl, streamType, encodingProperties]()
|
||||
{
|
||||
previewControl->Source = nullptr;
|
||||
// Apply desired stream properties
|
||||
return create_task(mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(streamType, encodingProperties));
|
||||
}).then([this, mediaCapture, previewControl]() {
|
||||
// Recreate the CaptureElement pipeline and restart the preview
|
||||
previewControl->Source = mediaCapture;
|
||||
return create_task(mediaCapture->StartPreviewAsync());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ namespace SDKTemplate
|
|||
}
|
||||
}
|
||||
|
||||
Concurrency::task<void> SetMediaStreamPropertiesAsync(Windows::Media::Capture::MediaCapture^ mediaCapture, Windows::UI::Xaml::Controls::CaptureElement^ previewControl, Windows::Media::Capture::MediaStreamType streamType, Windows::Media::MediaProperties::IMediaEncodingProperties ^ encodingProperties);
|
||||
|
||||
private:
|
||||
static Platform::Array<Scenario>^ scenariosInner;
|
||||
};
|
||||
|
|
|
@ -142,7 +142,7 @@ void Scenario1_PreviewSettings::ComboBoxSettings_Changed(Platform::Object^ sende
|
|||
{
|
||||
auto selectedItem = static_cast<ComboBoxItem^>(static_cast<ComboBox^>(sender)->SelectedItem);
|
||||
auto encodingProperties = static_cast<IMediaEncodingProperties^>(selectedItem->Tag);
|
||||
create_task(_mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(MediaStreamType::VideoPreview, encodingProperties));
|
||||
create_task(_rootPage->SetMediaStreamPropertiesAsync(_mediaCapture.Get(), PreviewControl, MediaStreamType::VideoPreview, encodingProperties));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -192,7 +192,7 @@ void Scenario2_PhotoSettings::PreviewSettings_Changed(Platform::Object^ sender,
|
|||
{
|
||||
auto selectedItem = static_cast<ComboBoxItem^>(static_cast<ComboBox^>(sender)->SelectedItem);
|
||||
auto encodingProperties = static_cast<IMediaEncodingProperties^>(selectedItem->Tag);
|
||||
create_task(_mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(MediaStreamType::VideoPreview, encodingProperties));
|
||||
create_task(_rootPage->SetMediaStreamPropertiesAsync(_mediaCapture.Get(), PreviewControl, MediaStreamType::VideoPreview, encodingProperties));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -206,7 +206,7 @@ void Scenario2_PhotoSettings::PhotoSettings_Changed(Platform::Object^ sender, Wi
|
|||
{
|
||||
auto selectedItem = static_cast<ComboBoxItem^>(static_cast<ComboBox^>(sender)->SelectedItem);
|
||||
auto encodingProperties = static_cast<IMediaEncodingProperties^>(selectedItem->Tag);
|
||||
create_task(_mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(MediaStreamType::Photo, encodingProperties));
|
||||
create_task(_rootPage->SetMediaStreamPropertiesAsync(_mediaCapture.Get(), PreviewControl, MediaStreamType::Photo, encodingProperties));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ void Scenario3_AspectRatio::PreviewSettings_Changed(Platform::Object^ sender, Wi
|
|||
{
|
||||
auto selectedItem = static_cast<ComboBoxItem^>(static_cast<ComboBox^>(sender)->SelectedItem);
|
||||
auto encodingProperties = static_cast<IMediaEncodingProperties^>(selectedItem->Tag);
|
||||
create_task(_mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(MediaStreamType::VideoPreview, encodingProperties));
|
||||
create_task(_rootPage->SetMediaStreamPropertiesAsync(_mediaCapture.Get(), PreviewControl, MediaStreamType::VideoPreview, encodingProperties));
|
||||
|
||||
// The preview just changed, update the video combo box
|
||||
MatchPreviewAspectRatio();
|
||||
|
@ -227,7 +227,7 @@ void Scenario3_AspectRatio::VideoSettings_Changed(Platform::Object^ sender, Wind
|
|||
{
|
||||
auto selectedItem = static_cast<ComboBoxItem^>(static_cast<ComboBox^>(sender)->SelectedItem);
|
||||
auto encodingProperties = static_cast<IMediaEncodingProperties^>(selectedItem->Tag);
|
||||
create_task(_mediaCapture->VideoDeviceController->SetMediaStreamPropertiesAsync(MediaStreamType::VideoRecord, encodingProperties));
|
||||
create_task(_rootPage->SetMediaStreamPropertiesAsync(_mediaCapture.Get(), PreviewControl, MediaStreamType::VideoRecord, encodingProperties));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ using System.Collections.Generic;
|
|||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.Media.Capture;
|
||||
using Windows.UI.Core;
|
||||
using Windows.Media.MediaProperties;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
|
@ -50,6 +51,22 @@ namespace SDKTemplate
|
|||
public bool IsRecording { get; set; }
|
||||
public MediaCapture MediaCapture { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets encoding properties on a camera stream. Ensures CaptureElement and preview stream are stopped before setting properties.
|
||||
/// </summary>
|
||||
public async Task SetMediaStreamPropertiesAsync(MediaStreamType streamType, IMediaEncodingProperties encodingProperties)
|
||||
{
|
||||
// Stop preview and unlink the CaptureElement from the MediaCapture object
|
||||
await MediaCapture.StopPreviewAsync();
|
||||
_previewControl.Source = null;
|
||||
|
||||
// Apply desired stream properties
|
||||
await MediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
|
||||
// Recreate the CaptureElement pipeline and restart the preview
|
||||
_previewControl.Source = MediaCapture;
|
||||
await MediaCapture.StartPreviewAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the MediaCapture, starts preview.
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace SDKTemplate
|
|||
{
|
||||
var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
|
||||
var encodingProperties = (selectedItem.Tag as StreamResolution).EncodingProperties;
|
||||
await _previewer.MediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
await _previewer.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ namespace SDKTemplate
|
|||
{
|
||||
var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
|
||||
var encodingProperties = (selectedItem.Tag as StreamResolution).EncodingProperties;
|
||||
await _previewer.MediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
await _previewer.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace SDKTemplate
|
|||
{
|
||||
var selectedItem = (sender as ComboBox).SelectedItem as ComboBoxItem;
|
||||
var encodingProperties = (selectedItem.Tag as StreamResolution).EncodingProperties;
|
||||
await _previewer.MediaCapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
await _previewer.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, encodingProperties);
|
||||
|
||||
// The preview just changed, update the video combo box
|
||||
MatchPreviewAspectRatio();
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
if (cameraSettings.value == "")
|
||||
return;
|
||||
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, allProperties[cameraSettings.value]);
|
||||
setMediaStreamPropertiesAsync(mediaCapture, Capture.MediaStreamType.videoPreview, allProperties[cameraSettings.value]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
if (previewSettings.value == "")
|
||||
return;
|
||||
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, previewProperties[previewSettings.value]);
|
||||
setMediaStreamPropertiesAsync(mediaCapture, Capture.MediaStreamType.videoPreview, previewProperties[previewSettings.value]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,7 +114,7 @@
|
|||
if (photoSettings.value == "")
|
||||
return;
|
||||
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, photoProperties[photoSettings.value]);
|
||||
setMediaStreamPropertiesAsync(mediaCapture, Capture.MediaStreamType.videoPreview, photoProperties[photoSettings.value]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,7 @@
|
|||
if (previewSettings.value == "")
|
||||
return;
|
||||
console.log(previewSettings.value)
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoPreview, previewProperties[previewSettings.value]);
|
||||
setMediaStreamPropertiesAsync(mediaCapture, Capture.MediaStreamType.videoPreview, previewProperties[previewSettings.value]);
|
||||
|
||||
// The preview just changed, update the video combo box
|
||||
MatchPreviewAspectRatio();
|
||||
|
@ -128,7 +128,7 @@
|
|||
// The first element is just text
|
||||
if (videoSettings.value == "")
|
||||
return;
|
||||
mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(Capture.MediaStreamType.videoRecord, videoProperties[videoSettings.value]);
|
||||
setMediaStreamPropertiesAsync(mediaCapture, Capture.MediaStreamType.videoRecord, videoProperties[videoSettings.value]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,3 +61,23 @@ streamResolutionHelper.prototype.frameRate = function () {
|
|||
streamResolutionHelper.prototype.aspectRatio = function () {
|
||||
return (this.width() / this.height()).toFixed(2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets encoding properties on a camera stream. Ensures VideoElement and preview stream are stopped before setting properties.
|
||||
/// </summary>
|
||||
function setMediaStreamPropertiesAsync(mediaCapture, streamType, encodingProperties) {
|
||||
// Stop preview and unlink the VideoElement from the MediaCapture object
|
||||
var previewVidTag = document.getElementById("cameraPreview");
|
||||
previewVidTag.pause;
|
||||
previewVidTag.src = null;
|
||||
|
||||
// Apply desired stream properties
|
||||
return mediaCapture.videoDeviceController.setMediaStreamPropertiesAsync(streamType, encodingProperties)
|
||||
.then(function () {
|
||||
// Recreate pipeline and restart the preview
|
||||
var previewVidTag = document.getElementById("cameraPreview");
|
||||
var previewUrl = URL.createObjectURL(mediaCapture);
|
||||
previewVidTag.src = previewUrl;
|
||||
previewVidTag.play();
|
||||
});
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.15063.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>15</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.15063.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.15063.0" MaxVersionTested="10.0.16299.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -53,5 +52,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -52,5 +52,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -15,8 +15,12 @@ using namespace Windows::Graphics::Holographic;
|
|||
static const std::wstring s_VertexShaderFiles[DX::VertexShader_Max] =
|
||||
{
|
||||
L"ms-appx:///VertexShader.cso",
|
||||
L"ms-appx:///VprtVertexShader.cso",
|
||||
L"ms-appx:///VertexShaderTexture.cso",
|
||||
};
|
||||
|
||||
static const std::wstring s_VprtVertexShaderFiles[DX::VertexShader_Max] =
|
||||
{
|
||||
L"ms-appx:///VprtVertexShader.cso",
|
||||
L"ms-appx:///VprtVertexShaderTexture.cso"
|
||||
};
|
||||
|
||||
|
@ -393,7 +397,7 @@ Concurrency::task<void> DX::DeviceResources::LoadShaders()
|
|||
// Load vertex shaders and input layouts
|
||||
for (int i = 0; i < VertexShader_Max; i++)
|
||||
{
|
||||
Concurrency::task<std::vector<byte>> loadVSTask = DX::ReadDataAsync(s_VertexShaderFiles[i]);
|
||||
Concurrency::task<std::vector<byte>> loadVSTask = DX::ReadDataAsync(m_supportsVprt ? s_VprtVertexShaderFiles[i] : s_VertexShaderFiles[i]);
|
||||
|
||||
Concurrency::task<void> createVSTask = loadVSTask.then([this, i](const std::vector<byte>& fileData)
|
||||
{
|
||||
|
@ -407,7 +411,6 @@ Concurrency::task<void> DX::DeviceResources::LoadShaders()
|
|||
switch (i)
|
||||
{
|
||||
case VertexShader_Simple:
|
||||
case VertexShader_VPRT:
|
||||
{
|
||||
const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
|
||||
{
|
||||
|
@ -425,7 +428,6 @@ Concurrency::task<void> DX::DeviceResources::LoadShaders()
|
|||
}
|
||||
break;
|
||||
case VertexShader_Texture:
|
||||
case VertexShader_TextureVPRT:
|
||||
{
|
||||
const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
|
||||
{
|
||||
|
|
|
@ -9,9 +9,7 @@ namespace DX
|
|||
typedef enum
|
||||
{
|
||||
VertexShader_Simple = 0,
|
||||
VertexShader_VPRT,
|
||||
VertexShader_Texture,
|
||||
VertexShader_TextureVPRT,
|
||||
VertexShader_Max
|
||||
} VertexShaderIndex;
|
||||
|
||||
|
|
|
@ -220,8 +220,8 @@ void Button::DoCreateDeviceDependentResources()
|
|||
// target array index, thus avoiding any overhead that would be
|
||||
// incurred by setting the geometry shader stage.
|
||||
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture);
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(DX::VertexShader_Texture);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(DX::VertexShader_Texture);
|
||||
m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Texture);
|
||||
|
||||
D3D11_TEXTURE2D_DESC texDesc;
|
||||
|
|
|
@ -154,8 +154,8 @@ void Cursor::CreateDeviceDependentResources()
|
|||
// target array index, thus avoiding any overhead that would be
|
||||
// incurred by setting the geometry shader stage.
|
||||
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_TextureVPRT : DX::VertexShader_Texture);
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(DX::VertexShader_Texture);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(DX::VertexShader_Texture);
|
||||
m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Cursor);
|
||||
|
||||
D3D11_TEXTURE2D_DESC texDesc;
|
||||
|
|
|
@ -145,8 +145,8 @@ void Panel::DoCreateDeviceDependentResources()
|
|||
// target array index, thus avoiding any overhead that would be
|
||||
// incurred by setting the geometry shader stage.
|
||||
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple);
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(DX::VertexShader_Simple);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(DX::VertexShader_Simple);
|
||||
m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Simple);
|
||||
|
||||
if (!m_usingVprtShaders)
|
||||
|
|
|
@ -166,8 +166,8 @@ void SpinningCubeRenderer::CreateDeviceDependentResources()
|
|||
// target array index, thus avoiding any overhead that would be
|
||||
// incurred by setting the geometry shader stage.
|
||||
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(m_usingVprtShaders ? DX::VertexShader_VPRT : DX::VertexShader_Simple);
|
||||
m_vertexShader = m_deviceResources->GetVertexShader(DX::VertexShader_Simple);
|
||||
m_inputLayout = m_deviceResources->GetInputLayout(DX::VertexShader_Simple);
|
||||
m_pixelShader = m_deviceResources->GetPixelShader(DX::PixelShader_Simple);
|
||||
|
||||
if (!m_usingVprtShaders)
|
||||
|
|
|
@ -517,8 +517,8 @@ void HolographicMRCSampleMain::OnButtonInitTapped()
|
|||
{
|
||||
Concurrency::create_task(m_mediaCapture->InitializeAsync()).then([this]()
|
||||
{
|
||||
m_photoButton->SetEnabled(true);
|
||||
m_videoButton->SetEnabled(true);
|
||||
m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto());
|
||||
m_videoButton->SetEnabled(m_mediaCapture->CanToggleVideo());
|
||||
m_hologramButton->SetEnabled(true);
|
||||
m_sysAudioButton->SetEnabled(true);
|
||||
});
|
||||
|
@ -544,7 +544,7 @@ void HolographicMRCSampleMain::OnButtonVideoTapped()
|
|||
|
||||
m_initButton->SetEnabled(false);
|
||||
m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto());
|
||||
m_videoButton->SetEnabled(true);
|
||||
m_videoButton->SetEnabled(m_mediaCapture->CanToggleVideo());
|
||||
m_hologramButton->SetEnabled(true);
|
||||
m_sysAudioButton->SetEnabled(true);
|
||||
});
|
||||
|
@ -565,7 +565,7 @@ void HolographicMRCSampleMain::OnButtonVideoTapped()
|
|||
|
||||
m_initButton->SetEnabled(false);
|
||||
m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto());
|
||||
m_videoButton->SetEnabled(true);
|
||||
m_videoButton->SetEnabled(m_mediaCapture->CanToggleVideo());
|
||||
m_hologramButton->SetEnabled(false);
|
||||
m_sysAudioButton->SetEnabled(false);
|
||||
});
|
||||
|
@ -587,7 +587,7 @@ void HolographicMRCSampleMain::OnButtonPhotoTapped()
|
|||
{
|
||||
m_initButton->SetEnabled(false);
|
||||
m_photoButton->SetEnabled(m_mediaCapture->CanTakePhoto());
|
||||
m_videoButton->SetEnabled(true);
|
||||
m_videoButton->SetEnabled(m_mediaCapture->CanToggleVideo());
|
||||
m_hologramButton->SetEnabled(true);
|
||||
m_sysAudioButton->SetEnabled(true);
|
||||
});
|
||||
|
|
|
@ -49,7 +49,16 @@ Concurrency::task<void> MediaCaptureManager::InitializeAsync(IMFDXGIDeviceManage
|
|||
return Concurrency::create_task(m_mediaCapture->InitializeAsync(initSetting)).then([this]()
|
||||
{
|
||||
auto lock = m_lock.LockExclusive();
|
||||
m_currentState = Initialized;
|
||||
|
||||
if (m_mediaCapture->MediaCaptureSettings->AudioDeviceId && m_mediaCapture->MediaCaptureSettings->VideoDeviceId)
|
||||
{
|
||||
// MediaCapture is initialized with valid audio and video device.
|
||||
m_currentState = Initialized;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugString(L"MediaCapture is initialized without valid sources.\n");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -295,14 +304,21 @@ bool MediaCaptureManager::CanTakePhoto()
|
|||
|
||||
if (m_currentState == Initialized)
|
||||
{
|
||||
OutputDebugString(L"Can Take Photo\n");
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
OutputDebugString(L"Can NOT Take Photo\n");
|
||||
ret = false;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool MediaCaptureManager::CanToggleVideo()
|
||||
{
|
||||
auto lock = m_lock.LockShared();
|
||||
bool ret = false;
|
||||
|
||||
if (m_currentState == Initialized || m_currentState == Recording)
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ namespace HolographicMRCSample
|
|||
bool IsHologramEnabled() { auto lock = m_lock.LockShared(); return m_hologramEnabled; }
|
||||
bool IsSystemAudioEnabled() { auto lock = m_lock.LockShared(); return m_sysAudioEnabled; }
|
||||
bool CanTakePhoto();
|
||||
bool CanToggleVideo();
|
||||
|
||||
private:
|
||||
Microsoft::WRL::Wrappers::SRWLock m_lock;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ Specifically, this sample covers using the [Windows.UI.Input.Inking](http://msdn
|
|||
- Delete ink strokes
|
||||
- Recognize handwriting from ink strokes
|
||||
- Search for a string within recognition results
|
||||
- Obtain the InkPresenter for a canvas
|
||||
|
||||
**Note** Read the following instructions before using the app.
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\$(WMSJSProjectDirectory)\Microsoft.VisualStudio.$(WMSJSProject).props" />
|
||||
<PropertyGroup>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformVersion>10.0.17069.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.17069.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>$(VersionNumberMajor).$(VersionNumberMinor)</MinimumVisualStudioVersion>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
</PropertyGroup>
|
||||
|
@ -55,8 +55,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
<Content Include="css\scenario1.css" />
|
||||
<Content Include="css\scenario2.css" />
|
||||
<Content Include="default.html" />
|
||||
<Content Include="html\scenario1.html" />
|
||||
<Content Include="html\scenario2.html" />
|
||||
<Content Include="images\Erase.cur" />
|
||||
<Content Include="..\..\..\SharedContent\media\microsoft-sdk.png">
|
||||
<Link>images\microsoft-sdk.png</Link>
|
||||
|
@ -85,6 +87,7 @@
|
|||
</Content>
|
||||
<Content Include="js\sample-configuration.js" />
|
||||
<Content Include="js\scenario1.js" />
|
||||
<Content Include="js\scenario2.js" />
|
||||
<Content Include="..\..\..\SharedContent\js\Microsoft.WinJS\css\ui-dark.css">
|
||||
<Link>Microsoft.WinJS.4.0\css\ui-dark.css</Link>
|
||||
</Content>
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
Copyright (c) Microsoft Corporation. All rights reserved
|
||||
*/
|
||||
|
||||
{
|
||||
-ms-content-zooming: none;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
#scenarioHeader
|
||||
{
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#scenarioView
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#scenarioContent
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#canvasGroup {
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
top: 0px;
|
||||
bottom: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
z-index: 0;
|
||||
pen-action: none;
|
||||
}
|
||||
|
||||
canvas.surface {
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 2560px;
|
||||
height: 2560px;
|
||||
}
|
||||
|
||||
#ToolBar
|
||||
{
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
#Black .win-label
|
||||
{
|
||||
color: Black;
|
||||
}
|
||||
|
||||
#Blue .win-label
|
||||
{
|
||||
color: Blue;
|
||||
}
|
||||
|
||||
#Red .win-label
|
||||
{
|
||||
color: Red;
|
||||
}
|
||||
|
||||
#Green .win-label
|
||||
{
|
||||
color: Green;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<!--
|
||||
Copyright (c) Microsoft Corporation. All rights reserved
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<title></title>
|
||||
<link rel="stylesheet" href="/css/scenario2.css">
|
||||
<script src="/js/scenario2.js"></script>
|
||||
</head>
|
||||
|
||||
<body class="win-type-body">
|
||||
<div id="scenarioView">
|
||||
<div id="scenarioHeader">
|
||||
<h2 id="sampleHeader" class="win-type-subheader">Description:</h2>
|
||||
<div id="scenarioDescription">
|
||||
Demonstrates use of Ink Presenter APIs.
|
||||
</div>
|
||||
</div>
|
||||
<div id="scenarioContent">
|
||||
<div id="canvasGroup">
|
||||
<canvas id="InkCanvas" class="surface"></canvas>
|
||||
</div>
|
||||
|
||||
<!-- This toolbar is displayed across the bottom of the screen.
|
||||
The color buttons have IDs which are the names of colors; the ID of each one is fed directly into the strokeStyle of the corresponding canvas.-->
|
||||
|
||||
<div id="ToolBar" data-win-control="WinJS.UI.ToolBar">
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'Undo', label:'Undo', icon:'undo', onclick:Ink.undo, section:'primary', tooltip:'Undo', priority:2}" class="win-button"></button>
|
||||
<hr data-win-control="WinJS.UI.Command" data-win-options="{type:'separator'}">
|
||||
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'InkColors', label:'Color', icon:'fontcolor', section:'primary', type:'flyout',flyout:'InkColorFlyout', tooltip:'Choose ink color', priority:2}" class="win-button"></button>
|
||||
<hr data-win-control="WinJS.UI.Command" data-win-options="{type:'separator'}">
|
||||
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'ModeErase', label:'Erase', icon:'dockleft', onclick:Ink.eraseMode, section:'primary', tooltip:'Switch pen tip to eraser mode', priority:2}" class="win-button"></button>
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'Pencil', label:'Pencil', icon:'edit', onclick:Ink.pencilMode, section:'primary', tooltip:'Switch pen tip to pencil mode', priority:2}" class="win-button"></button>
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'Highlighter', label:'Highlighter', icon:'highlight', onclick:Ink.highlighterMode, section:'primary', tooltip:'Switch to highlighter mode', priority:2}" class="win-button"></button>
|
||||
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'Load',label:'Load',onclick:Ink.load,section:'secondary'}" class="win-button"></button>
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'Save',label:'Save',onclick:Ink.save,section:'secondary'}" class="win-button"></button>
|
||||
<button data-win-control="WinJS.UI.Command" data-win-options="{id:'Clear',label:'Clear',onclick:Ink.clear,section:'secondary'}" class="win-button"></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -6,7 +6,8 @@
|
|||
var sampleTitle = "Ink sample";
|
||||
|
||||
var scenarios = [
|
||||
{ url: "/html/scenario1.html", title: "Scenario 1" }
|
||||
{ url: "/html/scenario1.html", title: "Scenario 1" },
|
||||
{ url: "/html/scenario2.html", title: "Scenario 2" }
|
||||
];
|
||||
|
||||
WinJS.Namespace.define("SdkSample", {
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
//// Copyright (c) Microsoft Corporation. All rights reserved
|
||||
|
||||
// Sample app demonstrating the use of InkPresenter APIs.
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
// abbreviations
|
||||
var Inking = Windows.UI.Input.Inking;
|
||||
var InkInputProcessingMode = Inking.InkInputProcessingMode;
|
||||
|
||||
function displayStatus(message) {
|
||||
WinJS.log && WinJS.log(message, "sample", "status");
|
||||
}
|
||||
|
||||
function displayError(message) {
|
||||
WinJS.log && WinJS.log(message, "sample", "error");
|
||||
}
|
||||
|
||||
var STROKES_FILENAME = "strokes.txt";
|
||||
|
||||
var inkCanvas;
|
||||
var inkContext;
|
||||
var inkPresenter;
|
||||
var inkColor;
|
||||
|
||||
// Undo the last stroke by removing it from the stroke container.
|
||||
function undo() {
|
||||
var strokeContainer = inkPresenter.strokeContainer;
|
||||
var strokes = strokeContainer.getStrokes();
|
||||
|
||||
// If there are no strokes, there's nothing to undo.
|
||||
if (strokes.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the last stroke and delete it.
|
||||
strokes[strokes.length - 1].selected = true;
|
||||
strokeContainer.deleteSelected();
|
||||
}
|
||||
|
||||
// Switch pen tip to eraser mode.
|
||||
function eraseMode() {
|
||||
inkPresenter.inputProcessingConfiguration.mode = InkInputProcessingMode.erasing;
|
||||
}
|
||||
|
||||
// Switch pen tip to pencil mode.
|
||||
function pencilMode() {
|
||||
var drawingAttributes = new Inking.InkDrawingAttributes.createForPencil();
|
||||
drawingAttributes.ignorePressure = false;
|
||||
drawingAttributes.fitToCurve = true;
|
||||
drawingAttributes.color = inkColor;
|
||||
drawingAttributes.size = { width: 3, height: 3 };
|
||||
inkPresenter.updateDefaultDrawingAttributes(drawingAttributes);
|
||||
inkPresenter.inputProcessingConfiguration.mode = InkInputProcessingMode.inking
|
||||
}
|
||||
|
||||
// Switch pen tip to highlighter mode.
|
||||
function highlighterMode() {
|
||||
var drawingAttributes = new Inking.InkDrawingAttributes();
|
||||
drawingAttributes.ignorePressure = true;
|
||||
drawingAttributes.fitToCurve = true;
|
||||
drawingAttributes.drawAsHighlighter = true;
|
||||
drawingAttributes.penTip = Inking.PenTipShape.rectangle;
|
||||
drawingAttributes.size = { width: 10, height: 10 };
|
||||
drawingAttributes.color = inkColor;
|
||||
inkPresenter.updateDefaultDrawingAttributes(drawingAttributes);
|
||||
inkPresenter.inputProcessingConfiguration.mode = InkInputProcessingMode.inking;
|
||||
}
|
||||
|
||||
// Load the strokes from the file into the stroke container.
|
||||
function load() {
|
||||
var strokeContainer = inkPresenter.strokeContainer;
|
||||
var loadStream;
|
||||
|
||||
var localAppDataFolder = Windows.Storage.ApplicationData.current.localFolder;
|
||||
localAppDataFolder.getFileAsync(STROKES_FILENAME).then(function (file) {
|
||||
// Open the file
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.read);
|
||||
}).then(function (stream) {
|
||||
// Load the strokes into the stroke container.
|
||||
loadStream = stream;
|
||||
return strokeContainer.loadAsync(stream)
|
||||
}).done(function () {
|
||||
// Input stream is IClosable interface and requires explicit close.
|
||||
loadStream.close();
|
||||
},
|
||||
function () {
|
||||
displayError("Load Failed. First save a file before loading one.");
|
||||
});
|
||||
}
|
||||
|
||||
// Save the strokes from the stroke container to a file.
|
||||
function save() {
|
||||
var strokeContainer = inkPresenter.strokeContainer;
|
||||
var saveStream;
|
||||
|
||||
// Create or replace existing file.
|
||||
var localAppDataFolder = Windows.Storage.ApplicationData.current.localFolder;
|
||||
localAppDataFolder.createFileAsync(STROKES_FILENAME, Windows.Storage.CreationCollisionOption.replaceExisting).then(function (file) {
|
||||
// Open the file
|
||||
return file.openAsync(Windows.Storage.FileAccessMode.readWrite);
|
||||
}).then(function (stream) {
|
||||
// Save the strokes to the file.
|
||||
saveStream = stream;
|
||||
return strokeContainer.saveAsync(stream);
|
||||
}).then(function () {
|
||||
return saveStream.flushAsync();
|
||||
}).done(function () {
|
||||
// Output stream is IClosable interface and requires explicit close.
|
||||
saveStream.close();
|
||||
});
|
||||
}
|
||||
|
||||
// Clear the stroke container and display text.
|
||||
function clear() {
|
||||
inkPresenter.strokeContainer.clear();
|
||||
|
||||
displayStatus("");
|
||||
displayError("");
|
||||
}
|
||||
|
||||
// A button handler which fetches the ID from the button, which should be a color name.
|
||||
// Set the ink presenter drawing attributes' color to that color.
|
||||
function setInkColor(evt) {
|
||||
switch (evt.currentTarget.id) {
|
||||
case "Black":
|
||||
inkColor = Windows.UI.Colors.black;
|
||||
break;
|
||||
case "Blue":
|
||||
inkColor = Windows.UI.Colors.blue;
|
||||
break;
|
||||
case "Red":
|
||||
inkColor = Windows.UI.Colors.red;
|
||||
break;
|
||||
case "Green":
|
||||
inkColor = Windows.UI.Colors.green;
|
||||
break;
|
||||
}
|
||||
|
||||
var drawingAttributes = inkPresenter.copyDefaultDrawingAttributes();
|
||||
drawingAttributes.color = inkColor;
|
||||
inkPresenter.updateDefaultDrawingAttributes(drawingAttributes);
|
||||
}
|
||||
|
||||
function inkInitialize() {
|
||||
// Utility to fetch elements by ID.
|
||||
function id(elementId) {
|
||||
return document.getElementById(elementId);
|
||||
}
|
||||
|
||||
WinJS.UI.processAll().then(
|
||||
function () {
|
||||
id("Black").addEventListener("click", setInkColor);
|
||||
id("Blue").addEventListener("click", setInkColor);
|
||||
id("Red").addEventListener("click", setInkColor);
|
||||
id("Green").addEventListener("click", setInkColor);
|
||||
|
||||
inkCanvas = id("InkCanvas");
|
||||
inkCanvas.setAttribute("width", inkCanvas.offsetWidth);
|
||||
inkCanvas.setAttribute("height", inkCanvas.offsetHeight);
|
||||
|
||||
// Get the ms-ink context
|
||||
inkContext = inkCanvas.getContext("ms-ink");
|
||||
inkPresenter = inkContext.msInkPresenter;
|
||||
|
||||
inkPresenter.inputDeviceTypes =
|
||||
Windows.UI.Core.CoreInputDeviceTypes.mouse |
|
||||
Windows.UI.Core.CoreInputDeviceTypes.pen;
|
||||
|
||||
// Set the default drawing attributes.
|
||||
inkColor = Windows.UI.Colors.black;
|
||||
pencilMode();
|
||||
}
|
||||
).done(null, function (e) {
|
||||
displayError("inkInitialize " + e.toString());
|
||||
});
|
||||
}
|
||||
|
||||
// Tag the event handlers of the ToolBar so that they can be used in a declarative context.
|
||||
// For security reasons WinJS.UI.processAll and WinJS.Binding.processAll (and related) functions allow only
|
||||
// functions that are marked as being usable declaratively to be invoked through declarative processing.
|
||||
WinJS.UI.eventHandler(undo);
|
||||
WinJS.UI.eventHandler(eraseMode);
|
||||
WinJS.UI.eventHandler(pencilMode);
|
||||
WinJS.UI.eventHandler(highlighterMode);
|
||||
WinJS.UI.eventHandler(load);
|
||||
WinJS.UI.eventHandler(save);
|
||||
WinJS.UI.eventHandler(clear);
|
||||
WinJS.Namespace.define("Ink", {
|
||||
undo: undo,
|
||||
eraseMode: eraseMode,
|
||||
pencilMode: pencilMode,
|
||||
highlighterMode: highlighterMode,
|
||||
load: load,
|
||||
save: save,
|
||||
clear: clear,
|
||||
});
|
||||
|
||||
var page = WinJS.UI.Pages.define("/html/scenario2.html", {
|
||||
ready: function (element, options) {
|
||||
inkInitialize();
|
||||
}
|
||||
});
|
||||
})();
|
|
@ -19,7 +19,7 @@
|
|||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.10240.0" MaxVersionTested="10.0.16299.0" />
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17069.0" MaxVersionTested="10.0.17069.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ Scenario2::Scenario2()
|
|||
|
||||
mapIconStreamReference = RandomAccessStreamReference::CreateFromUri(ref new Uri("ms-appx:///Assets/MapPin.png"));
|
||||
mapBillboardStreamReference = RandomAccessStreamReference::CreateFromUri(ref new Uri("ms-appx:///Assets/billboard.jpg"));
|
||||
mapModelStreamReference = RandomAccessStreamReference::CreateFromUri(ref new Uri("ms-appx:///Assets/ConkerAfro.3mf"));
|
||||
mapModelStreamReference = RandomAccessStreamReference::CreateFromUri(ref new Uri("ms-appx:///Assets/box.3mf"));
|
||||
}
|
||||
|
||||
void Scenario2::MyMap_Loaded(Object^ sender, RoutedEventArgs^ e)
|
||||
|
|
|
@ -281,7 +281,7 @@
|
|||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\shared\box.3mf">
|
||||
<Link>Assets\ConkerAfro.3mf</Link>
|
||||
<Link>Assets\box.3mf</Link>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="..\shared\MyCustomStates.json">
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -32,12 +32,18 @@
|
|||
|
||||
<StackPanel x:Name="RenderingPanel" Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock VerticalAlignment="center">View page</TextBlock>
|
||||
<TextBox x:Name="PageNumberBox" InputScope="Number" Width="30" Text="1" TextAlignment="Right" Margin="5,0,5,0"/>
|
||||
<TextBlock Name="ViewPageLabel" VerticalAlignment="center">View page</TextBlock>
|
||||
<!-- Always give a TextBox a name that's accessible to a screen reader. In this case,
|
||||
reference the labeling TextBlock to have the accessible name set on the TextBox. -->
|
||||
<TextBox x:Name="PageNumberBox" InputScope="Number" Width="30" Text="1" TextAlignment="Right" Margin="5,0,5,0"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=ViewPageLabel}"/>
|
||||
<TextBlock VerticalAlignment="Center">of <Run x:Name="PageCountText"/>.</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<ComboBox x:Name="Options" SelectedIndex="0">
|
||||
<!-- Always give a ComboBox a name that's accessible to a screen reader. Given that there's no labeling
|
||||
TextBlock to reference, explicitly set the accessible name on the ComboBox. A shipping app would
|
||||
localize this name. -->
|
||||
<ComboBox x:Name="Options" AutomationProperties.Name="View page size" SelectedIndex="0">
|
||||
<ComboBoxItem>Actual size</ComboBoxItem>
|
||||
<ComboBoxItem>Half size on beige background</ComboBoxItem>
|
||||
<ComboBoxItem>Crop to center of page</ComboBoxItem>
|
||||
|
@ -45,7 +51,9 @@
|
|||
<Button Click="{x:Bind ViewPage}" Content="View" Margin="10,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<Image x:Name="Output" Stretch="None" Margin="0,10,0,0"/>
|
||||
<!-- Always give an Image a name that's accessible to screen reader, (unless the Image is purely decorative.)
|
||||
A shipping app would localize this name.-->
|
||||
<Image x:Name="Output" AutomationProperties.Name="PDF document content" Stretch="None" Margin="0,10,0,0"/>
|
||||
</StackPanel>
|
||||
<ProgressRing x:Name="ProgressControl" Height="50" Width="50" IsActive="True" Visibility="Collapsed" Margin="0,10,0,0"/>
|
||||
</StackPanel>
|
||||
|
|
|
@ -55,11 +55,10 @@
|
|||
<RichTextBlockOverflow x:Name="ContinuationPageLinkedContainer" Grid.Row="3" Grid.ColumnSpan="2"/>
|
||||
<Image Source="ms-appx:///Assets/print_1.png" x:Name="ScenarioImage" HorizontalAlignment="Center" Grid.Row="2" Grid.Column="1" Margin="10"/>
|
||||
|
||||
<StackPanel x:Name="Footer" Grid.Row="4" Grid.Column="0" VerticalAlignment="Top" Visibility="Collapsed">
|
||||
<Image Source="ms-appx:///Assets/splash-sdk.png" HorizontalAlignment="Left" Stretch="None"/>
|
||||
<RichTextBlock Foreground="Black" FontSize="16" TextAlignment="Left" FontFamily="Segoe UI">
|
||||
<Paragraph>Copyright © Microsoft Corporation. All rights reserved.</Paragraph>
|
||||
</RichTextBlock>
|
||||
<StackPanel x:Name="Footer" Grid.Row="4" Grid.ColumnSpan="2">
|
||||
<TextBlock Foreground="Black" FontSize="16" TextAlignment="Left" FontFamily="Segoe UI">
|
||||
Copyright © Microsoft Corporation. All rights reserved.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -209,7 +209,8 @@ RichTextBlockOverflow^ PrintHelper::AddOnePrintPreviewPage(RichTextBlockOverflow
|
|||
{
|
||||
// If this is the first page add the specific scenario content
|
||||
page = FirstPage;
|
||||
//Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
|
||||
// Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
StackPanel^ footer = safe_cast<StackPanel^>(page->FindName("Footer"));
|
||||
footer->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
|
||||
}
|
||||
|
@ -248,6 +249,7 @@ RichTextBlockOverflow^ PrintHelper::AddOnePrintPreviewPage(RichTextBlockOverflow
|
|||
{
|
||||
StackPanel^ footer = safe_cast<StackPanel^>(page->FindName("Footer"));
|
||||
footer->Visibility = Windows::UI::Xaml::Visibility::Visible;
|
||||
PrintCanvas->UpdateLayout();
|
||||
}
|
||||
|
||||
// Add the page to the page preview collection
|
||||
|
|
|
@ -103,7 +103,8 @@ RichTextBlockOverflow^ PreviewOptionsPrintHelper::AddOnePrintPage(RichTextBlockO
|
|||
{
|
||||
// If this is the first page add the specific scenario content
|
||||
page = FirstPage;
|
||||
//Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
|
||||
// Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
StackPanel^ footer = safe_cast<StackPanel^>(page->FindName("Footer"));
|
||||
footer->Visibility = Visibility::Collapsed;
|
||||
}
|
||||
|
@ -142,6 +143,7 @@ RichTextBlockOverflow^ PreviewOptionsPrintHelper::AddOnePrintPage(RichTextBlockO
|
|||
{
|
||||
StackPanel^ footer = safe_cast<StackPanel^>(page->FindName("Footer"));
|
||||
footer->Visibility = Visibility::Visible;
|
||||
PrintCanvas->UpdateLayout();
|
||||
}
|
||||
|
||||
// Add the page to the page print collection
|
||||
|
|
|
@ -65,11 +65,10 @@
|
|||
<RichTextBlockOverflow x:Name="ContinuationPageLinkedContainer" Grid.Row="3" Grid.ColumnSpan="2"/>
|
||||
<Image Source="ms-appx:///Assets/print_1.png" x:Name="ScenarioImage" HorizontalAlignment="Center" Grid.Row="2" Grid.Column="1" Margin="10"/>
|
||||
|
||||
<StackPanel x:Name="Footer" Grid.Row="4" Grid.Column="0" VerticalAlignment="Top" Visibility="Collapsed">
|
||||
<Image Source="ms-appx:///Assets/splash-sdk.png" HorizontalAlignment="Left" Stretch="None"/>
|
||||
<RichTextBlock Foreground="Black" FontSize="16" TextAlignment="Left" FontFamily="Segoe UI">
|
||||
<Paragraph>Copyright © Microsoft Corporation. All rights reserved.</Paragraph>
|
||||
</RichTextBlock>
|
||||
<StackPanel x:Name="Footer" Grid.Row="4" Grid.ColumnSpan="2">
|
||||
<TextBlock Foreground="Black" FontSize="16" TextAlignment="Left" FontFamily="Segoe UI">
|
||||
Copyright © Microsoft Corporation. All rights reserved.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -273,7 +273,8 @@ namespace PrintSample
|
|||
{
|
||||
// If this is the first page add the specific scenario content
|
||||
page = firstPage;
|
||||
//Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
|
||||
// Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
StackPanel footer = (StackPanel)page.FindName("Footer");
|
||||
footer.Visibility = Windows.UI.Xaml.Visibility.Collapsed;
|
||||
}
|
||||
|
@ -312,6 +313,7 @@ namespace PrintSample
|
|||
{
|
||||
StackPanel footer = (StackPanel)page.FindName("Footer");
|
||||
footer.Visibility = Windows.UI.Xaml.Visibility.Visible;
|
||||
PrintCanvas.UpdateLayout();
|
||||
}
|
||||
|
||||
// Add the page to the page preview collection
|
||||
|
|
|
@ -144,7 +144,8 @@ namespace PrintSample
|
|||
{
|
||||
// If this is the first page add the specific scenario content
|
||||
page = firstPage;
|
||||
//Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
|
||||
// Hide footer since we don't know yet if it will be displayed (this might not be the last page) - wait for layout
|
||||
StackPanel footer = (StackPanel)page.FindName("Footer");
|
||||
footer.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
@ -183,6 +184,7 @@ namespace PrintSample
|
|||
{
|
||||
StackPanel footer = (StackPanel)page.FindName("Footer");
|
||||
footer.Visibility = Visibility.Visible;
|
||||
PrintCanvas.UpdateLayout();
|
||||
}
|
||||
|
||||
// Add the page to the print page collection
|
||||
|
|
|
@ -49,65 +49,81 @@
|
|||
|
||||
<ScrollViewer Grid.Row="1">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<GridView IsItemClickEnabled="False" SelectionMode="None">
|
||||
|
||||
<!-- Provide an AutomationProperties.Name for a GridView to a screen reader. A shipping app would localize this. -->
|
||||
<GridView AutomationProperties.Name="Radial Controller Events Hookup" IsItemClickEnabled="False" SelectionMode="None">
|
||||
<GridView.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<ItemsWrapGrid Orientation="Horizontal" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
|
||||
</ItemsPanelTemplate>
|
||||
</GridView.ItemsPanel>
|
||||
|
||||
<StackPanel Style="{StaticResource ButtonGroup}">
|
||||
<Image Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item0.png"/>
|
||||
<!-- All shipping GridView items must have helpful, concise, localized and unique accessible names, so that
|
||||
a screen reader can make your customers aware of their purpose. Given that this sample defines each item
|
||||
here, (are the items are not databound,) set the accessible names on each item explicitly. This sample
|
||||
contains placeholder text which would be replaced with appropriate localized text by a shipping app. -->
|
||||
|
||||
<!-- All shipping Images, Sliders, and ToggleSwitches must have helpful, concise, localized and unique
|
||||
accessible names, so that a screen reader can make your customers aware of their purpose. This sample
|
||||
contains placeholder text which would be replaced with appropriate localized text by a shipping app. -->
|
||||
|
||||
<StackPanel AutomationProperties.Name="Item 0 details" Style="{StaticResource ButtonGroup}">
|
||||
<Image AutomationProperties.Name="Item 0 Image accessible name" Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item0.png"/>
|
||||
<Button Content="Add Item 0" Click="AddItem" CommandParameter="0"/>
|
||||
<Button Content="Select Item 0" Click="SelectItem" CommandParameter="0"/>
|
||||
<Button Content="Remove Item 0" Click="RemoveItem" CommandParameter="0"/>
|
||||
<Slider x:Name="slider0" />
|
||||
<ToggleSwitch x:Name="toggle0" />
|
||||
<Slider AutomationProperties.Name="Item 0 Slider accessible name" x:Name="slider0" />
|
||||
<ToggleSwitch x:Name="toggle0" AutomationProperties.Name="Item 0 ToggleSwitch accessible name" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Style="{StaticResource ButtonGroup}">
|
||||
<Image Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item1.png"/>
|
||||
<StackPanel AutomationProperties.Name="Item 1 details" Style="{StaticResource ButtonGroup}">
|
||||
<Image AutomationProperties.Name="Item 1 Image accessible name" Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item1.png"/>
|
||||
<Button Content="Add Item 1" Click="AddItem" CommandParameter="1"/>
|
||||
<Button Content="Select Item 1" Click="SelectItem" CommandParameter="1"/>
|
||||
<Button Content="Remove Item 1" Click="RemoveItem" CommandParameter="1"/>
|
||||
<Slider x:Name="slider1" />
|
||||
<ToggleSwitch x:Name="toggle1" />
|
||||
<Slider AutomationProperties.Name="Item 1 Slider accessible name" x:Name="slider1" />
|
||||
<ToggleSwitch x:Name="toggle1" AutomationProperties.Name="Item 1 ToggleSwitch accessible name" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Style="{StaticResource ButtonGroup}">
|
||||
<Image Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item2.png"/>
|
||||
<StackPanel AutomationProperties.Name="Item 2 details" Style="{StaticResource ButtonGroup}">
|
||||
<Image AutomationProperties.Name="Item 2 Image accessible name" Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item2.png"/>
|
||||
<Button Content="Add Item 2" Click="AddItem" CommandParameter="2"/>
|
||||
<Button Content="Select Item 2" Click="SelectItem" CommandParameter="2"/>
|
||||
<Button Content="Remove Item 2" Click="RemoveItem" CommandParameter="2"/>
|
||||
<Slider x:Name="slider2" />
|
||||
<ToggleSwitch x:Name="toggle2" />
|
||||
<Slider AutomationProperties.Name="Item 2 Slider accessible name" x:Name="slider2" />
|
||||
<ToggleSwitch x:Name="toggle2" AutomationProperties.Name="Item 2 ToggleSwitch accessible name" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Style="{StaticResource ButtonGroup}">
|
||||
<Image Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item3.png"/>
|
||||
<StackPanel AutomationProperties.Name="Item 3 details" Style="{StaticResource ButtonGroup}">
|
||||
<Image AutomationProperties.Name="Item 3 Image accessible name" Height="64" Width="64" HorizontalAlignment="Left" Source="Assets\Item3.png"/>
|
||||
<Button Content="Add Item 3" Click="AddItem" CommandParameter="3"/>
|
||||
<Button Content="Select Item 3" Click="SelectItem" CommandParameter="3"/>
|
||||
<Button Content="Remove Item 3" Click="RemoveItem" CommandParameter="3"/>
|
||||
<Slider x:Name="slider3" />
|
||||
<ToggleSwitch x:Name="toggle3" />
|
||||
<Slider AutomationProperties.Name="Item 3 Slider accessible name" x:Name="slider3" />
|
||||
<ToggleSwitch x:Name="toggle3" AutomationProperties.Name="Item 3 ToggleSwitch accessible name" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Style="{StaticResource ButtonGroup}">
|
||||
<TextBlock Height="64" Width="64" HorizontalAlignment="Left" FontFamily="Segoe UI Emoji" FontSize="45" Text="❤"/>
|
||||
<!-- There's no guarantee that a symbolic character from some font will be pronounced by a screen reader
|
||||
in a helpful way. So set helpful, concise, localized and uniqueaccessible names on the TextBlocks
|
||||
so that a screen reader can make your customers aware of their purpose. This sample contains
|
||||
placeholder text which would be replaced with appropriate localized text by a shipping app. -->
|
||||
|
||||
<StackPanel AutomationProperties.Name="Item 4 details" Style="{StaticResource ButtonGroup}">
|
||||
<TextBlock AutomationProperties.Name="Item 4 TextBlock accessible name" Height="64" Width="64" HorizontalAlignment="Left" FontFamily="Segoe UI Emoji" FontSize="45" Text="❤"/>
|
||||
<Button Content="Add Item 4" Click="AddItem" CommandParameter="4"/>
|
||||
<Button Content="Select Item 4" Click="SelectItem" CommandParameter="4"/>
|
||||
<Button Content="Remove Item 4" Click="RemoveItem" CommandParameter="4"/>
|
||||
<Slider x:Name="slider4" />
|
||||
<ToggleSwitch x:Name="toggle4" />
|
||||
<Slider AutomationProperties.Name="Item 4 Slider accessible name" x:Name="slider4" />
|
||||
<ToggleSwitch x:Name="toggle4" AutomationProperties.Name="Item 4 ToggleSwitch accessible name" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Style="{StaticResource ButtonGroup}">
|
||||
<TextBlock Height="64" Width="64" HorizontalAlignment="Left" FontFamily="Assets\fontawesome-webfont.ttf#FontAwesome" FontSize="57" Text=""/>
|
||||
<StackPanel AutomationProperties.Name="Item 5 details" Style="{StaticResource ButtonGroup}">
|
||||
<TextBlock AutomationProperties.Name="Item 5 TextBlock accessible name" Height="64" Width="64" HorizontalAlignment="Left" FontFamily="Assets\fontawesome-webfont.ttf#FontAwesome" FontSize="57" Text=""/>
|
||||
<Button Content="Add Item 5" Click="AddItem" CommandParameter="5"/>
|
||||
<Button Content="Select Item 5" Click="SelectItem" CommandParameter="5"/>
|
||||
<Button Content="Remove Item 5" Click="RemoveItem" CommandParameter="5"/>
|
||||
<Slider x:Name="slider5" />
|
||||
<ToggleSwitch x:Name="toggle5" />
|
||||
<Slider AutomationProperties.Name="Item 5 Slider accessible name" x:Name="slider5" />
|
||||
<ToggleSwitch x:Name="toggle5" AutomationProperties.Name="Item 5 ToggleSwitch accessible name" />
|
||||
</StackPanel>
|
||||
</GridView>
|
||||
|
||||
|
@ -121,7 +137,7 @@
|
|||
<StackPanel Style="{StaticResource PaddedPanel}">
|
||||
<TextBlock FontSize="20">Log</TextBlock>
|
||||
<ScrollViewer x:Name="logViewer" Grid.Column="0" MaxHeight="300" Padding="0,0,20,0">
|
||||
<TextBlock x:Name="log" SizeChanged="OnLogSizeChanged"/>
|
||||
<TextBlock x:Name="log" SizeChanged="OnLogSizeChanged" />
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26228.4
|
||||
|
@ -39,5 +38,3 @@ Global
|
|||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
|
||||
|
|
|
@ -36,47 +36,58 @@
|
|||
<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Friendly Name" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<TextBox x:Name="FriendlyName" Text="My Virtual Smart Card" HorizontalAlignment="Left"/>
|
||||
<TextBlock Name="FriendlyNameLabel" Text="Friendly Name" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<!-- Always give a TextBox a name that's accessible to a screen reader. In this case,
|
||||
reference the labeling TextBlock to have the accessible name set on the TextBox. -->
|
||||
<TextBox x:Name="FriendlyName" Text="My Virtual Smart Card" HorizontalAlignment="Left"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=FriendlyNameLabel}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Minimum PIN length" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<TextBox x:Name="PinMinLength" InputScope="Number" Text="8" HorizontalAlignment="Left"/>
|
||||
<TextBlock Name="PinMinLengthLabel" Text="Minimum PIN length" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<TextBox x:Name="PinMinLength" InputScope="Number" Text="8" HorizontalAlignment="Left"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=PinMinLengthLabel}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Maximum PIN length" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<TextBox x:Name="PinMaxLength" InputScope="Number" Text="127" HorizontalAlignment="Left"/>
|
||||
<TextBlock Name="PinMaxLengthLabel" Text="Maximum PIN length" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<TextBox x:Name="PinMaxLength" InputScope="Number" Text="127" HorizontalAlignment="Left"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=PinMaxLengthLabel}" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Character Set" HorizontalAlignment="Left" />
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Uppercase" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinUppercase" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<TextBlock Name="PinUppercaseLabel" Text="Uppercase" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<!-- Always give a ComboBox a name that's accessible to a screen reader. In this case,
|
||||
reference the labeling TextBlock to have the accessible name set on the ComboBox. -->
|
||||
<ComboBox x:Name="PinUppercase" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=PinUppercaseLabel}">
|
||||
<x:String>Disallowed</x:String>
|
||||
<x:String>Allowed</x:String>
|
||||
<x:String>Require At Least One</x:String>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Lowercase" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinLowercase" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<TextBlock Name="PinLowercaseLabel" Text="Lowercase" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinLowercase" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=PinLowercaseLabel}">
|
||||
<x:String>Disallowed</x:String>
|
||||
<x:String>Allowed</x:String>
|
||||
<x:String>Require At Least One</x:String>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Digits" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinDigits" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<TextBlock Name="PinDigitsLabel" Text="Digits" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinDigits" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=PinDigitsLabel}">
|
||||
<x:String>Disallowed</x:String>
|
||||
<x:String>Allowed</x:String>
|
||||
<x:String>Require At Least One</x:String>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Special" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinSpecial" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center">
|
||||
<TextBlock Name="PinSpecialLabel" Text="Special" TextWrapping="Wrap" HorizontalAlignment="Left" VerticalAlignment="Center" Width="85"/>
|
||||
<ComboBox x:Name="PinSpecial" SelectedIndex="1" HorizontalAlignment="Left" VerticalAlignment="Center"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=PinSpecialLabel}">
|
||||
<x:String>Disallowed</x:String>
|
||||
<x:String>Allowed</x:String>
|
||||
<x:String>Require At Least One</x:String>
|
||||
|
|
|
@ -36,20 +36,27 @@
|
|||
<Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
|
||||
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
|
||||
</Grid>
|
||||
<Button Content="Play" Click="PlayButton_Click" HorizontalAlignment="Left" Margin="93,273,0,335" Width="47"/>
|
||||
<Button Content="Stop" Click="StopButton_Click" HorizontalAlignment="Left" Margin="189,273,0,335" Width="50"/>
|
||||
<Slider x:Name="RadiusSlider" HorizontalAlignment="Left" Margin="9,213,0,0" VerticalAlignment="Top" Width="152" Maximum="10" LargeChange="1" Value="1" ValueChanged="RadiusSlider_ValueChanged" SmallChange="0.1" TickFrequency="1" StepFrequency="0.1"/>
|
||||
<ComboBox x:Name="EnvironmentComboBox" HorizontalAlignment="Left" Margin="9,100,0,0" VerticalAlignment="Top" Width="160" IsDropDownOpen="True" SelectionChanged="EnvironmentComboBox_SelectionChanged">
|
||||
<!-- Always give ComboBoxes and Sliders names that are accessible to a screen reader.
|
||||
In this case, reference the labeling TextBlocks to have the accessible names set
|
||||
on the ComboBoxes and Sliders. -->
|
||||
<TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="10,74,0,0" TextWrapping="Wrap" Text="Environment" VerticalAlignment="Top"/>
|
||||
<ComboBox x:Name="EnvironmentComboBox" HorizontalAlignment="Left" Margin="9,100,0,0" VerticalAlignment="Top" Width="160" IsDropDownOpen="True" SelectionChanged="EnvironmentComboBox_SelectionChanged"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock1}">
|
||||
<x:String>Small Room</x:String>
|
||||
<x:String>Medium Room</x:String>
|
||||
<x:String>Large Room</x:String>
|
||||
<x:String>Outdoors</x:String>
|
||||
</ComboBox>
|
||||
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="9,203,0,0" TextWrapping="Wrap" Text="Radius of Orbit" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="10,74,0,0" TextWrapping="Wrap" Text="Environment" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock2" HorizontalAlignment="Left" Margin="9,149,0,0" TextWrapping="Wrap" Text="Speed of Orbit in Seconds" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="RotationSpeedSlider" HorizontalAlignment="Left" Margin="10,159,0,0" VerticalAlignment="Top" Width="152" Maximum="20" LargeChange="1" ValueChanged="RotationSpeedSlider_ValueChanged" SmallChange="0.5"/>
|
||||
<Slider x:Name="HeightSlider" HorizontalAlignment="Left" Margin="191,213,0,0" VerticalAlignment="Top" Width="152" Minimum="-10" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="HeightSlider_ValueChanged"/>
|
||||
<Slider x:Name="RotationSpeedSlider" HorizontalAlignment="Left" Margin="10,159,0,0" VerticalAlignment="Top" Width="152" Maximum="20" LargeChange="1" ValueChanged="RotationSpeedSlider_ValueChanged" SmallChange="0.5"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock2}"/>
|
||||
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="9,203,0,0" TextWrapping="Wrap" Text="Radius of Orbit" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="RadiusSlider" HorizontalAlignment="Left" Margin="9,213,0,0" VerticalAlignment="Top" Width="152" Maximum="10" LargeChange="1" Value="1" ValueChanged="RadiusSlider_ValueChanged" SmallChange="0.1" TickFrequency="1" StepFrequency="0.1"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock}"/>
|
||||
<TextBlock x:Name="textBlock3" HorizontalAlignment="Left" Margin="191,203,0,0" TextWrapping="Wrap" Text="Height of Orbit" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="HeightSlider" HorizontalAlignment="Left" Margin="191,213,0,0" VerticalAlignment="Top" Width="152" Minimum="-10" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="HeightSlider_ValueChanged"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock3}"/>
|
||||
<Button Content="Play" Click="PlayButton_Click" HorizontalAlignment="Left" Margin="93,273,0,335" Width="47"/>
|
||||
<Button Content="Stop" Click="StopButton_Click" HorizontalAlignment="Left" Margin="189,273,0,335" Width="50"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -26,32 +26,47 @@
|
|||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Description:" VerticalAlignment="Top" FontSize="26.667" Height="35" Width="140"/>
|
||||
<TextBlock x:Name="textBlock1" HorizontalAlignment="Left" Margin="10,50,0,0" TextWrapping="Wrap" Text="Source with cardioid directivity pattern" VerticalAlignment="Top" FontSize="13.333" Height="18" Width="229"/>
|
||||
<Slider x:Name="ScalingSlider" HorizontalAlignment="Left" Margin="10,177,0,0" VerticalAlignment="Top" Width="160" LargeChange="0.5" Maximum="1" SmallChange="0.1" StepFrequency="0.1" TickFrequency="0.1" Height="44" ValueChanged="ScalingSlider_ValueChanged" ToolTipService.ToolTip="0 is Omnidirectional and 1 is fully directional"/>
|
||||
<Slider x:Name="OrderSlider" HorizontalAlignment="Left" Margin="189,177,0,0" VerticalAlignment="Top" Width="160" LargeChange="0.5" Maximum="32" SmallChange="0.1" StepFrequency="0.1" Minimum="0.1" Height="44" TickFrequency="0.1" ValueChanged="OrderSlider_ValudChanged" ToolTipService.ToolTip="Higher the order, narrower the directivity pattern"/>
|
||||
<ComboBox x:Name="EnvironmentComboBox" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="160" SelectionChanged="EnvironmentComboBox_SelectionChanged" Height="28">
|
||||
<!-- Always give ComboBoxes and Sliders names that are accessible to a screen reader.
|
||||
In this case, reference the labeling TextBlocks to have the accessible names set
|
||||
on the ComboBoxes and Sliders. -->
|
||||
<TextBlock x:Name="textBlock4" HorizontalAlignment="Left" Margin="10,90,0,0" TextWrapping="Wrap" Text="Environment" VerticalAlignment="Top"/>
|
||||
<ComboBox x:Name="EnvironmentComboBox" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="160" SelectionChanged="EnvironmentComboBox_SelectionChanged" Height="28"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock4}">
|
||||
<x:String>Small Room</x:String>
|
||||
<x:String>Medium Room</x:String>
|
||||
<x:String>Large Room</x:String>
|
||||
<x:String>Outdoors</x:String>
|
||||
</ComboBox>
|
||||
<Slider x:Name="YawSlider" HorizontalAlignment="Left" Margin="10,337,0,0" VerticalAlignment="Top" Width="100" Maximum="6.283185307" SmallChange="0.5" Height="44" ValueChanged="YawSlider_ValueChanged" LargeChange="0.5"/>
|
||||
<Slider x:Name="PitchSlider" HorizontalAlignment="Left" Margin="120,337,0,0" VerticalAlignment="Top" Width="100" Maximum="6.283185307" SmallChange="0.5" Height="44" ValueChanged="PitchSlider_ValueChanged" LargeChange="0.5"/>
|
||||
<Slider x:Name="RollSlider" HorizontalAlignment="Left" Margin="235,337,0,0" VerticalAlignment="Top" Width="100" Maximum="6.283185307" SmallChange="0.5" Height="44" ValueChanged="RollSlider_ValueChanged" LargeChange="0.5"/>
|
||||
<Button x:Name="PlayButton" Content="Play" HorizontalAlignment="Left" Margin="93,396,0,0" VerticalAlignment="Top" Height="32" Width="47" Click="PlayButton_Click"/>
|
||||
<Button x:Name="StopButton" Content="Stop" HorizontalAlignment="Left" Margin="189,396,0,0" VerticalAlignment="Top" Height="32" Width="50" Click="StopButton_Click"/>
|
||||
<TextBlock x:Name="textBlock2" HorizontalAlignment="Left" Margin="10,164,0,0" TextWrapping="Wrap" Text="Directivity Scaling" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="ScalingSlider" HorizontalAlignment="Left" Margin="10,177,0,0" VerticalAlignment="Top" Width="160" LargeChange="0.5" Maximum="1" SmallChange="0.1" StepFrequency="0.1" TickFrequency="0.1" Height="44" ValueChanged="ScalingSlider_ValueChanged" ToolTipService.ToolTip="0 is Omnidirectional and 1 is fully directional"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock2}" />
|
||||
<TextBlock x:Name="textBlock3" HorizontalAlignment="Left" Margin="189,164,0,0" TextWrapping="Wrap" Text="Cardioid Order" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock4" HorizontalAlignment="Left" Margin="10,90,0,0" TextWrapping="Wrap" Text="Environment" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock5" HorizontalAlignment="Left" Margin="10,326,0,0" TextWrapping="Wrap" Text="Yaw" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock6" HorizontalAlignment="Left" Margin="137,326,0,0" TextWrapping="Wrap" Text="Pitch" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock7" HorizontalAlignment="Left" Margin="250,326,0,0" TextWrapping="Wrap" Text="Roll" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock8" HorizontalAlignment="Left" Margin="10,300,0,0" TextWrapping="Wrap" Text="Source Orientation in Radians" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="OrderSlider" HorizontalAlignment="Left" Margin="189,177,0,0" VerticalAlignment="Top" Width="160"
|
||||
LargeChange="0.5" Maximum="32" SmallChange="0.1" StepFrequency="0.1" Minimum="0.1" Height="44" TickFrequency="0.1"
|
||||
ValueChanged="OrderSlider_ValudChanged"
|
||||
ToolTipService.ToolTip="Higher the order, narrower the directivity pattern"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock3}" />
|
||||
<TextBlock x:Name="textBlock9" HorizontalAlignment="Left" Margin="10,220,0,0" TextWrapping="Wrap" Text="Source Position in Meters" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock10" HorizontalAlignment="Left" Margin="10,252,0,364" TextWrapping="Wrap" Text="X:" VerticalAlignment="Center" Height="24" Width="25"/>
|
||||
<Slider x:Name="SourcePositionXSlider" HorizontalAlignment="Left" Margin="30,244,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="SourcePositionX_ValueChanged" Minimum="-10"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock10}" />
|
||||
<TextBlock x:Name="textBlock11" HorizontalAlignment="Left" Margin="126,253,0,0" TextWrapping="Wrap" Text="Y:" VerticalAlignment="Top" Width="27"/>
|
||||
<Slider x:Name="SourcePositionYSlider" HorizontalAlignment="Left" Margin="149,244,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="SourcePositionY_ValueChanged" Minimum="-10"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock11}" />
|
||||
<TextBlock x:Name="textBlock12" HorizontalAlignment="Left" Margin="250,253,0,0" TextWrapping="Wrap" Text="Z:" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="SourcePositionXSlider" HorizontalAlignment="Left" Margin="30,244,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="SourcePositionX_ValueChanged" Minimum="-10"/>
|
||||
<Slider x:Name="SourcePositionYSlider" HorizontalAlignment="Left" Margin="149,244,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="SourcePositionY_ValueChanged" Minimum="-10"/>
|
||||
<Slider x:Name="SourcePositionZSlider" HorizontalAlignment="Left" Margin="269,244,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="SourcePositionZ_ValueChanged" Minimum="-10"/>
|
||||
<Slider x:Name="SourcePositionZSlider" HorizontalAlignment="Left" Margin="269,244,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" ValueChanged="SourcePositionZ_ValueChanged" Minimum="-10"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock12}" />
|
||||
<TextBlock x:Name="textBlock8" HorizontalAlignment="Left" Margin="10,300,0,0" TextWrapping="Wrap" Text="Source Orientation in Radians" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock5" HorizontalAlignment="Left" Margin="10,326,0,0" TextWrapping="Wrap" Text="Yaw" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="YawSlider" HorizontalAlignment="Left" Margin="10,337,0,0" VerticalAlignment="Top" Width="100" Maximum="6.283185307" SmallChange="0.5" Height="44" ValueChanged="YawSlider_ValueChanged" LargeChange="0.5"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock5}" />
|
||||
<TextBlock x:Name="textBlock6" HorizontalAlignment="Left" Margin="137,326,0,0" TextWrapping="Wrap" Text="Pitch" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="PitchSlider" HorizontalAlignment="Left" Margin="120,337,0,0" VerticalAlignment="Top" Width="100" Maximum="6.283185307" SmallChange="0.5" Height="44" ValueChanged="PitchSlider_ValueChanged" LargeChange="0.5"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock6}" />
|
||||
<TextBlock x:Name="textBlock7" HorizontalAlignment="Left" Margin="250,326,0,0" TextWrapping="Wrap" Text="Roll" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="RollSlider" HorizontalAlignment="Left" Margin="235,337,0,0" VerticalAlignment="Top" Width="100" Maximum="6.283185307" SmallChange="0.5" Height="44" ValueChanged="RollSlider_ValueChanged" LargeChange="0.5"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock7}" />
|
||||
<Button x:Name="PlayButton" Content="Play" HorizontalAlignment="Left" Margin="93,396,0,0" VerticalAlignment="Top" Height="32" Width="47" Click="PlayButton_Click"/>
|
||||
<Button x:Name="StopButton" Content="Stop" HorizontalAlignment="Left" Margin="189,396,0,0" VerticalAlignment="Top" Height="32" Width="50" Click="StopButton_Click"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -25,8 +25,12 @@
|
|||
</Grid.ColumnDefinitions>
|
||||
<TextBlock HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Description:" VerticalAlignment="Top" FontSize="26.667" Height="35" Width="140"/>
|
||||
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="10,50,0,0" TextWrapping="Wrap" Text="Source with custom decay" VerticalAlignment="Top" FontSize="13.333" Height="18" Width="229"/>
|
||||
<!-- Always give ComboBoxes and Sliders names that are accessible to a screen reader.
|
||||
In this case, reference the labeling TextBlocks to have the accessible names set
|
||||
on the ComboBoxes and Sliders. -->
|
||||
<TextBlock x:Name="textBlock4" HorizontalAlignment="Left" Margin="10,90,0,0" TextWrapping="Wrap" Text="HRTF Environment" VerticalAlignment="Top"/>
|
||||
<ComboBox x:Name="EnvironmentComboBox" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="160" Height="28" SelectionChanged="EnvironmentComboBox_SelectionChanged">
|
||||
<ComboBox x:Name="EnvironmentComboBox" HorizontalAlignment="Left" Margin="10,115,0,0" VerticalAlignment="Top" Width="160" Height="28" SelectionChanged="EnvironmentComboBox_SelectionChanged"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock4}">
|
||||
<x:String>Small Room</x:String>
|
||||
<x:String>Medium Room</x:String>
|
||||
<x:String>Large Room</x:String>
|
||||
|
@ -34,13 +38,16 @@
|
|||
</ComboBox>
|
||||
<TextBlock x:Name="textBlock9" HorizontalAlignment="Left" Margin="10,169,0,0" TextWrapping="Wrap" Text="Source Position in Meters" VerticalAlignment="Top"/>
|
||||
<TextBlock x:Name="textBlock10" HorizontalAlignment="Left" Margin="10,201,0,415" TextWrapping="Wrap" Text="X:" VerticalAlignment="Center" Height="24" Width="25"/>
|
||||
<Slider x:Name="SourcePositionXSlider" HorizontalAlignment="Left" Margin="30,193,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" Minimum="-10" ValueChanged="SourcePositionX_ValueChanged"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock10}" />
|
||||
<TextBlock x:Name="textBlock11" HorizontalAlignment="Left" Margin="126,202,0,0" TextWrapping="Wrap" Text="Y:" VerticalAlignment="Top" Width="27"/>
|
||||
<Slider x:Name="SourcePositionYSlider" HorizontalAlignment="Left" Margin="149,193,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" Minimum="-10" ValueChanged="SourcePositionY_ValueChanged"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock11}" />
|
||||
<TextBlock x:Name="textBlock12" HorizontalAlignment="Left" Margin="250,202,0,0" TextWrapping="Wrap" Text="Z:" VerticalAlignment="Top"/>
|
||||
<Slider x:Name="SourcePositionXSlider" HorizontalAlignment="Left" Margin="30,193,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" Minimum="-10" ValueChanged="SourcePositionX_ValueChanged"/>
|
||||
<Slider x:Name="SourcePositionYSlider" HorizontalAlignment="Left" Margin="149,193,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" Minimum="-10" ValueChanged="SourcePositionY_ValueChanged"/>
|
||||
<Slider x:Name="SourcePositionZSlider" HorizontalAlignment="Left" Margin="269,193,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" Minimum="-10" ValueChanged="SourcePositionZ_ValueChanged"/>
|
||||
<Slider x:Name="SourcePositionZSlider" HorizontalAlignment="Left" Margin="269,193,0,0" VerticalAlignment="Top" Width="80" Height="44" Maximum="10" LargeChange="1" SmallChange="0.5" Minimum="-10" ValueChanged="SourcePositionZ_ValueChanged"
|
||||
AutomationProperties.LabeledBy="{Binding ElementName=textBlock12}" />
|
||||
<Button x:Name="PlayButton" Content="Play" HorizontalAlignment="Left" Margin="93,252,0,0" VerticalAlignment="Top" Height="32" Width="47" Click="PlayButton_Click"/>
|
||||
<Button x:Name="StopButton" Content="Stop" HorizontalAlignment="Left" Margin="189,252,0,0" VerticalAlignment="Top" Height="32" Width="50" Click="StopButton_Click"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
</Page>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion>10.0.16299.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.15063.0</TargetPlatformMinVersion>
|
||||
<TargetPlatformMinVersion>10.0.16299.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<EnableDotNetNativeCompatibleProfile>true</EnableDotNetNativeCompatibleProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page
|
||||
x:Class="SDKTemplate.Scenario1_CheckConsentAvailability"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid x:Name="RootGrid" Margin="12,20,12,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="0,0,0,10">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
Verifies the availability of fingerprint consent.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0" Grid.Row="1">
|
||||
<Button x:Name="CheckAvailability" Content="Check Availability" Margin="0,0,10,0" Click="CheckAvailability_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Status Block for providing messages to the user. Use the
|
||||
NotifyUser() method to populate the message -->
|
||||
<Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
|
||||
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -7,16 +7,8 @@ using namespace SDKTemplate;
|
|||
|
||||
using namespace concurrency;
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Foundation::Collections;
|
||||
using namespace Windows::Security::Credentials::UI;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
using namespace Windows::UI::Xaml::Controls::Primitives;
|
||||
using namespace Windows::UI::Xaml::Data;
|
||||
using namespace Windows::UI::Xaml::Input;
|
||||
using namespace Windows::UI::Xaml::Media;
|
||||
using namespace Windows::UI::Xaml::Navigation;
|
||||
|
||||
Scenario1_CheckConsentAvailability::Scenario1_CheckConsentAvailability()
|
||||
{
|
||||
|
@ -24,42 +16,28 @@ Scenario1_CheckConsentAvailability::Scenario1_CheckConsentAvailability()
|
|||
}
|
||||
|
||||
// Check the availability of Windows Hello authentication through User Consent Verifier.
|
||||
void Scenario1_CheckConsentAvailability::CheckAvailability_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
void Scenario1_CheckConsentAvailability::CheckAvailability_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
Button^ checkAvailabilityButton = dynamic_cast<Button^>(sender);
|
||||
checkAvailabilityButton->IsEnabled = false;
|
||||
CheckAvailabilityButton->IsEnabled = false;
|
||||
|
||||
try
|
||||
create_task(UserConsentVerifier::CheckAvailabilityAsync())
|
||||
.then([this](UserConsentVerifierAvailability consentAvailability)
|
||||
{
|
||||
create_task(Windows::Security::Credentials::UI::UserConsentVerifier::CheckAvailabilityAsync())
|
||||
.then([checkAvailabilityButton](UserConsentVerifierAvailability consentAvailability)
|
||||
switch (consentAvailability)
|
||||
{
|
||||
switch (consentAvailability)
|
||||
{
|
||||
case UserConsentVerifierAvailability::Available:
|
||||
{
|
||||
MainPage::Current->NotifyUser("User consent verification available!", NotifyType::StatusMessage);
|
||||
break;
|
||||
}
|
||||
case UserConsentVerifierAvailability::Available:
|
||||
MainPage::Current->NotifyUser("User consent verification is available.", NotifyType::StatusMessage);
|
||||
break;
|
||||
|
||||
case UserConsentVerifierAvailability::DeviceNotPresent:
|
||||
{
|
||||
MainPage::Current->NotifyUser("No PIN or biometric found, please set one up.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
case UserConsentVerifierAvailability::DeviceNotPresent:
|
||||
MainPage::Current->NotifyUser("No PIN or biometric device found, please set one up.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
MainPage::Current->NotifyUser("User consent verification is currently unavailable.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
checkAvailabilityButton->IsEnabled = true;
|
||||
});
|
||||
}
|
||||
catch (Exception ^ex)
|
||||
{
|
||||
MainPage::Current->NotifyUser("Checking the availability of Consent feature failed with exception. Operation: CheckAvailabilityAsync, Exception: " + ex->ToString(), NotifyType::ErrorMessage);
|
||||
checkAvailabilityButton->IsEnabled = true;
|
||||
}
|
||||
default:
|
||||
MainPage::Current->NotifyUser("User consent verification is currently unavailable.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
CheckAvailabilityButton->IsEnabled = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page
|
||||
x:Class="SDKTemplate.Scenario2_RequestConsent"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid x:Name="RootGrid" Margin="12,20,12,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="0,0,0,10">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
Requests fingerprint consent from the current user. Allows the calling application to specify a message to display.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<!-- Add Content Here -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<TextBlock Text="Message:" VerticalAlignment="Center" Width="85"/>
|
||||
<TextBox x:Name="Message" Text="Message to user" Width="300"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<Button x:Name="RequestConsent" Content="Request Consent" Margin="85,0,0,0" Click="RequestConsent_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Status Block for providing messages to the user. Use the
|
||||
NotifyUser() method to populate the message -->
|
||||
<Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
|
||||
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -7,16 +7,8 @@ using namespace SDKTemplate;
|
|||
|
||||
using namespace concurrency;
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Foundation::Collections;
|
||||
using namespace Windows::Security::Credentials::UI;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
using namespace Windows::UI::Xaml::Controls::Primitives;
|
||||
using namespace Windows::UI::Xaml::Data;
|
||||
using namespace Windows::UI::Xaml::Input;
|
||||
using namespace Windows::UI::Xaml::Media;
|
||||
using namespace Windows::UI::Xaml::Navigation;
|
||||
|
||||
Scenario2_RequestConsent::Scenario2_RequestConsent()
|
||||
{
|
||||
|
@ -24,58 +16,33 @@ Scenario2_RequestConsent::Scenario2_RequestConsent()
|
|||
}
|
||||
|
||||
// Requests consent from the current user.
|
||||
void Scenario2_RequestConsent::RequestConsent_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
|
||||
void Scenario2_RequestConsent::RequestConsent_Click(Object^ sender, RoutedEventArgs^ e)
|
||||
{
|
||||
Button^ requestConsentButton = dynamic_cast<Button^>(sender);
|
||||
requestConsentButton->IsEnabled = false;
|
||||
RequestConsentButton->IsEnabled = false;
|
||||
|
||||
// Read the message that has to be displayed in the consent request prompt
|
||||
if (Message->Text != nullptr)
|
||||
// Request the user's consent using Windows Hello via biometric verification or a PIN.
|
||||
String^ message = L"Please confirm your identity to complete this (pretend) in-app purchase.";
|
||||
create_task(Windows::Security::Credentials::UI::UserConsentVerifier::RequestVerificationAsync(message))
|
||||
.then([this](UserConsentVerificationResult consentResult)
|
||||
{
|
||||
try
|
||||
switch (consentResult)
|
||||
{
|
||||
// Request the logged on user's consent using Windows Hello via biometric verification or a PIN.
|
||||
create_task(Windows::Security::Credentials::UI::UserConsentVerifier::RequestVerificationAsync(Message->Text))
|
||||
.then([requestConsentButton](UserConsentVerificationResult consentResult)
|
||||
{
|
||||
switch (consentResult)
|
||||
{
|
||||
case UserConsentVerificationResult::Verified:
|
||||
{
|
||||
MainPage::Current->NotifyUser("User consent verified!", NotifyType::StatusMessage);
|
||||
break;
|
||||
}
|
||||
case UserConsentVerificationResult::Verified:
|
||||
MainPage::Current->NotifyUser("Pretend in-app purchase was successful.", NotifyType::StatusMessage);
|
||||
break;
|
||||
|
||||
case UserConsentVerificationResult::DeviceNotPresent:
|
||||
{
|
||||
MainPage::Current->NotifyUser("No PIN or biometric found, please set one up.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
case UserConsentVerificationResult::DeviceNotPresent:
|
||||
MainPage::Current->NotifyUser("No PIN or biometric device found, please set one up.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
|
||||
case UserConsentVerificationResult::Canceled:
|
||||
{
|
||||
MainPage::Current->NotifyUser("User consent verification canceled.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
case UserConsentVerificationResult::Canceled:
|
||||
MainPage::Current->NotifyUser("User consent verification canceled.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
MainPage::Current->NotifyUser("User consent verification is currently unavailable.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
requestConsentButton->IsEnabled = true;
|
||||
});
|
||||
default:
|
||||
MainPage::Current->NotifyUser("User consent verification is currently unavailable.", NotifyType::ErrorMessage);
|
||||
break;
|
||||
}
|
||||
catch (Exception ^ex)
|
||||
{
|
||||
MainPage::Current->NotifyUser("Request current user's consent failed with exception. Operation: RequestVerificationAsync, Exception: " + ex->ToString(), NotifyType::ErrorMessage);
|
||||
requestConsentButton->IsEnabled = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainPage::Current->NotifyUser("Empty Message String. Enter prompt string in the Message text field.", NotifyType::ErrorMessage);
|
||||
requestConsentButton->IsEnabled = true;
|
||||
}
|
||||
}
|
||||
RequestConsentButton->IsEnabled = true;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -155,10 +155,10 @@
|
|||
</ClInclude>
|
||||
<ClInclude Include="SampleConfiguration.h" />
|
||||
<ClInclude Include="Scenario1_CheckConsentAvailability.xaml.h">
|
||||
<DependentUpon>Scenario1_CheckConsentAvailability.xaml</DependentUpon>
|
||||
<DependentUpon>..\shared\Scenario1_CheckConsentAvailability.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Scenario2_RequestConsent.xaml.h">
|
||||
<DependentUpon>Scenario2_RequestConsent.xaml</DependentUpon>
|
||||
<DependentUpon>..\shared\Scenario2_RequestConsent.xaml</DependentUpon>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -168,8 +168,8 @@
|
|||
<Page Include="..\..\..\SharedContent\cpp\MainPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Scenario1_CheckConsentAvailability.xaml" />
|
||||
<Page Include="Scenario2_RequestConsent.xaml" />
|
||||
<Page Include="..\shared\Scenario1_CheckConsentAvailability.xaml" />
|
||||
<Page Include="..\shared\Scenario2_RequestConsent.xaml" />
|
||||
<Page Include="..\..\..\SharedContent\xaml\Styles.xaml">
|
||||
<Link>Styles\Styles.xaml</Link>
|
||||
</Page>
|
||||
|
@ -196,10 +196,10 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="SampleConfiguration.cpp" />
|
||||
<ClCompile Include="Scenario1_CheckConsentAvailability.xaml.cpp">
|
||||
<DependentUpon>Scenario1_CheckConsentAvailability.xaml</DependentUpon>
|
||||
<DependentUpon>..\shared\Scenario1_CheckConsentAvailability.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Scenario2_RequestConsent.xaml.cpp">
|
||||
<DependentUpon>Scenario2_RequestConsent.xaml</DependentUpon>
|
||||
<DependentUpon>..\shared\Scenario2_RequestConsent.xaml</DependentUpon>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
|
@ -47,8 +47,8 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="..\..\..\SharedContent\cpp\MainPage.xaml" />
|
||||
<Page Include="Scenario1_CheckConsentAvailability.xaml" />
|
||||
<Page Include="Scenario2_RequestConsent.xaml" />
|
||||
<Page Include="..\shared\Scenario1_CheckConsentAvailability.xaml" />
|
||||
<Page Include="..\shared\Scenario2_RequestConsent.xaml" />
|
||||
<Page Include="..\..\..\SharedContent\xaml\Styles.xaml">
|
||||
<Filter>Styles</Filter>
|
||||
</Page>
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using UserConsentVerifier;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page
|
||||
x:Class="UserConsentVerifier.Scenario1_CheckConsentAvailability"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:UserConsentVerifier"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<Grid x:Name="RootGrid" Margin="12,20,12,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Margin="0,0,0,10">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
Verifies the availability of fingerprint consent.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<ScrollViewer Grid.Row="1" VerticalScrollMode="Auto" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Top">
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0" Grid.Row="1">
|
||||
<Button x:Name="CheckAvailability" Content="Check Availability" Margin="0,0,10,0" Click="CheckAvailability_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Status Block for providing messages to the user. Use the
|
||||
NotifyUser() method to populate the message -->
|
||||
<Border x:Name="ErrorBorder" Background="Red" Grid.Row="2"/>
|
||||
<TextBlock x:Name="StatusBlock" Grid.Row="2" Margin="12, 10, 12, 10" Visibility="Collapsed"/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -14,9 +14,8 @@ using Windows.UI.Xaml.Controls;
|
|||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Security.Credentials.UI;
|
||||
using System;
|
||||
using SDKTemplate;
|
||||
|
||||
namespace UserConsentVerifier
|
||||
namespace SDKTemplate
|
||||
{
|
||||
public sealed partial class Scenario1_CheckConsentAvailability : Page
|
||||
{
|
||||
|
@ -27,48 +26,29 @@ namespace UserConsentVerifier
|
|||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is the click handler for the 'Check Availability' button. It checks the availability of Windows Hello via User Consent Verifier
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
private async void CheckAvailability_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Button b = sender as Button;
|
||||
b.IsEnabled = false;
|
||||
try
|
||||
{
|
||||
// Check the availability of Windows Hello authentication through User Consent Verifier.
|
||||
UserConsentVerifierAvailability consentAvailability = await Windows.Security.Credentials.UI.UserConsentVerifier.CheckAvailabilityAsync();
|
||||
switch (consentAvailability)
|
||||
{
|
||||
case UserConsentVerifierAvailability.Available:
|
||||
{
|
||||
rootPage.NotifyUser("User consent verification available!", NotifyType.StatusMessage);
|
||||
break;
|
||||
}
|
||||
CheckAvailabilityButton.IsEnabled = false;
|
||||
|
||||
case UserConsentVerifierAvailability.DeviceNotPresent:
|
||||
{
|
||||
rootPage.NotifyUser("No PIN or biometric found, please set one up.", NotifyType.ErrorMessage);
|
||||
break;
|
||||
}
|
||||
// Check the availability of Windows Hello authentication through User Consent Verifier.
|
||||
UserConsentVerifierAvailability consentAvailability = await UserConsentVerifier.CheckAvailabilityAsync();
|
||||
switch (consentAvailability)
|
||||
{
|
||||
case UserConsentVerifierAvailability.Available:
|
||||
rootPage.NotifyUser("User consent verification available!", NotifyType.StatusMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
rootPage.NotifyUser("User consent verification is currently unavailable.", NotifyType.ErrorMessage);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
rootPage.NotifyUser("Checking the availability of Consent feature failed with exception. Operation: CheckAvailabilityAsync, Exception: " + ex.ToString(), NotifyType.ErrorMessage);
|
||||
}
|
||||
finally
|
||||
{
|
||||
b.IsEnabled = true;
|
||||
case UserConsentVerifierAvailability.DeviceNotPresent:
|
||||
rootPage.NotifyUser("No PIN or biometric found, please set one up.", NotifyType.ErrorMessage);
|
||||
break;
|
||||
|
||||
default:
|
||||
rootPage.NotifyUser("User consent verification is currently unavailable.", NotifyType.ErrorMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
CheckAvailabilityButton.IsEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче