Skip to content

Commit 64980d4

Browse files
authored
Merge pull request #53 from SyncfusionExamples/896383
896383 - How to create a customized signature pad in the application to add signatures to a PDF document
2 parents 9921c81 + 3e12e81 commit 64980d4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+10192
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version = "1.0" encoding = "UTF-8" ?>
2+
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
xmlns:local="clr-namespace:CustomSignatureDialog"
5+
x:Class="CustomSignatureDialog.App">
6+
<Application.Resources>
7+
<ResourceDictionary>
8+
<ResourceDictionary.MergedDictionaries>
9+
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
10+
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
11+
</ResourceDictionary.MergedDictionaries>
12+
</ResourceDictionary>
13+
</Application.Resources>
14+
</Application>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace CustomSignatureDialog
2+
{
3+
public partial class App : Application
4+
{
5+
public App()
6+
{
7+
Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Add license key");
8+
InitializeComponent();
9+
}
10+
11+
protected override Window CreateWindow(IActivationState? activationState)
12+
{
13+
return new Window(new AppShell());
14+
}
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<Shell
3+
x:Class="CustomSignatureDialog.AppShell"
4+
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
5+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
6+
xmlns:local="clr-namespace:CustomSignatureDialog"
7+
Shell.FlyoutBehavior="Flyout"
8+
Title="CustomSignatureDialog">
9+
10+
<ShellContent
11+
Title="Home"
12+
ContentTemplate="{DataTemplate local:MainPage}"
13+
Route="MainPage" />
14+
15+
</Shell>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace CustomSignatureDialog
2+
{
3+
public partial class AppShell : Shell
4+
{
5+
public AppShell()
6+
{
7+
InitializeComponent();
8+
}
9+
}
10+
}
Binary file not shown.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks>
5+
<TargetFrameworks Condition="$([MSBuild]::IsOSPlatform('windows'))">$(TargetFrameworks);net9.0-windows10.0.19041.0</TargetFrameworks>
6+
<!-- Uncomment to also build the tizen app. You will need to install tizen by following this: https://github.com/Samsung/Tizen.NET -->
7+
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
8+
9+
<!-- Note for MacCatalyst:
10+
The default runtime is maccatalyst-x64, except in Release config, in which case the default is maccatalyst-x64;maccatalyst-arm64.
11+
When specifying both architectures, use the plural <RuntimeIdentifiers> instead of the singular <RuntimeIdentifier>.
12+
The Mac App Store will NOT accept apps with ONLY maccatalyst-arm64 indicated;
13+
either BOTH runtimes must be indicated or ONLY macatalyst-x64. -->
14+
<!-- For example: <RuntimeIdentifiers>maccatalyst-x64;maccatalyst-arm64</RuntimeIdentifiers> -->
15+
16+
<OutputType>Exe</OutputType>
17+
<RootNamespace>CustomSignatureDialog</RootNamespace>
18+
<UseMaui>true</UseMaui>
19+
<SingleProject>true</SingleProject>
20+
<ImplicitUsings>enable</ImplicitUsings>
21+
<Nullable>enable</Nullable>
22+
23+
<!-- Display name -->
24+
<ApplicationTitle>CustomSignatureDialog</ApplicationTitle>
25+
26+
<!-- App Identifier -->
27+
<ApplicationId>com.companyname.customsignaturedialog</ApplicationId>
28+
29+
<!-- Versions -->
30+
<ApplicationDisplayVersion>1.0</ApplicationDisplayVersion>
31+
<ApplicationVersion>1</ApplicationVersion>
32+
33+
<!-- To develop, package, and publish an app to the Microsoft Store, see: https://aka.ms/MauiTemplateUnpackaged -->
34+
<WindowsPackageType>None</WindowsPackageType>
35+
36+
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">15.0</SupportedOSPlatformVersion>
37+
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'maccatalyst'">15.0</SupportedOSPlatformVersion>
38+
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
39+
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
40+
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
41+
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'tizen'">6.5</SupportedOSPlatformVersion>
42+
</PropertyGroup>
43+
44+
<ItemGroup>
45+
<!-- App Icon -->
46+
<MauiIcon Include="Resources\AppIcon\appicon.svg" ForegroundFile="Resources\AppIcon\appiconfg.svg" Color="#512BD4" />
47+
48+
<!-- Splash Screen -->
49+
<MauiSplashScreen Include="Resources\Splash\splash.svg" Color="#512BD4" BaseSize="128,128" />
50+
51+
<!-- Images -->
52+
<MauiImage Include="Resources\Images\*" />
53+
<MauiImage Update="Resources\Images\dotnet_bot.png" Resize="True" BaseSize="300,185" />
54+
55+
<!-- Custom Fonts -->
56+
<MauiFont Include="Resources\Fonts\*" />
57+
58+
<!-- Raw Assets (also remove the "Resources\Raw" prefix) -->
59+
<MauiAsset Include="Resources\Raw\**" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
60+
</ItemGroup>
61+
62+
<ItemGroup>
63+
<None Remove="Assets\handwritten-signature.pdf" />
64+
</ItemGroup>
65+
66+
<ItemGroup>
67+
<EmbeddedResource Include="Assets\handwritten-signature.pdf" />
68+
</ItemGroup>
69+
70+
<ItemGroup>
71+
<PackageReference Include="Microsoft.Maui.Controls" Version="$(MauiVersion)" />
72+
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0" />
73+
<PackageReference Include="Syncfusion.Maui.PdfViewer" Version="*" />
74+
</ItemGroup>
75+
76+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio Version 17
3+
VisualStudioVersion = 17.5.2.0
4+
MinimumVisualStudioVersion = 10.0.40219.1
5+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSignatureDialog", "CustomSignatureDialog.csproj", "{4B007565-E583-9DEC-26CC-EA361CB5A747}"
6+
EndProject
7+
Global
8+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9+
Debug|Any CPU = Debug|Any CPU
10+
Release|Any CPU = Release|Any CPU
11+
EndGlobalSection
12+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
13+
{4B007565-E583-9DEC-26CC-EA361CB5A747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14+
{4B007565-E583-9DEC-26CC-EA361CB5A747}.Debug|Any CPU.Build.0 = Debug|Any CPU
15+
{4B007565-E583-9DEC-26CC-EA361CB5A747}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
16+
{4B007565-E583-9DEC-26CC-EA361CB5A747}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{4B007565-E583-9DEC-26CC-EA361CB5A747}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {AC0C2D50-B707-4CD2-8A80-4E8886ED1BD3}
24+
EndGlobalSection
25+
EndGlobal
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
namespace CustomSignatureDialog
2+
{
3+
/// <summary>
4+
/// Provides the functionality to open and save PDF files.
5+
/// </summary>
6+
public partial class FileService
7+
{
8+
/// <summary>
9+
/// Shows a file picker and lets the user choose the required PDF file.
10+
/// </summary>
11+
/// <returns>The data of the PDF file that is chosen by the user.</returns>
12+
public async static Task<PdfFileData?> OpenFile(string fileExtension)
13+
{
14+
FilePickerFileType pdfFileType = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<string>>{
15+
{ DevicePlatform.iOS, new[] { $"com.adobe.{fileExtension}" } },
16+
{ DevicePlatform.Android, new[] { $"application/{fileExtension}" } },
17+
{ DevicePlatform.WinUI, new[] { fileExtension } },
18+
{ DevicePlatform.MacCatalyst, new[] { fileExtension } },
19+
});
20+
PickOptions options = new()
21+
{
22+
PickerTitle = "Please select a PDF file",
23+
};
24+
#if !ANDROID
25+
options.FileTypes = pdfFileType;
26+
#else
27+
if (fileExtension == "pdf")
28+
options.FileTypes = pdfFileType;
29+
#endif
30+
return await PickFile(options, fileExtension);
31+
}
32+
static async Task<PdfFileData?> PickFile(PickOptions options, string fileExtension)
33+
{
34+
try
35+
{
36+
var result = await FilePicker.Default.PickAsync(options);
37+
if (result != null)
38+
{
39+
if (result.FileName != null)
40+
{
41+
if (result.FileName.EndsWith($".{fileExtension}", StringComparison.OrdinalIgnoreCase))
42+
{
43+
return new PdfFileData(result.FileName, await result.OpenReadAsync());
44+
}
45+
else
46+
{
47+
var page = Application.Current?.Windows[0]?.Page;
48+
page?.DisplayAlert("Error", $"Pick a file of type {fileExtension}", "OK");
49+
}
50+
}
51+
}
52+
return null;
53+
}
54+
catch (Exception ex)
55+
{
56+
string message = !string.IsNullOrEmpty(ex.Message) ? ex.Message : "File open failed.";
57+
var page = Application.Current?.Windows[0]?.Page;
58+
page?.DisplayAlert("Error", message, "OK");
59+
}
60+
return null;
61+
}
62+
/// <summary>
63+
/// Saves the PDF stream with given file name using platform specific file saving APIs.
64+
/// </summary>
65+
/// <param name="fileName">The file name with which the PDF needs to be saved.</param>
66+
/// <param name="fileStream">The stream of the PDF to be saved.</param>
67+
/// <returns></returns>
68+
public async static Task<string?> SaveAsAsync(string fileName, Stream fileStream)
69+
{
70+
return await PlatformSaveAsAsync(fileName, fileStream);
71+
}
72+
73+
/// <summary>
74+
/// Writes the given stream to the specified file path.
75+
/// </summary>
76+
/// <param name="stream">The stream of the PDF file to be written.</param>
77+
/// <param name="filePath">The file path to which the PDF file needs to be written.</param>
78+
/// <returns></returns>
79+
static async Task WriteStream(Stream stream, string? filePath)
80+
{
81+
if (!string.IsNullOrEmpty(filePath))
82+
{
83+
await using var fileStream = new FileStream(filePath, FileMode.OpenOrCreate);
84+
fileStream.SetLength(0);
85+
if (stream.CanSeek)
86+
{
87+
stream.Seek(0, SeekOrigin.Begin);
88+
}
89+
90+
await stream.CopyToAsync(fileStream).ConfigureAwait(false);
91+
}
92+
}
93+
}
94+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
4+
xmlns:syncfusion="clr-namespace:Syncfusion.Maui.PdfViewer;assembly=Syncfusion.Maui.PdfViewer"
5+
xmlns:local="clr-namespace:CustomSignatureDialog"
6+
x:DataType="local:PdfViewerViewModel"
7+
x:Class="CustomSignatureDialog.MainPage">
8+
9+
<ContentPage.BindingContext>
10+
<local:PdfViewerViewModel x:Name="viewModel"/>
11+
</ContentPage.BindingContext>
12+
<ContentPage.Resources>
13+
<Style x:Key="buttonIconStyle" TargetType="Button">
14+
<Setter Property="BorderWidth" Value="0" />
15+
<Setter Property="FontSize" Value="18" />
16+
<Setter Property="Padding" Value="4" />
17+
<Setter Property="VerticalOptions" Value="Center" />
18+
<Setter Property="BackgroundColor" Value="Transparent"/>
19+
<Setter Property="TextColor" Value="#99000000"/>
20+
<Setter Property="FontFamily" Value="MauiMaterialAssets" />
21+
<Setter Property="VisualStateManager.VisualStateGroups">
22+
<VisualStateGroupList>
23+
<VisualStateGroup x:Name="CommonStates">
24+
<VisualState x:Name="Normal">
25+
<VisualState.Setters>
26+
<Setter Property="BackgroundColor" Value="Transparent" />
27+
<Setter Property="Opacity" Value="1"/>
28+
</VisualState.Setters>
29+
</VisualState>
30+
<VisualState x:Name="Disabled">
31+
<VisualState.Setters>
32+
<Setter Property="BackgroundColor" Value="Transparent" />
33+
<Setter Property="Opacity" Value="0.25"/>
34+
</VisualState.Setters>
35+
</VisualState>
36+
<VisualState x:Name="Pressed">
37+
<VisualState.Setters>
38+
<Setter Property="BackgroundColor" Value="#14000000" />
39+
</VisualState.Setters>
40+
</VisualState>
41+
</VisualStateGroup>
42+
</VisualStateGroupList>
43+
</Setter>
44+
</Style>
45+
</ContentPage.Resources>
46+
<ContentPage.Content>
47+
<Grid x:Name="signature">
48+
<Grid RowDefinitions="50,*">
49+
<Grid Grid.Row="0" BackgroundColor="#F3EDF7">
50+
<HorizontalStackLayout Spacing="20" Margin="20,0,0,0" HorizontalOptions="Start">
51+
<Button x:Name="openButton" ToolTipProperties.Text="Open PDF" Style="{x:StaticResource buttonIconStyle}" Text="&#xe712;" Command="{Binding OpenCommand}" />
52+
<Button x:Name="saveAsButton" ToolTipProperties.Text="Save as" Style="{x:StaticResource buttonIconStyle}" Text="&#xe75f;" Clicked="saveAsButton_Clicked" />
53+
</HorizontalStackLayout>
54+
<Button HorizontalOptions="End" x:Name="deleteButton" IsVisible="False" Margin="0,0,10,0" Style="{x:StaticResource buttonIconStyle}" ToolTipProperties.Text="Delete signature" Text="&#xe70f;" Clicked="deleteButton_Clicked" />
55+
</Grid>
56+
<Grid Grid.Row="1" >
57+
<syncfusion:SfPdfViewer x:Name="pdfViewer" DocumentSource="{Binding FileData.Stream}"
58+
AnnotationSelected="pdfViewer_AnnotationSelected"
59+
AnnotationDeselected="pdfViewer_AnnotationDeselected"
60+
Tapped="PdfViewerTapped"
61+
ShowToolbars="False"
62+
ShowScrollHead="False"/>
63+
64+
<Button x:Name="signatureButton" Background="#6750A4" FontSize="24" ToolTipProperties.Text="Click to add signature" FontFamily="MauiMaterialAssets" Text="&#xe737;" TextColor="White" VerticalOptions="End" HorizontalOptions="End" Margin="0,0,50,50" CornerRadius="30" WidthRequest="60" HeightRequest="60" Clicked="signatureButton_Clicked">
65+
<Button.Shadow>
66+
<Shadow Brush="Black" Offset="0,0" Radius="5" Opacity="0.5" />
67+
</Button.Shadow>
68+
</Button>
69+
</Grid>
70+
<Border x:Name="toast" Grid.Row="1" BackgroundColor="Black" Padding="8" VerticalOptions="Center" HorizontalOptions="Center" Opacity="0">
71+
<Border.StrokeShape>
72+
<RoundRectangle CornerRadius="4"/>
73+
</Border.StrokeShape>
74+
<Label x:Name="toastText" VerticalOptions="Center" VerticalTextAlignment="Center" HorizontalOptions="Center" TextColor="White"/>
75+
</Border>
76+
</Grid>
77+
</Grid>
78+
</ContentPage.Content>
79+
</ContentPage>

0 commit comments

Comments
 (0)