mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2026-05-07 13:37:47 +00:00
File scoped namespaces
This commit is contained in:
parent
c14377f976
commit
65aba44af6
152 changed files with 11962 additions and 12115 deletions
|
|
@ -5,55 +5,54 @@ using Windows.UI.Xaml;
|
|||
using Microsoft.UI.Xaml;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public static class DependencyPropertyHelper
|
||||
{
|
||||
public static class DependencyPropertyHelper
|
||||
public static DependencyProperty RegisterAttached<TValue>(
|
||||
string name,
|
||||
Type ownerType,
|
||||
TValue defaultValue = default,
|
||||
Action<FrameworkElement, TValue, TValue> changed = null)
|
||||
{
|
||||
public static DependencyProperty RegisterAttached<TValue>(
|
||||
string name,
|
||||
Type ownerType,
|
||||
TValue defaultValue = default,
|
||||
Action<FrameworkElement, TValue, TValue> changed = null)
|
||||
{
|
||||
var metadata = changed == null
|
||||
? new PropertyMetadata(defaultValue)
|
||||
: new PropertyMetadata(defaultValue, (o, e) =>
|
||||
{
|
||||
if (o is FrameworkElement element)
|
||||
{
|
||||
changed(element, (TValue)e.OldValue, (TValue)e.NewValue);
|
||||
}
|
||||
});
|
||||
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TValue), ownerType, metadata);
|
||||
}
|
||||
|
||||
public static DependencyProperty Register<TOwner, TValue>(
|
||||
string name,
|
||||
TValue defaultValue = default,
|
||||
Action<TOwner, TValue, TValue> changed = null)
|
||||
where TOwner : DependencyObject
|
||||
{
|
||||
var metadata = changed != null
|
||||
? new PropertyMetadata(defaultValue, (o, e) => changed((TOwner)o, (TValue)e.OldValue, (TValue)e.NewValue))
|
||||
: new PropertyMetadata(defaultValue);
|
||||
|
||||
return DependencyProperty.Register(name, typeof(TValue), typeof(TOwner), metadata);
|
||||
}
|
||||
|
||||
public static DependencyProperty AddOwner<TOwner, TValue>(
|
||||
string name,
|
||||
DependencyProperty source,
|
||||
Action<TOwner, TValue, TValue> changed = null)
|
||||
where TOwner : DependencyObject
|
||||
{
|
||||
var metadata = new PropertyMetadata(default, (o, e) =>
|
||||
var metadata = changed == null
|
||||
? new PropertyMetadata(defaultValue)
|
||||
: new PropertyMetadata(defaultValue, (o, e) =>
|
||||
{
|
||||
o.SetValue(source, e.NewValue);
|
||||
changed?.Invoke((TOwner)o, (TValue)e.OldValue, (TValue)e.NewValue);
|
||||
if (o is FrameworkElement element)
|
||||
{
|
||||
changed(element, (TValue)e.OldValue, (TValue)e.NewValue);
|
||||
}
|
||||
});
|
||||
|
||||
return DependencyProperty.Register(name, typeof(TValue), typeof(TOwner), metadata);
|
||||
}
|
||||
return DependencyProperty.RegisterAttached(name, typeof(TValue), ownerType, metadata);
|
||||
}
|
||||
|
||||
public static DependencyProperty Register<TOwner, TValue>(
|
||||
string name,
|
||||
TValue defaultValue = default,
|
||||
Action<TOwner, TValue, TValue> changed = null)
|
||||
where TOwner : DependencyObject
|
||||
{
|
||||
var metadata = changed != null
|
||||
? new PropertyMetadata(defaultValue, (o, e) => changed((TOwner)o, (TValue)e.OldValue, (TValue)e.NewValue))
|
||||
: new PropertyMetadata(defaultValue);
|
||||
|
||||
return DependencyProperty.Register(name, typeof(TValue), typeof(TOwner), metadata);
|
||||
}
|
||||
|
||||
public static DependencyProperty AddOwner<TOwner, TValue>(
|
||||
string name,
|
||||
DependencyProperty source,
|
||||
Action<TOwner, TValue, TValue> changed = null)
|
||||
where TOwner : DependencyObject
|
||||
{
|
||||
var metadata = new PropertyMetadata(default, (o, e) =>
|
||||
{
|
||||
o.SetValue(source, e.NewValue);
|
||||
changed?.Invoke((TOwner)o, (TValue)e.OldValue, (TValue)e.NewValue);
|
||||
});
|
||||
|
||||
return DependencyProperty.Register(name, typeof(TValue), typeof(TOwner), metadata);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,66 +8,65 @@ using Windows.UI.Xaml.Media.Imaging;
|
|||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public static partial class GeoImage
|
||||
{
|
||||
public static partial class GeoImage
|
||||
private static async Task<GeoBitmap> LoadGeoTiff(string sourcePath)
|
||||
{
|
||||
private static async Task<GeoBitmap> LoadGeoTiff(string sourcePath)
|
||||
BitmapSource bitmap;
|
||||
Matrix transform;
|
||||
MapProjection projection = null;
|
||||
|
||||
var file = await StorageFile.GetFileFromPathAsync(FilePath.GetFullPath(sourcePath));
|
||||
|
||||
using var stream = await file.OpenReadAsync();
|
||||
|
||||
var decoder = await BitmapDecoder.CreateAsync(stream);
|
||||
|
||||
bitmap = await ImageLoader.LoadWriteableBitmapAsync(decoder);
|
||||
|
||||
var geoKeyDirectoryQuery = QueryString(GeoKeyDirectoryTag);
|
||||
var pixelScaleQuery = QueryString(ModelPixelScaleTag);
|
||||
var tiePointQuery = QueryString(ModelTiePointTag);
|
||||
var transformationQuery = QueryString(ModelTransformationTag);
|
||||
var metadata = await decoder.BitmapProperties.GetPropertiesAsync(
|
||||
new string[]
|
||||
{
|
||||
pixelScaleQuery,
|
||||
tiePointQuery,
|
||||
transformationQuery,
|
||||
geoKeyDirectoryQuery
|
||||
});
|
||||
|
||||
if (metadata.TryGetValue(pixelScaleQuery, out BitmapTypedValue pixelScaleValue) &&
|
||||
pixelScaleValue.Value is double[] pixelScale &&
|
||||
pixelScale.Length == 3 &&
|
||||
metadata.TryGetValue(tiePointQuery, out BitmapTypedValue tiePointValue) &&
|
||||
tiePointValue.Value is double[] tiePoint &&
|
||||
tiePoint.Length >= 6)
|
||||
{
|
||||
BitmapSource bitmap;
|
||||
Matrix transform;
|
||||
MapProjection projection = null;
|
||||
|
||||
var file = await StorageFile.GetFileFromPathAsync(FilePath.GetFullPath(sourcePath));
|
||||
|
||||
using var stream = await file.OpenReadAsync();
|
||||
|
||||
var decoder = await BitmapDecoder.CreateAsync(stream);
|
||||
|
||||
bitmap = await ImageLoader.LoadWriteableBitmapAsync(decoder);
|
||||
|
||||
var geoKeyDirectoryQuery = QueryString(GeoKeyDirectoryTag);
|
||||
var pixelScaleQuery = QueryString(ModelPixelScaleTag);
|
||||
var tiePointQuery = QueryString(ModelTiePointTag);
|
||||
var transformationQuery = QueryString(ModelTransformationTag);
|
||||
var metadata = await decoder.BitmapProperties.GetPropertiesAsync(
|
||||
new string[]
|
||||
{
|
||||
pixelScaleQuery,
|
||||
tiePointQuery,
|
||||
transformationQuery,
|
||||
geoKeyDirectoryQuery
|
||||
});
|
||||
|
||||
if (metadata.TryGetValue(pixelScaleQuery, out BitmapTypedValue pixelScaleValue) &&
|
||||
pixelScaleValue.Value is double[] pixelScale &&
|
||||
pixelScale.Length == 3 &&
|
||||
metadata.TryGetValue(tiePointQuery, out BitmapTypedValue tiePointValue) &&
|
||||
tiePointValue.Value is double[] tiePoint &&
|
||||
tiePoint.Length >= 6)
|
||||
{
|
||||
transform = new Matrix(pixelScale[0], 0d, 0d, -pixelScale[1], tiePoint[3], tiePoint[4]);
|
||||
}
|
||||
else if (metadata.TryGetValue(transformationQuery, out BitmapTypedValue transformValue) &&
|
||||
transformValue.Value is double[] transformValues &&
|
||||
transformValues.Length == 16)
|
||||
{
|
||||
transform = new Matrix(transformValues[0], transformValues[1],
|
||||
transformValues[4], transformValues[5],
|
||||
transformValues[3], transformValues[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("No coordinate transformation found.");
|
||||
}
|
||||
|
||||
if (metadata.TryGetValue(geoKeyDirectoryQuery, out BitmapTypedValue geoKeyDirValue) &&
|
||||
geoKeyDirValue.Value is short[] geoKeyDirectory)
|
||||
{
|
||||
projection = GetProjection(geoKeyDirectory);
|
||||
}
|
||||
|
||||
return new GeoBitmap(bitmap, transform, projection);
|
||||
transform = new Matrix(pixelScale[0], 0d, 0d, -pixelScale[1], tiePoint[3], tiePoint[4]);
|
||||
}
|
||||
else if (metadata.TryGetValue(transformationQuery, out BitmapTypedValue transformValue) &&
|
||||
transformValue.Value is double[] transformValues &&
|
||||
transformValues.Length == 16)
|
||||
{
|
||||
transform = new Matrix(transformValues[0], transformValues[1],
|
||||
transformValues[4], transformValues[5],
|
||||
transformValues[3], transformValues[7]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("No coordinate transformation found.");
|
||||
}
|
||||
|
||||
if (metadata.TryGetValue(geoKeyDirectoryQuery, out BitmapTypedValue geoKeyDirValue) &&
|
||||
geoKeyDirValue.Value is short[] geoKeyDirectory)
|
||||
{
|
||||
projection = GetProjection(geoKeyDirectory);
|
||||
}
|
||||
|
||||
return new GeoBitmap(bitmap, transform, projection);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,126 +14,125 @@ using Microsoft.UI.Xaml.Media;
|
|||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public static partial class ImageLoader
|
||||
{
|
||||
public static partial class ImageLoader
|
||||
public static ImageSource LoadResourceImage(Uri uri)
|
||||
{
|
||||
public static ImageSource LoadResourceImage(Uri uri)
|
||||
return new BitmapImage(uri);
|
||||
}
|
||||
|
||||
public static async Task<ImageSource> LoadImageAsync(IRandomAccessStream randomAccessStream)
|
||||
{
|
||||
var image = new BitmapImage();
|
||||
|
||||
await image.SetSourceAsync(randomAccessStream);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public static async Task<ImageSource> LoadImageAsync(Stream stream)
|
||||
{
|
||||
using var randomAccessStream = stream.AsRandomAccessStream();
|
||||
|
||||
return await LoadImageAsync(randomAccessStream);
|
||||
}
|
||||
|
||||
public static async Task<ImageSource> LoadImageAsync(string path)
|
||||
{
|
||||
ImageSource image = null;
|
||||
|
||||
path = FilePath.GetFullPath(path);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return new BitmapImage(uri);
|
||||
var file = await StorageFile.GetFileFromPathAsync(path);
|
||||
|
||||
using var randomAccessStream = await file.OpenReadAsync();
|
||||
|
||||
image = await LoadImageAsync(randomAccessStream);
|
||||
}
|
||||
|
||||
public static async Task<ImageSource> LoadImageAsync(IRandomAccessStream randomAccessStream)
|
||||
return image;
|
||||
}
|
||||
|
||||
internal static async Task<WriteableBitmap> LoadWriteableBitmapAsync(BitmapDecoder decoder)
|
||||
{
|
||||
var image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
|
||||
|
||||
var pixelData = await decoder.GetPixelDataAsync(
|
||||
BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, new BitmapTransform(),
|
||||
ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage);
|
||||
|
||||
pixelData.DetachPixelData().CopyTo(image.PixelBuffer);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
internal static async Task<WriteableBitmap> LoadWriteableBitmapAsync(Uri uri, IProgress<double> progress)
|
||||
{
|
||||
WriteableBitmap bitmap = null;
|
||||
|
||||
progress.Report(0d);
|
||||
|
||||
try
|
||||
{
|
||||
var image = new BitmapImage();
|
||||
var buffer = await GetHttpContent(uri, progress);
|
||||
|
||||
await image.SetSourceAsync(randomAccessStream);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
public static async Task<ImageSource> LoadImageAsync(Stream stream)
|
||||
{
|
||||
using var randomAccessStream = stream.AsRandomAccessStream();
|
||||
|
||||
return await LoadImageAsync(randomAccessStream);
|
||||
}
|
||||
|
||||
public static async Task<ImageSource> LoadImageAsync(string path)
|
||||
{
|
||||
ImageSource image = null;
|
||||
|
||||
path = FilePath.GetFullPath(path);
|
||||
|
||||
if (File.Exists(path))
|
||||
if (buffer != null)
|
||||
{
|
||||
var file = await StorageFile.GetFileFromPathAsync(path);
|
||||
using var memoryStream = new MemoryStream(buffer);
|
||||
using var randomAccessStream = memoryStream.AsRandomAccessStream();
|
||||
|
||||
using var randomAccessStream = await file.OpenReadAsync();
|
||||
var decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
|
||||
|
||||
image = await LoadImageAsync(randomAccessStream);
|
||||
bitmap = await LoadWriteableBitmapAsync(decoder);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
internal static async Task<WriteableBitmap> LoadWriteableBitmapAsync(BitmapDecoder decoder)
|
||||
catch (Exception ex)
|
||||
{
|
||||
var image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
|
||||
|
||||
var pixelData = await decoder.GetPixelDataAsync(
|
||||
BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied, new BitmapTransform(),
|
||||
ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage);
|
||||
|
||||
pixelData.DetachPixelData().CopyTo(image.PixelBuffer);
|
||||
|
||||
return image;
|
||||
Logger?.LogError(ex, "Failed loading {uri}", uri);
|
||||
}
|
||||
|
||||
internal static async Task<WriteableBitmap> LoadWriteableBitmapAsync(Uri uri, IProgress<double> progress)
|
||||
progress.Report(1d);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
internal static async Task<ImageSource> LoadMergedImageAsync(Uri uri1, Uri uri2, IProgress<double> progress)
|
||||
{
|
||||
WriteableBitmap mergedBitmap = null;
|
||||
var p1 = 0d;
|
||||
var p2 = 0d;
|
||||
|
||||
var bitmaps = await Task.WhenAll(
|
||||
LoadWriteableBitmapAsync(uri1, new Progress<double>(p => { p1 = p; progress.Report((p1 + p2) / 2d); })),
|
||||
LoadWriteableBitmapAsync(uri2, new Progress<double>(p => { p2 = p; progress.Report((p1 + p2) / 2d); })));
|
||||
|
||||
if (bitmaps.Length == 2 &&
|
||||
bitmaps[0] != null &&
|
||||
bitmaps[1] != null &&
|
||||
bitmaps[0].PixelHeight == bitmaps[1].PixelHeight)
|
||||
{
|
||||
WriteableBitmap bitmap = null;
|
||||
var buffer1 = bitmaps[0].PixelBuffer;
|
||||
var buffer2 = bitmaps[1].PixelBuffer;
|
||||
var stride1 = (uint)bitmaps[0].PixelWidth * 4;
|
||||
var stride2 = (uint)bitmaps[1].PixelWidth * 4;
|
||||
var stride = stride1 + stride2;
|
||||
var height = bitmaps[0].PixelHeight;
|
||||
|
||||
progress.Report(0d);
|
||||
mergedBitmap = new WriteableBitmap(bitmaps[0].PixelWidth + bitmaps[1].PixelWidth, height);
|
||||
|
||||
try
|
||||
var buffer = mergedBitmap.PixelBuffer;
|
||||
|
||||
for (uint y = 0; y < height; y++)
|
||||
{
|
||||
var buffer = await GetHttpContent(uri, progress);
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
using var memoryStream = new MemoryStream(buffer);
|
||||
using var randomAccessStream = memoryStream.AsRandomAccessStream();
|
||||
|
||||
var decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
|
||||
|
||||
bitmap = await LoadWriteableBitmapAsync(decoder);
|
||||
}
|
||||
buffer1.CopyTo(y * stride1, buffer, y * stride, stride1);
|
||||
buffer2.CopyTo(y * stride2, buffer, y * stride + stride1, stride2);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.LogError(ex, "Failed loading {uri}", uri);
|
||||
}
|
||||
|
||||
progress.Report(1d);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
internal static async Task<ImageSource> LoadMergedImageAsync(Uri uri1, Uri uri2, IProgress<double> progress)
|
||||
{
|
||||
WriteableBitmap mergedBitmap = null;
|
||||
var p1 = 0d;
|
||||
var p2 = 0d;
|
||||
|
||||
var bitmaps = await Task.WhenAll(
|
||||
LoadWriteableBitmapAsync(uri1, new Progress<double>(p => { p1 = p; progress.Report((p1 + p2) / 2d); })),
|
||||
LoadWriteableBitmapAsync(uri2, new Progress<double>(p => { p2 = p; progress.Report((p1 + p2) / 2d); })));
|
||||
|
||||
if (bitmaps.Length == 2 &&
|
||||
bitmaps[0] != null &&
|
||||
bitmaps[1] != null &&
|
||||
bitmaps[0].PixelHeight == bitmaps[1].PixelHeight)
|
||||
{
|
||||
var buffer1 = bitmaps[0].PixelBuffer;
|
||||
var buffer2 = bitmaps[1].PixelBuffer;
|
||||
var stride1 = (uint)bitmaps[0].PixelWidth * 4;
|
||||
var stride2 = (uint)bitmaps[1].PixelWidth * 4;
|
||||
var stride = stride1 + stride2;
|
||||
var height = bitmaps[0].PixelHeight;
|
||||
|
||||
mergedBitmap = new WriteableBitmap(bitmaps[0].PixelWidth + bitmaps[1].PixelWidth, height);
|
||||
|
||||
var buffer = mergedBitmap.PixelBuffer;
|
||||
|
||||
for (uint y = 0; y < height; y++)
|
||||
{
|
||||
buffer1.CopyTo(y * stride1, buffer, y * stride, stride1);
|
||||
buffer2.CopyTo(y * stride2, buffer, y * stride + stride1, stride2);
|
||||
}
|
||||
}
|
||||
|
||||
return mergedBitmap;
|
||||
}
|
||||
return mergedBitmap;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,92 +16,91 @@ using Microsoft.UI.Xaml.Media.Animation;
|
|||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public class ImageTile(int zoomLevel, int x, int y, int columnCount)
|
||||
: Tile(zoomLevel, x, y, columnCount)
|
||||
{
|
||||
public class ImageTile(int zoomLevel, int x, int y, int columnCount)
|
||||
: Tile(zoomLevel, x, y, columnCount)
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
|
||||
public override async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||
{
|
||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
public override async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||
async void LoadAndSetImageSource()
|
||||
{
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
async void LoadAndSetImageSource()
|
||||
try
|
||||
{
|
||||
try
|
||||
var image = await loadImageFunc();
|
||||
|
||||
Image.Source = image;
|
||||
|
||||
if (image != null && MapBase.ImageFadeDuration > TimeSpan.Zero)
|
||||
{
|
||||
var image = await loadImageFunc();
|
||||
|
||||
Image.Source = image;
|
||||
|
||||
if (image != null && MapBase.ImageFadeDuration > TimeSpan.Zero)
|
||||
if (image is BitmapImage bitmap && bitmap.UriSource != null)
|
||||
{
|
||||
if (image is BitmapImage bitmap && bitmap.UriSource != null)
|
||||
{
|
||||
bitmap.ImageOpened += BitmapImageOpened;
|
||||
bitmap.ImageFailed += BitmapImageFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginFadeInAnimation();
|
||||
}
|
||||
bitmap.ImageOpened += BitmapImageOpened;
|
||||
bitmap.ImageFailed += BitmapImageFailed;
|
||||
}
|
||||
else
|
||||
{
|
||||
BeginFadeInAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
tcs.TrySetResult(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.TrySetException(ex);
|
||||
}
|
||||
tcs.TrySetResult(null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tcs.TrySetException(ex);
|
||||
}
|
||||
}
|
||||
#if UWP
|
||||
if (!await Image.Dispatcher.TryRunAsync(CoreDispatcherPriority.Low, LoadAndSetImageSource))
|
||||
if (!await Image.Dispatcher.TryRunAsync(CoreDispatcherPriority.Low, LoadAndSetImageSource))
|
||||
#else
|
||||
if (!Image.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, LoadAndSetImageSource))
|
||||
if (!Image.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, LoadAndSetImageSource))
|
||||
#endif
|
||||
{
|
||||
tcs.TrySetCanceled();
|
||||
}
|
||||
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
private void BeginFadeInAnimation()
|
||||
{
|
||||
var fadeInAnimation = new DoubleAnimation
|
||||
{
|
||||
From = 0d,
|
||||
Duration = MapBase.ImageFadeDuration,
|
||||
FillBehavior = FillBehavior.Stop
|
||||
};
|
||||
|
||||
Storyboard.SetTarget(fadeInAnimation, Image);
|
||||
Storyboard.SetTargetProperty(fadeInAnimation, nameof(UIElement.Opacity));
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(fadeInAnimation);
|
||||
storyboard.Begin();
|
||||
tcs.TrySetCanceled();
|
||||
}
|
||||
|
||||
private void BitmapImageOpened(object sender, RoutedEventArgs e)
|
||||
await tcs.Task;
|
||||
}
|
||||
|
||||
private void BeginFadeInAnimation()
|
||||
{
|
||||
var fadeInAnimation = new DoubleAnimation
|
||||
{
|
||||
var bitmap = (BitmapImage)sender;
|
||||
From = 0d,
|
||||
Duration = MapBase.ImageFadeDuration,
|
||||
FillBehavior = FillBehavior.Stop
|
||||
};
|
||||
|
||||
bitmap.ImageOpened -= BitmapImageOpened;
|
||||
bitmap.ImageFailed -= BitmapImageFailed;
|
||||
Storyboard.SetTarget(fadeInAnimation, Image);
|
||||
Storyboard.SetTargetProperty(fadeInAnimation, nameof(UIElement.Opacity));
|
||||
|
||||
BeginFadeInAnimation();
|
||||
}
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(fadeInAnimation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
|
||||
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
var bitmap = (BitmapImage)sender;
|
||||
private void BitmapImageOpened(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var bitmap = (BitmapImage)sender;
|
||||
|
||||
bitmap.ImageOpened -= BitmapImageOpened;
|
||||
bitmap.ImageFailed -= BitmapImageFailed;
|
||||
bitmap.ImageOpened -= BitmapImageOpened;
|
||||
bitmap.ImageFailed -= BitmapImageFailed;
|
||||
|
||||
Image.Source = null;
|
||||
}
|
||||
BeginFadeInAnimation();
|
||||
}
|
||||
|
||||
private void BitmapImageFailed(object sender, ExceptionRoutedEventArgs e)
|
||||
{
|
||||
var bitmap = (BitmapImage)sender;
|
||||
|
||||
bitmap.ImageOpened -= BitmapImageOpened;
|
||||
bitmap.ImageFailed -= BitmapImageFailed;
|
||||
|
||||
Image.Source = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,65 +7,64 @@ using Microsoft.UI.Input;
|
|||
using Microsoft.UI.Xaml.Input;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class Map
|
||||
{
|
||||
public partial class Map
|
||||
public Map()
|
||||
{
|
||||
public Map()
|
||||
ManipulationMode
|
||||
= ManipulationModes.Scale
|
||||
| ManipulationModes.TranslateX
|
||||
| ManipulationModes.TranslateY
|
||||
| ManipulationModes.TranslateInertia;
|
||||
|
||||
PointerWheelChanged += OnPointerWheelChanged;
|
||||
PointerMoved += OnPointerMoved;
|
||||
ManipulationDelta += OnManipulationDelta;
|
||||
ManipulationCompleted += OnManipulationCompleted;
|
||||
}
|
||||
|
||||
private void OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
|
||||
{
|
||||
ManipulationMode
|
||||
= ManipulationModes.Scale
|
||||
| ManipulationModes.TranslateX
|
||||
| ManipulationModes.TranslateY
|
||||
| ManipulationModes.TranslateInertia;
|
||||
var point = e.GetCurrentPoint(this);
|
||||
|
||||
PointerWheelChanged += OnPointerWheelChanged;
|
||||
PointerMoved += OnPointerMoved;
|
||||
ManipulationDelta += OnManipulationDelta;
|
||||
ManipulationCompleted += OnManipulationCompleted;
|
||||
}
|
||||
|
||||
private void OnPointerWheelChanged(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
|
||||
{
|
||||
var point = e.GetCurrentPoint(this);
|
||||
|
||||
// Standard mouse wheel delta value is 120.
|
||||
//
|
||||
OnMouseWheel(point.Position, point.Properties.MouseWheelDelta / 120d);
|
||||
}
|
||||
}
|
||||
|
||||
private bool? manipulationEnabled;
|
||||
|
||||
private void OnPointerMoved(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
if (!manipulationEnabled.HasValue &&
|
||||
e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
manipulationEnabled = e.KeyModifiers == VirtualKeyModifiers.None;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
|
||||
{
|
||||
if (manipulationEnabled.HasValue && manipulationEnabled.Value)
|
||||
{
|
||||
if (e.PointerDeviceType == PointerDeviceType.Mouse)
|
||||
{
|
||||
TranslateMap(e.Delta.Translation);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransformMap(e.Position, e.Delta.Translation, e.Delta.Rotation, e.Delta.Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
|
||||
{
|
||||
manipulationEnabled = null;
|
||||
// Standard mouse wheel delta value is 120.
|
||||
//
|
||||
OnMouseWheel(point.Position, point.Properties.MouseWheelDelta / 120d);
|
||||
}
|
||||
}
|
||||
|
||||
private bool? manipulationEnabled;
|
||||
|
||||
private void OnPointerMoved(object sender, PointerRoutedEventArgs e)
|
||||
{
|
||||
if (!manipulationEnabled.HasValue &&
|
||||
e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
|
||||
{
|
||||
manipulationEnabled = e.KeyModifiers == VirtualKeyModifiers.None;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
|
||||
{
|
||||
if (manipulationEnabled.HasValue && manipulationEnabled.Value)
|
||||
{
|
||||
if (e.PointerDeviceType == PointerDeviceType.Mouse)
|
||||
{
|
||||
TranslateMap(e.Delta.Translation);
|
||||
}
|
||||
else
|
||||
{
|
||||
TransformMap(e.Position, e.Delta.Translation, e.Delta.Rotation, e.Delta.Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
|
||||
{
|
||||
manipulationEnabled = null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,355 +10,354 @@ using Microsoft.UI.Xaml.Media;
|
|||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapBase
|
||||
{
|
||||
public partial class MapBase
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Brush>(nameof(Foreground),
|
||||
new SolidColorBrush(Colors.Black));
|
||||
|
||||
public static readonly DependencyProperty AnimationEasingFunctionProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, EasingFunctionBase>(nameof(AnimationEasingFunction),
|
||||
new QuadraticEase { EasingMode = EasingMode.EaseOut });
|
||||
|
||||
public static readonly DependencyProperty CenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Location>(nameof(Center), new Location(0d, 0d),
|
||||
(map, oldValue, newValue) => map.CenterPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetCenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Location>(nameof(TargetCenter), new Location(0d, 0d),
|
||||
(map, oldValue, newValue) => map.TargetCenterPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty MinZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(MinZoomLevel), 1d,
|
||||
(map, oldValue, newValue) => map.MinZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty MaxZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(MaxZoomLevel), 20d,
|
||||
(map, oldValue, newValue) => map.MaxZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(ZoomLevel), 1d,
|
||||
(map, oldValue, newValue) => map.ZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetZoomLevel), 1d,
|
||||
(map, oldValue, newValue) => map.TargetZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty HeadingProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(Heading), 0d,
|
||||
(map, oldValue, newValue) => map.HeadingPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetHeadingProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetHeading), 0d,
|
||||
(map, oldValue, newValue) => map.TargetHeadingPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ViewScaleProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(ViewScale));
|
||||
|
||||
private static readonly DependencyProperty AnimatedCenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Windows.Foundation.Point>(nameof(AnimatedCenter),
|
||||
new Windows.Foundation.Point(),
|
||||
(map, oldValue, newValue) => map.Center = new Location(newValue.Y, newValue.X));
|
||||
|
||||
private Windows.Foundation.Point AnimatedCenter => (Windows.Foundation.Point)GetValue(AnimatedCenterProperty);
|
||||
|
||||
private PointAnimation centerAnimation;
|
||||
private DoubleAnimation zoomLevelAnimation;
|
||||
private DoubleAnimation headingAnimation;
|
||||
|
||||
public MapBase()
|
||||
{
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Brush>(nameof(Foreground),
|
||||
new SolidColorBrush(Colors.Black));
|
||||
// Set Background by Style to enable resetting by ClearValue in MapLayerPropertyChanged.
|
||||
// There is no default Style in Generic.xaml because MapBase has no DefaultStyleKey property.
|
||||
//
|
||||
var style = new Style(typeof(MapBase));
|
||||
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.White)));
|
||||
style.Seal();
|
||||
Style = style;
|
||||
|
||||
public static readonly DependencyProperty AnimationEasingFunctionProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, EasingFunctionBase>(nameof(AnimationEasingFunction),
|
||||
new QuadraticEase { EasingMode = EasingMode.EaseOut });
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty CenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Location>(nameof(Center), new Location(0d, 0d),
|
||||
(map, oldValue, newValue) => map.CenterPropertyChanged(newValue));
|
||||
/// <summary>
|
||||
/// Gets or sets the EasingFunction of the Center, ZoomLevel and Heading animations.
|
||||
/// The default value is a QuadraticEase with EasingMode.EaseOut.
|
||||
/// </summary>
|
||||
public EasingFunctionBase AnimationEasingFunction
|
||||
{
|
||||
get => (EasingFunctionBase)GetValue(AnimationEasingFunctionProperty);
|
||||
set => SetValue(AnimationEasingFunctionProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TargetCenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Location>(nameof(TargetCenter), new Location(0d, 0d),
|
||||
(map, oldValue, newValue) => map.TargetCenterPropertyChanged(newValue));
|
||||
/// <summary>
|
||||
/// Gets the scaling factor from projected map coordinates to view coordinates,
|
||||
/// as pixels per meter.
|
||||
/// </summary>
|
||||
public double ViewScale
|
||||
{
|
||||
get => (double)GetValue(ViewScaleProperty);
|
||||
private set => SetValue(ViewScaleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty MinZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(MinZoomLevel), 1d,
|
||||
(map, oldValue, newValue) => map.MinZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty MaxZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(MaxZoomLevel), 20d,
|
||||
(map, oldValue, newValue) => map.MaxZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(ZoomLevel), 1d,
|
||||
(map, oldValue, newValue) => map.ZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetZoomLevelProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetZoomLevel), 1d,
|
||||
(map, oldValue, newValue) => map.TargetZoomLevelPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty HeadingProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(Heading), 0d,
|
||||
(map, oldValue, newValue) => map.HeadingPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty TargetHeadingProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(TargetHeading), 0d,
|
||||
(map, oldValue, newValue) => map.TargetHeadingPropertyChanged(newValue));
|
||||
|
||||
public static readonly DependencyProperty ViewScaleProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, double>(nameof(ViewScale));
|
||||
|
||||
private static readonly DependencyProperty AnimatedCenterProperty =
|
||||
DependencyPropertyHelper.Register<MapBase, Windows.Foundation.Point>(nameof(AnimatedCenter),
|
||||
new Windows.Foundation.Point(),
|
||||
(map, oldValue, newValue) => map.Center = new Location(newValue.Y, newValue.X));
|
||||
|
||||
private Windows.Foundation.Point AnimatedCenter => (Windows.Foundation.Point)GetValue(AnimatedCenterProperty);
|
||||
|
||||
private PointAnimation centerAnimation;
|
||||
private DoubleAnimation zoomLevelAnimation;
|
||||
private DoubleAnimation headingAnimation;
|
||||
|
||||
public MapBase()
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
Clip = new RectangleGeometry
|
||||
{
|
||||
// Set Background by Style to enable resetting by ClearValue in MapLayerPropertyChanged.
|
||||
// There is no default Style in Generic.xaml because MapBase has no DefaultStyleKey property.
|
||||
//
|
||||
var style = new Style(typeof(MapBase));
|
||||
style.Setters.Add(new Setter(BackgroundProperty, new SolidColorBrush(Colors.White)));
|
||||
style.Seal();
|
||||
Style = style;
|
||||
Rect = new Windows.Foundation.Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height)
|
||||
};
|
||||
|
||||
SizeChanged += OnSizeChanged;
|
||||
}
|
||||
ResetTransformCenter();
|
||||
UpdateTransform();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the EasingFunction of the Center, ZoomLevel and Heading animations.
|
||||
/// The default value is a QuadraticEase with EasingMode.EaseOut.
|
||||
/// </summary>
|
||||
public EasingFunctionBase AnimationEasingFunction
|
||||
private void CenterPropertyChanged(Location value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
get => (EasingFunctionBase)GetValue(AnimationEasingFunctionProperty);
|
||||
set => SetValue(AnimationEasingFunctionProperty, value);
|
||||
}
|
||||
var center = CoerceCenterProperty(value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the scaling factor from projected map coordinates to view coordinates,
|
||||
/// as pixels per meter.
|
||||
/// </summary>
|
||||
public double ViewScale
|
||||
{
|
||||
get => (double)GetValue(ViewScaleProperty);
|
||||
private set => SetValue(ViewScaleProperty, value);
|
||||
}
|
||||
|
||||
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
Clip = new RectangleGeometry
|
||||
if (!center.Equals(value))
|
||||
{
|
||||
Rect = new Windows.Foundation.Rect(0d, 0d, e.NewSize.Width, e.NewSize.Height)
|
||||
};
|
||||
SetValueInternal(CenterProperty, center);
|
||||
}
|
||||
|
||||
ResetTransformCenter();
|
||||
UpdateTransform();
|
||||
}
|
||||
|
||||
private void CenterPropertyChanged(Location value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
var center = CoerceCenterProperty(value);
|
||||
|
||||
if (!center.Equals(value))
|
||||
{
|
||||
SetValueInternal(CenterProperty, center);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (centerAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, center);
|
||||
}
|
||||
SetValueInternal(TargetCenterProperty, center);
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetCenterPropertyChanged(Location value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
ResetTransformCenter();
|
||||
|
||||
var targetCenter = CoerceCenterProperty(value);
|
||||
|
||||
if (!targetCenter.Equals(value))
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, targetCenter);
|
||||
}
|
||||
|
||||
if (!targetCenter.Equals(Center))
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
}
|
||||
|
||||
centerAnimation = new PointAnimation
|
||||
{
|
||||
From = new Windows.Foundation.Point(Center.Longitude, Center.Latitude),
|
||||
To = new Windows.Foundation.Point(NearestLongitude(targetCenter.Longitude), targetCenter.Latitude),
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
centerAnimation.Completed += CenterAnimationCompleted;
|
||||
|
||||
BeginAnimation(nameof(AnimatedCenter), centerAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CenterAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
centerAnimation = null;
|
||||
|
||||
SetValueInternal(CenterProperty, TargetCenter);
|
||||
UpdateTransform();
|
||||
}
|
||||
}
|
||||
|
||||
private void MinZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
var minZoomLevel = CoerceMinZoomLevelProperty(value);
|
||||
|
||||
if (minZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(MinZoomLevelProperty, minZoomLevel);
|
||||
}
|
||||
|
||||
if (ZoomLevel < minZoomLevel)
|
||||
{
|
||||
ZoomLevel = minZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private void MaxZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
var maxZoomLevel = CoerceMaxZoomLevelProperty(value);
|
||||
|
||||
if (maxZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(MaxZoomLevelProperty, maxZoomLevel);
|
||||
}
|
||||
|
||||
if (ZoomLevel > maxZoomLevel)
|
||||
{
|
||||
ZoomLevel = maxZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var zoomLevel = CoerceZoomLevelProperty(value);
|
||||
|
||||
if (zoomLevel != value)
|
||||
{
|
||||
SetValueInternal(ZoomLevelProperty, zoomLevel);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (zoomLevelAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetZoomLevelProperty, zoomLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetZoomLevel = CoerceZoomLevelProperty(value);
|
||||
|
||||
if (targetZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(TargetZoomLevelProperty, targetZoomLevel);
|
||||
}
|
||||
|
||||
if (targetZoomLevel != ZoomLevel)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
}
|
||||
|
||||
zoomLevelAnimation = new DoubleAnimation
|
||||
{
|
||||
To = targetZoomLevel,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
|
||||
|
||||
BeginAnimation(nameof(ZoomLevel), zoomLevelAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomLevelAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
zoomLevelAnimation = null;
|
||||
|
||||
SetValueInternal(ZoomLevelProperty, TargetZoomLevel);
|
||||
UpdateTransform(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void HeadingPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var heading = CoerceHeadingProperty(value);
|
||||
|
||||
if (heading != value)
|
||||
{
|
||||
SetValueInternal(HeadingProperty, heading);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (headingAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetHeadingProperty, heading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetHeadingPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetHeading = CoerceHeadingProperty(value);
|
||||
|
||||
if (targetHeading != value)
|
||||
{
|
||||
SetValueInternal(TargetHeadingProperty, targetHeading);
|
||||
}
|
||||
|
||||
if (targetHeading != Heading)
|
||||
{
|
||||
var delta = targetHeading - Heading;
|
||||
|
||||
if (delta > 180d)
|
||||
{
|
||||
delta -= 360d;
|
||||
}
|
||||
else if (delta < -180d)
|
||||
{
|
||||
delta += 360d;
|
||||
}
|
||||
|
||||
if (headingAnimation != null)
|
||||
{
|
||||
headingAnimation.Completed -= HeadingAnimationCompleted;
|
||||
}
|
||||
|
||||
headingAnimation = new DoubleAnimation
|
||||
{
|
||||
By = delta,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
headingAnimation.Completed += HeadingAnimationCompleted;
|
||||
|
||||
BeginAnimation(nameof(Heading), headingAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HeadingAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (headingAnimation != null)
|
||||
{
|
||||
headingAnimation.Completed -= HeadingAnimationCompleted;
|
||||
headingAnimation = null;
|
||||
|
||||
SetValueInternal(HeadingProperty, TargetHeading);
|
||||
UpdateTransform();
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginAnimation(string property, Timeline animation)
|
||||
{
|
||||
Storyboard.SetTarget(animation, this);
|
||||
Storyboard.SetTargetProperty(animation, property);
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(animation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetCenterPropertyChanged(Location value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
ResetTransformCenter();
|
||||
|
||||
var targetCenter = CoerceCenterProperty(value);
|
||||
|
||||
if (!targetCenter.Equals(value))
|
||||
{
|
||||
SetValueInternal(TargetCenterProperty, targetCenter);
|
||||
}
|
||||
|
||||
if (!targetCenter.Equals(Center))
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
}
|
||||
|
||||
centerAnimation = new PointAnimation
|
||||
{
|
||||
From = new Windows.Foundation.Point(Center.Longitude, Center.Latitude),
|
||||
To = new Windows.Foundation.Point(NearestLongitude(targetCenter.Longitude), targetCenter.Latitude),
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
centerAnimation.Completed += CenterAnimationCompleted;
|
||||
|
||||
BeginAnimation(nameof(AnimatedCenter), centerAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CenterAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (centerAnimation != null)
|
||||
{
|
||||
centerAnimation.Completed -= CenterAnimationCompleted;
|
||||
centerAnimation = null;
|
||||
|
||||
SetValueInternal(CenterProperty, TargetCenter);
|
||||
UpdateTransform();
|
||||
}
|
||||
}
|
||||
|
||||
private void MinZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
var minZoomLevel = CoerceMinZoomLevelProperty(value);
|
||||
|
||||
if (minZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(MinZoomLevelProperty, minZoomLevel);
|
||||
}
|
||||
|
||||
if (ZoomLevel < minZoomLevel)
|
||||
{
|
||||
ZoomLevel = minZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private void MaxZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
var maxZoomLevel = CoerceMaxZoomLevelProperty(value);
|
||||
|
||||
if (maxZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(MaxZoomLevelProperty, maxZoomLevel);
|
||||
}
|
||||
|
||||
if (ZoomLevel > maxZoomLevel)
|
||||
{
|
||||
ZoomLevel = maxZoomLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var zoomLevel = CoerceZoomLevelProperty(value);
|
||||
|
||||
if (zoomLevel != value)
|
||||
{
|
||||
SetValueInternal(ZoomLevelProperty, zoomLevel);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (zoomLevelAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetZoomLevelProperty, zoomLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetZoomLevelPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetZoomLevel = CoerceZoomLevelProperty(value);
|
||||
|
||||
if (targetZoomLevel != value)
|
||||
{
|
||||
SetValueInternal(TargetZoomLevelProperty, targetZoomLevel);
|
||||
}
|
||||
|
||||
if (targetZoomLevel != ZoomLevel)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
}
|
||||
|
||||
zoomLevelAnimation = new DoubleAnimation
|
||||
{
|
||||
To = targetZoomLevel,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
zoomLevelAnimation.Completed += ZoomLevelAnimationCompleted;
|
||||
|
||||
BeginAnimation(nameof(ZoomLevel), zoomLevelAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomLevelAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (zoomLevelAnimation != null)
|
||||
{
|
||||
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
|
||||
zoomLevelAnimation = null;
|
||||
|
||||
SetValueInternal(ZoomLevelProperty, TargetZoomLevel);
|
||||
UpdateTransform(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void HeadingPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var heading = CoerceHeadingProperty(value);
|
||||
|
||||
if (heading != value)
|
||||
{
|
||||
SetValueInternal(HeadingProperty, heading);
|
||||
}
|
||||
|
||||
UpdateTransform();
|
||||
|
||||
if (headingAnimation == null)
|
||||
{
|
||||
SetValueInternal(TargetHeadingProperty, heading);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void TargetHeadingPropertyChanged(double value)
|
||||
{
|
||||
if (!internalPropertyChange)
|
||||
{
|
||||
var targetHeading = CoerceHeadingProperty(value);
|
||||
|
||||
if (targetHeading != value)
|
||||
{
|
||||
SetValueInternal(TargetHeadingProperty, targetHeading);
|
||||
}
|
||||
|
||||
if (targetHeading != Heading)
|
||||
{
|
||||
var delta = targetHeading - Heading;
|
||||
|
||||
if (delta > 180d)
|
||||
{
|
||||
delta -= 360d;
|
||||
}
|
||||
else if (delta < -180d)
|
||||
{
|
||||
delta += 360d;
|
||||
}
|
||||
|
||||
if (headingAnimation != null)
|
||||
{
|
||||
headingAnimation.Completed -= HeadingAnimationCompleted;
|
||||
}
|
||||
|
||||
headingAnimation = new DoubleAnimation
|
||||
{
|
||||
By = delta,
|
||||
Duration = AnimationDuration,
|
||||
EasingFunction = AnimationEasingFunction,
|
||||
EnableDependentAnimation = true
|
||||
};
|
||||
|
||||
headingAnimation.Completed += HeadingAnimationCompleted;
|
||||
|
||||
BeginAnimation(nameof(Heading), headingAnimation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HeadingAnimationCompleted(object sender, object e)
|
||||
{
|
||||
if (headingAnimation != null)
|
||||
{
|
||||
headingAnimation.Completed -= HeadingAnimationCompleted;
|
||||
headingAnimation = null;
|
||||
|
||||
SetValueInternal(HeadingProperty, TargetHeading);
|
||||
UpdateTransform();
|
||||
}
|
||||
}
|
||||
|
||||
private void BeginAnimation(string property, Timeline animation)
|
||||
{
|
||||
Storyboard.SetTarget(animation, this);
|
||||
Storyboard.SetTargetProperty(animation, property);
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(animation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,50 +6,49 @@ using Microsoft.UI.Xaml;
|
|||
using Microsoft.UI.Xaml.Data;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapContentControl
|
||||
{
|
||||
public partial class MapContentControl
|
||||
public MapContentControl()
|
||||
{
|
||||
public MapContentControl()
|
||||
DefaultStyleKey = typeof(MapContentControl);
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var parentMap = MapPanel.GetParentMap(this);
|
||||
|
||||
if (parentMap != null)
|
||||
{
|
||||
DefaultStyleKey = typeof(MapContentControl);
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var parentMap = MapPanel.GetParentMap(this);
|
||||
|
||||
if (parentMap != null)
|
||||
// Workaround for missing RelativeSource AncestorType=MapBase Bindings in default Style.
|
||||
//
|
||||
if (Background == null)
|
||||
{
|
||||
// Workaround for missing RelativeSource AncestorType=MapBase Bindings in default Style.
|
||||
//
|
||||
if (Background == null)
|
||||
{
|
||||
SetBinding(BackgroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Background)) });
|
||||
}
|
||||
if (Foreground == null)
|
||||
{
|
||||
SetBinding(ForegroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
if (BorderBrush == null)
|
||||
{
|
||||
SetBinding(BorderBrushProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
SetBinding(BackgroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Background)) });
|
||||
}
|
||||
if (Foreground == null)
|
||||
{
|
||||
SetBinding(ForegroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
if (BorderBrush == null)
|
||||
{
|
||||
SetBinding(BorderBrushProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public partial class Pushpin
|
||||
public partial class Pushpin
|
||||
{
|
||||
public Pushpin()
|
||||
{
|
||||
public Pushpin()
|
||||
{
|
||||
DefaultStyleKey = typeof(Pushpin);
|
||||
}
|
||||
DefaultStyleKey = typeof(Pushpin);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,129 +14,128 @@ using Microsoft.UI.Xaml.Media;
|
|||
using Microsoft.UI.Xaml.Shapes;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapGrid : MapPanel
|
||||
{
|
||||
public partial class MapGrid : MapPanel
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
DependencyPropertyHelper.Register<MapGrid, Brush>(nameof(Foreground));
|
||||
|
||||
public static readonly DependencyProperty FontFamilyProperty =
|
||||
DependencyPropertyHelper.Register<MapGrid, FontFamily>(nameof(FontFamily));
|
||||
|
||||
public static readonly DependencyProperty FontSizeProperty =
|
||||
DependencyPropertyHelper.Register<MapGrid, double>(nameof(FontSize), 12d);
|
||||
|
||||
protected override void SetParentMap(MapBase map)
|
||||
{
|
||||
public static readonly DependencyProperty ForegroundProperty =
|
||||
DependencyPropertyHelper.Register<MapGrid, Brush>(nameof(Foreground));
|
||||
|
||||
public static readonly DependencyProperty FontFamilyProperty =
|
||||
DependencyPropertyHelper.Register<MapGrid, FontFamily>(nameof(FontFamily));
|
||||
|
||||
public static readonly DependencyProperty FontSizeProperty =
|
||||
DependencyPropertyHelper.Register<MapGrid, double>(nameof(FontSize), 12d);
|
||||
|
||||
protected override void SetParentMap(MapBase map)
|
||||
if (map != null && Foreground == null)
|
||||
{
|
||||
if (map != null && Foreground == null)
|
||||
{
|
||||
SetBinding(ForegroundProperty,
|
||||
new Binding { Source = map, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
|
||||
base.SetParentMap(map);
|
||||
SetBinding(ForegroundProperty,
|
||||
new Binding { Source = map, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||
base.SetParentMap(map);
|
||||
}
|
||||
|
||||
protected override void OnViewportChanged(ViewportChangedEventArgs e)
|
||||
{
|
||||
Path path;
|
||||
|
||||
if (Children.Count == 0)
|
||||
{
|
||||
Path path;
|
||||
path = new Path { Data = new PathGeometry() };
|
||||
|
||||
if (Children.Count == 0)
|
||||
path.SetBinding(Shape.StrokeProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Foreground)) });
|
||||
|
||||
path.SetBinding(Shape.StrokeThicknessProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(StrokeThickness)) });
|
||||
|
||||
Children.Add(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = (Path)Children[0];
|
||||
}
|
||||
|
||||
var childrenCount = 1;
|
||||
var labels = new List<Label>();
|
||||
var figures = ((PathGeometry)path.Data).Figures;
|
||||
figures.Clear();
|
||||
|
||||
DrawGrid(figures, labels);
|
||||
|
||||
foreach (var label in labels)
|
||||
{
|
||||
TextBlock textBlock;
|
||||
|
||||
if (childrenCount < Children.Count)
|
||||
{
|
||||
path = new Path { Data = new PathGeometry() };
|
||||
|
||||
path.SetBinding(Shape.StrokeProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Foreground)) });
|
||||
|
||||
path.SetBinding(Shape.StrokeThicknessProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(StrokeThickness)) });
|
||||
|
||||
Children.Add(path);
|
||||
textBlock = (TextBlock)Children[childrenCount];
|
||||
}
|
||||
else
|
||||
{
|
||||
path = (Path)Children[0];
|
||||
}
|
||||
textBlock = new TextBlock { RenderTransform = new MatrixTransform() };
|
||||
|
||||
var childrenCount = 1;
|
||||
var labels = new List<Label>();
|
||||
var figures = ((PathGeometry)path.Data).Figures;
|
||||
figures.Clear();
|
||||
textBlock.SetBinding(TextBlock.FontSizeProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(FontSize)) });
|
||||
|
||||
DrawGrid(figures, labels);
|
||||
textBlock.SetBinding(TextBlock.ForegroundProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Foreground)) });
|
||||
|
||||
foreach (var label in labels)
|
||||
{
|
||||
TextBlock textBlock;
|
||||
|
||||
if (childrenCount < Children.Count)
|
||||
if (FontFamily != null)
|
||||
{
|
||||
textBlock = (TextBlock)Children[childrenCount];
|
||||
}
|
||||
else
|
||||
{
|
||||
textBlock = new TextBlock { RenderTransform = new MatrixTransform() };
|
||||
|
||||
textBlock.SetBinding(TextBlock.FontSizeProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(FontSize)) });
|
||||
|
||||
textBlock.SetBinding(TextBlock.ForegroundProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Foreground)) });
|
||||
|
||||
if (FontFamily != null)
|
||||
{
|
||||
textBlock.SetBinding(TextBlock.FontFamilyProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(FontFamily)) });
|
||||
}
|
||||
|
||||
Children.Add(textBlock);
|
||||
textBlock.SetBinding(TextBlock.FontFamilyProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(FontFamily)) });
|
||||
}
|
||||
|
||||
textBlock.Text = label.Text;
|
||||
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
var x = label.HorizontalAlignment switch
|
||||
{
|
||||
HorizontalAlignment.Left => 2d,
|
||||
HorizontalAlignment.Right => -textBlock.DesiredSize.Width - 2d,
|
||||
_ => -textBlock.DesiredSize.Width / 2d
|
||||
};
|
||||
var y = label.VerticalAlignment switch
|
||||
{
|
||||
VerticalAlignment.Top => 0d,
|
||||
VerticalAlignment.Bottom => -textBlock.DesiredSize.Height,
|
||||
_ => -textBlock.DesiredSize.Height / 2d,
|
||||
};
|
||||
|
||||
var matrix = new Matrix(1, 0, 0, 1, 0, 0);
|
||||
matrix.Translate(x, y);
|
||||
matrix.Rotate(label.Rotation);
|
||||
matrix.Translate(label.X, label.Y);
|
||||
|
||||
((MatrixTransform)textBlock.RenderTransform).Matrix = matrix;
|
||||
|
||||
childrenCount++;
|
||||
Children.Add(textBlock);
|
||||
}
|
||||
|
||||
while (Children.Count > childrenCount)
|
||||
textBlock.Text = label.Text;
|
||||
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
|
||||
|
||||
var x = label.HorizontalAlignment switch
|
||||
{
|
||||
Children.RemoveAt(Children.Count - 1);
|
||||
}
|
||||
HorizontalAlignment.Left => 2d,
|
||||
HorizontalAlignment.Right => -textBlock.DesiredSize.Width - 2d,
|
||||
_ => -textBlock.DesiredSize.Width / 2d
|
||||
};
|
||||
var y = label.VerticalAlignment switch
|
||||
{
|
||||
VerticalAlignment.Top => 0d,
|
||||
VerticalAlignment.Bottom => -textBlock.DesiredSize.Height,
|
||||
_ => -textBlock.DesiredSize.Height / 2d,
|
||||
};
|
||||
|
||||
base.OnViewportChanged(e);
|
||||
var matrix = new Matrix(1, 0, 0, 1, 0, 0);
|
||||
matrix.Translate(x, y);
|
||||
matrix.Rotate(label.Rotation);
|
||||
matrix.Translate(label.X, label.Y);
|
||||
|
||||
((MatrixTransform)textBlock.RenderTransform).Matrix = matrix;
|
||||
|
||||
childrenCount++;
|
||||
}
|
||||
|
||||
private static PolyLineSegment CreatePolyLineSegment(IEnumerable<Point> points)
|
||||
while (Children.Count > childrenCount)
|
||||
{
|
||||
var polyline = new PolyLineSegment();
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
polyline.Points.Add(p);
|
||||
}
|
||||
|
||||
return polyline;
|
||||
Children.RemoveAt(Children.Count - 1);
|
||||
}
|
||||
|
||||
base.OnViewportChanged(e);
|
||||
}
|
||||
|
||||
private static PolyLineSegment CreatePolyLineSegment(IEnumerable<Point> points)
|
||||
{
|
||||
var polyline = new PolyLineSegment();
|
||||
|
||||
foreach (var p in points)
|
||||
{
|
||||
polyline.Points.Add(p);
|
||||
}
|
||||
|
||||
return polyline;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,35 +5,34 @@ using Windows.UI.Xaml.Media.Animation;
|
|||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapImageLayer
|
||||
{
|
||||
public partial class MapImageLayer
|
||||
private void FadeOver()
|
||||
{
|
||||
private void FadeOver()
|
||||
var fadeInAnimation = new DoubleAnimation
|
||||
{
|
||||
var fadeInAnimation = new DoubleAnimation
|
||||
{
|
||||
To = 1d,
|
||||
Duration = MapBase.ImageFadeDuration
|
||||
};
|
||||
To = 1d,
|
||||
Duration = MapBase.ImageFadeDuration
|
||||
};
|
||||
|
||||
var fadeOutAnimation = new DoubleAnimation
|
||||
{
|
||||
To = 0d,
|
||||
BeginTime = MapBase.ImageFadeDuration,
|
||||
Duration = TimeSpan.Zero
|
||||
};
|
||||
var fadeOutAnimation = new DoubleAnimation
|
||||
{
|
||||
To = 0d,
|
||||
BeginTime = MapBase.ImageFadeDuration,
|
||||
Duration = TimeSpan.Zero
|
||||
};
|
||||
|
||||
Storyboard.SetTarget(fadeInAnimation, Children[1]);
|
||||
Storyboard.SetTargetProperty(fadeInAnimation, nameof(Opacity));
|
||||
Storyboard.SetTarget(fadeInAnimation, Children[1]);
|
||||
Storyboard.SetTargetProperty(fadeInAnimation, nameof(Opacity));
|
||||
|
||||
Storyboard.SetTarget(fadeOutAnimation, Children[0]);
|
||||
Storyboard.SetTargetProperty(fadeOutAnimation, nameof(Opacity));
|
||||
Storyboard.SetTarget(fadeOutAnimation, Children[0]);
|
||||
Storyboard.SetTargetProperty(fadeOutAnimation, nameof(Opacity));
|
||||
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(fadeInAnimation);
|
||||
storyboard.Children.Add(fadeOutAnimation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
var storyboard = new Storyboard();
|
||||
storyboard.Children.Add(fadeInAnimation);
|
||||
storyboard.Children.Add(fadeOutAnimation);
|
||||
storyboard.Begin();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,80 +12,79 @@ using Microsoft.UI.Xaml.Data;
|
|||
using Microsoft.UI.Xaml.Input;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapItem
|
||||
{
|
||||
public partial class MapItem
|
||||
private Windows.Foundation.Point? pointerPressedPosition;
|
||||
|
||||
public MapItem()
|
||||
{
|
||||
private Windows.Foundation.Point? pointerPressedPosition;
|
||||
DefaultStyleKey = typeof(MapItem);
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
|
||||
public MapItem()
|
||||
{
|
||||
DefaultStyleKey = typeof(MapItem);
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
protected override void OnPointerPressed(PointerRoutedEventArgs e)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
pointerPressedPosition = e.GetCurrentPoint(null).Position;
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnPointerPressed(PointerRoutedEventArgs e)
|
||||
protected override void OnPointerReleased(PointerRoutedEventArgs e)
|
||||
{
|
||||
if (pointerPressedPosition.HasValue)
|
||||
{
|
||||
base.OnPointerPressed(e);
|
||||
pointerPressedPosition = e.GetCurrentPoint(null).Position;
|
||||
e.Handled = true;
|
||||
}
|
||||
const float pointerMovementThreshold = 2f;
|
||||
var p = e.GetCurrentPoint(null).Position;
|
||||
|
||||
protected override void OnPointerReleased(PointerRoutedEventArgs e)
|
||||
{
|
||||
if (pointerPressedPosition.HasValue)
|
||||
// Perform selection only when no significant pointer movement occured.
|
||||
//
|
||||
if (Math.Abs(p.X - pointerPressedPosition.Value.X) <= pointerMovementThreshold &&
|
||||
Math.Abs(p.Y - pointerPressedPosition.Value.Y) <= pointerMovementThreshold &&
|
||||
ItemsControl.ItemsControlFromItemContainer(this) is MapItemsControl mapItemsControl)
|
||||
{
|
||||
const float pointerMovementThreshold = 2f;
|
||||
var p = e.GetCurrentPoint(null).Position;
|
||||
|
||||
// Perform selection only when no significant pointer movement occured.
|
||||
//
|
||||
if (Math.Abs(p.X - pointerPressedPosition.Value.X) <= pointerMovementThreshold &&
|
||||
Math.Abs(p.Y - pointerPressedPosition.Value.Y) <= pointerMovementThreshold &&
|
||||
ItemsControl.ItemsControlFromItemContainer(this) is MapItemsControl mapItemsControl)
|
||||
if (mapItemsControl.SelectionMode == SelectionMode.Extended &&
|
||||
e.KeyModifiers.HasFlag(VirtualKeyModifiers.Shift))
|
||||
{
|
||||
if (mapItemsControl.SelectionMode == SelectionMode.Extended &&
|
||||
e.KeyModifiers.HasFlag(VirtualKeyModifiers.Shift))
|
||||
{
|
||||
mapItemsControl.SelectItemsInRange(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnPointerReleased(e);
|
||||
}
|
||||
mapItemsControl.SelectItemsInRange(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnPointerReleased(e);
|
||||
}
|
||||
|
||||
pointerPressedPosition = null;
|
||||
}
|
||||
|
||||
e.Handled = true;
|
||||
pointerPressedPosition = null;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var parentMap = MapPanel.GetParentMap(this);
|
||||
|
||||
if (parentMap != null)
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
var parentMap = MapPanel.GetParentMap(this);
|
||||
|
||||
if (parentMap != null)
|
||||
// Workaround for missing RelativeSource AncestorType=MapBase Bindings in default Style.
|
||||
//
|
||||
if (Background == null)
|
||||
{
|
||||
// Workaround for missing RelativeSource AncestorType=MapBase Bindings in default Style.
|
||||
//
|
||||
if (Background == null)
|
||||
{
|
||||
SetBinding(BackgroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Background)) });
|
||||
}
|
||||
if (Foreground == null)
|
||||
{
|
||||
SetBinding(ForegroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
if (BorderBrush == null)
|
||||
{
|
||||
SetBinding(BorderBrushProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
SetBinding(BackgroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Background)) });
|
||||
}
|
||||
if (Foreground == null)
|
||||
{
|
||||
SetBinding(ForegroundProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
if (BorderBrush == null)
|
||||
{
|
||||
SetBinding(BorderBrushProperty,
|
||||
new Binding { Source = parentMap, Path = new PropertyPath(nameof(Foreground)) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,41 +4,40 @@ using Windows.UI.Xaml;
|
|||
using Microsoft.UI.Xaml;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapItemsControl
|
||||
{
|
||||
public partial class MapItemsControl
|
||||
public MapItemsControl()
|
||||
{
|
||||
public MapItemsControl()
|
||||
{
|
||||
DefaultStyleKey = typeof(MapItemsControl);
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
DefaultStyleKey = typeof(MapItemsControl);
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
|
||||
public new MapItem ContainerFromItem(object item)
|
||||
{
|
||||
return (MapItem)base.ContainerFromItem(item);
|
||||
}
|
||||
public new MapItem ContainerFromItem(object item)
|
||||
{
|
||||
return (MapItem)base.ContainerFromItem(item);
|
||||
}
|
||||
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
return item is MapItem;
|
||||
}
|
||||
protected override bool IsItemItsOwnContainerOverride(object item)
|
||||
{
|
||||
return item is MapItem;
|
||||
}
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
return new MapItem();
|
||||
}
|
||||
protected override DependencyObject GetContainerForItemOverride()
|
||||
{
|
||||
return new MapItem();
|
||||
}
|
||||
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject container, object item)
|
||||
{
|
||||
base.PrepareContainerForItemOverride(container, item);
|
||||
PrepareContainer((MapItem)container, item);
|
||||
}
|
||||
protected override void PrepareContainerForItemOverride(DependencyObject container, object item)
|
||||
{
|
||||
base.PrepareContainerForItemOverride(container, item);
|
||||
PrepareContainer((MapItem)container, item);
|
||||
}
|
||||
|
||||
protected override void ClearContainerForItemOverride(DependencyObject container, object item)
|
||||
{
|
||||
base.ClearContainerForItemOverride(container, item);
|
||||
ClearContainer((MapItem)container);
|
||||
}
|
||||
protected override void ClearContainerForItemOverride(DependencyObject container, object item)
|
||||
{
|
||||
base.ClearContainerForItemOverride(container, item);
|
||||
ClearContainer((MapItem)container);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,52 +6,51 @@ using Microsoft.UI.Xaml;
|
|||
using Microsoft.UI.Xaml.Media;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapPanel
|
||||
{
|
||||
public partial class MapPanel
|
||||
public static readonly DependencyProperty AutoCollapseProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<bool>("AutoCollapse", typeof(MapPanel));
|
||||
|
||||
public static readonly DependencyProperty LocationProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<Location>("Location", typeof(MapPanel), null,
|
||||
(element, oldValue, newValue) => (element.Parent as MapPanel)?.InvalidateArrange());
|
||||
|
||||
public static readonly DependencyProperty BoundingBoxProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<BoundingBox>("BoundingBox", typeof(MapPanel), null,
|
||||
(element, oldValue, newValue) => (element.Parent as MapPanel)?.InvalidateArrange());
|
||||
|
||||
public static readonly DependencyProperty MapRectProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<Rect?>("MapRect", typeof(MapPanel), null,
|
||||
(element, oldValue, newValue) => (element.Parent as MapPanel)?.InvalidateArrange());
|
||||
|
||||
public static void InitMapElement(FrameworkElement element)
|
||||
{
|
||||
public static readonly DependencyProperty AutoCollapseProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<bool>("AutoCollapse", typeof(MapPanel));
|
||||
// Workaround for missing property value inheritance.
|
||||
// Loaded and Unloaded handlers set and clear the ParentMap property value.
|
||||
//
|
||||
element.Loaded += (_, _) => GetParentMap(element);
|
||||
element.Unloaded += (_, _) => element.ClearValue(ParentMapProperty);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty LocationProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<Location>("Location", typeof(MapPanel), null,
|
||||
(element, oldValue, newValue) => (element.Parent as MapPanel)?.InvalidateArrange());
|
||||
public static MapBase GetParentMap(FrameworkElement element)
|
||||
{
|
||||
var parentMap = (MapBase)element.GetValue(ParentMapProperty);
|
||||
|
||||
public static readonly DependencyProperty BoundingBoxProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<BoundingBox>("BoundingBox", typeof(MapPanel), null,
|
||||
(element, oldValue, newValue) => (element.Parent as MapPanel)?.InvalidateArrange());
|
||||
|
||||
public static readonly DependencyProperty MapRectProperty =
|
||||
DependencyPropertyHelper.RegisterAttached<Rect?>("MapRect", typeof(MapPanel), null,
|
||||
(element, oldValue, newValue) => (element.Parent as MapPanel)?.InvalidateArrange());
|
||||
|
||||
public static void InitMapElement(FrameworkElement element)
|
||||
// Traverse visual tree because of missing property value inheritance.
|
||||
//
|
||||
if (parentMap == null &&
|
||||
VisualTreeHelper.GetParent(element) is FrameworkElement parentElement)
|
||||
{
|
||||
// Workaround for missing property value inheritance.
|
||||
// Loaded and Unloaded handlers set and clear the ParentMap property value.
|
||||
//
|
||||
element.Loaded += (_, _) => GetParentMap(element);
|
||||
element.Unloaded += (_, _) => element.ClearValue(ParentMapProperty);
|
||||
}
|
||||
parentMap = (parentElement as MapBase) ?? GetParentMap(parentElement);
|
||||
|
||||
public static MapBase GetParentMap(FrameworkElement element)
|
||||
{
|
||||
var parentMap = (MapBase)element.GetValue(ParentMapProperty);
|
||||
|
||||
// Traverse visual tree because of missing property value inheritance.
|
||||
//
|
||||
if (parentMap == null &&
|
||||
VisualTreeHelper.GetParent(element) is FrameworkElement parentElement)
|
||||
if (parentMap != null)
|
||||
{
|
||||
parentMap = (parentElement as MapBase) ?? GetParentMap(parentElement);
|
||||
|
||||
if (parentMap != null)
|
||||
{
|
||||
element.SetValue(ParentMapProperty, parentMap);
|
||||
}
|
||||
element.SetValue(ParentMapProperty, parentMap);
|
||||
}
|
||||
|
||||
return parentMap;
|
||||
}
|
||||
|
||||
return parentMap;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,13 +4,12 @@ using Windows.UI.Xaml.Shapes;
|
|||
using Microsoft.UI.Xaml.Shapes;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapPath : Path
|
||||
{
|
||||
public partial class MapPath : Path
|
||||
public MapPath()
|
||||
{
|
||||
public MapPath()
|
||||
{
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
MapPanel.InitMapElement(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,74 +7,73 @@ using Windows.UI.Xaml.Media;
|
|||
using Microsoft.UI.Xaml.Media;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
public partial class MapPolypoint : MapPath
|
||||
{
|
||||
public partial class MapPolypoint : MapPath
|
||||
protected void UpdateData(IEnumerable<Location> locations, bool closed)
|
||||
{
|
||||
protected void UpdateData(IEnumerable<Location> locations, bool closed)
|
||||
var figures = ((PathGeometry)Data).Figures;
|
||||
figures.Clear();
|
||||
|
||||
if (ParentMap != null && locations != null)
|
||||
{
|
||||
var figures = ((PathGeometry)Data).Figures;
|
||||
figures.Clear();
|
||||
var longitudeOffset = GetLongitudeOffset(locations);
|
||||
|
||||
if (ParentMap != null && locations != null)
|
||||
AddPolylinePoints(figures, locations, longitudeOffset, closed);
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateData(IEnumerable<IEnumerable<Location>> polygons)
|
||||
{
|
||||
var figures = ((PathGeometry)Data).Figures;
|
||||
figures.Clear();
|
||||
|
||||
if (ParentMap != null && polygons != null)
|
||||
{
|
||||
var longitudeOffset = GetLongitudeOffset(polygons.FirstOrDefault());
|
||||
|
||||
foreach (var locations in polygons)
|
||||
{
|
||||
var longitudeOffset = GetLongitudeOffset(locations);
|
||||
|
||||
AddPolylinePoints(figures, locations, longitudeOffset, closed);
|
||||
AddPolylinePoints(figures, locations, longitudeOffset, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateData(IEnumerable<IEnumerable<Location>> polygons)
|
||||
private void AddPolylinePoints(PathFigureCollection figures, IEnumerable<Location> locations, double longitudeOffset, bool closed)
|
||||
{
|
||||
var points = locations.Select(location => LocationToView(location, longitudeOffset));
|
||||
|
||||
if (points.Any())
|
||||
{
|
||||
var figures = ((PathGeometry)Data).Figures;
|
||||
figures.Clear();
|
||||
var start = points.First();
|
||||
var polyline = new PolyLineSegment();
|
||||
var minX = start.X;
|
||||
var maxX = start.X;
|
||||
var minY = start.Y;
|
||||
var maxY = start.Y;
|
||||
|
||||
if (ParentMap != null && polygons != null)
|
||||
foreach (var point in points.Skip(1))
|
||||
{
|
||||
var longitudeOffset = GetLongitudeOffset(polygons.FirstOrDefault());
|
||||
|
||||
foreach (var locations in polygons)
|
||||
{
|
||||
AddPolylinePoints(figures, locations, longitudeOffset, true);
|
||||
}
|
||||
polyline.Points.Add(point);
|
||||
minX = Math.Min(minX, point.X);
|
||||
maxX = Math.Max(maxX, point.X);
|
||||
minY = Math.Min(minY, point.Y);
|
||||
maxY = Math.Max(maxY, point.Y);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddPolylinePoints(PathFigureCollection figures, IEnumerable<Location> locations, double longitudeOffset, bool closed)
|
||||
{
|
||||
var points = locations.Select(location => LocationToView(location, longitudeOffset));
|
||||
|
||||
if (points.Any())
|
||||
if (maxX >= 0d && minX <= ParentMap.ActualWidth &&
|
||||
maxY >= 0d && minY <= ParentMap.ActualHeight)
|
||||
{
|
||||
var start = points.First();
|
||||
var polyline = new PolyLineSegment();
|
||||
var minX = start.X;
|
||||
var maxX = start.X;
|
||||
var minY = start.Y;
|
||||
var maxY = start.Y;
|
||||
|
||||
foreach (var point in points.Skip(1))
|
||||
var figure = new PathFigure
|
||||
{
|
||||
polyline.Points.Add(point);
|
||||
minX = Math.Min(minX, point.X);
|
||||
maxX = Math.Max(maxX, point.X);
|
||||
minY = Math.Min(minY, point.Y);
|
||||
maxY = Math.Max(maxY, point.Y);
|
||||
}
|
||||
StartPoint = start,
|
||||
IsClosed = closed,
|
||||
IsFilled = true
|
||||
};
|
||||
|
||||
if (maxX >= 0d && minX <= ParentMap.ActualWidth &&
|
||||
maxY >= 0d && minY <= ParentMap.ActualHeight)
|
||||
{
|
||||
var figure = new PathFigure
|
||||
{
|
||||
StartPoint = start,
|
||||
IsClosed = closed,
|
||||
IsFilled = true
|
||||
};
|
||||
|
||||
figure.Segments.Add(polyline);
|
||||
figures.Add(figure);
|
||||
}
|
||||
figure.Segments.Add(polyline);
|
||||
figures.Add(figure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,26 @@
|
|||
using System;
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
/// <summary>
|
||||
/// Replaces Windows.Foundation.Point for double floating point precision.
|
||||
/// </summary>
|
||||
public readonly struct Point(double x, double y) : IEquatable<Point>
|
||||
{
|
||||
/// <summary>
|
||||
/// Replaces Windows.Foundation.Point for double floating point precision.
|
||||
/// </summary>
|
||||
public readonly struct Point(double x, double y) : IEquatable<Point>
|
||||
{
|
||||
public double X => x;
|
||||
public double Y => y;
|
||||
public double X => x;
|
||||
public double Y => y;
|
||||
|
||||
public static implicit operator Windows.Foundation.Point(Point p) => new(p.X, p.Y);
|
||||
public static implicit operator Windows.Foundation.Point(Point p) => new(p.X, p.Y);
|
||||
|
||||
public static implicit operator Point(Windows.Foundation.Point p) => new(p.X, p.Y);
|
||||
public static implicit operator Point(Windows.Foundation.Point p) => new(p.X, p.Y);
|
||||
|
||||
public static bool operator ==(Point p1, Point p2) => p1.Equals(p2);
|
||||
public static bool operator ==(Point p1, Point p2) => p1.Equals(p2);
|
||||
|
||||
public static bool operator !=(Point p1, Point p2) => !p1.Equals(p2);
|
||||
public static bool operator !=(Point p1, Point p2) => !p1.Equals(p2);
|
||||
|
||||
public bool Equals(Point p) => X == p.X && Y == p.Y;
|
||||
public bool Equals(Point p) => X == p.X && Y == p.Y;
|
||||
|
||||
public override bool Equals(object obj) => obj is Point p && Equals(p);
|
||||
public override bool Equals(object obj) => obj is Point p && Equals(p);
|
||||
|
||||
public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode();
|
||||
}
|
||||
public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,63 +15,62 @@ using Microsoft.UI.Xaml.Media;
|
|||
using Microsoft.UI.Xaml.Shapes;
|
||||
#endif
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
[ContentProperty(Name = "Child")]
|
||||
public partial class PushpinBorder : UserControl
|
||||
{
|
||||
[ContentProperty(Name = "Child")]
|
||||
public partial class PushpinBorder : UserControl
|
||||
public static readonly DependencyProperty ArrowSizeProperty =
|
||||
DependencyPropertyHelper.Register<PushpinBorder, Size>(nameof(ArrowSize), new Size(10d, 20d),
|
||||
(border, oldValue, newValue) => border.SetBorderMargin());
|
||||
|
||||
public static readonly DependencyProperty BorderWidthProperty =
|
||||
DependencyPropertyHelper.Register<PushpinBorder, double>(nameof(BorderWidth), 0d,
|
||||
(border, oldValue, newValue) => border.SetBorderMargin());
|
||||
|
||||
private readonly Border border = new Border();
|
||||
|
||||
public PushpinBorder()
|
||||
{
|
||||
public static readonly DependencyProperty ArrowSizeProperty =
|
||||
DependencyPropertyHelper.Register<PushpinBorder, Size>(nameof(ArrowSize), new Size(10d, 20d),
|
||||
(border, oldValue, newValue) => border.SetBorderMargin());
|
||||
|
||||
public static readonly DependencyProperty BorderWidthProperty =
|
||||
DependencyPropertyHelper.Register<PushpinBorder, double>(nameof(BorderWidth), 0d,
|
||||
(border, oldValue, newValue) => border.SetBorderMargin());
|
||||
|
||||
private readonly Border border = new Border();
|
||||
|
||||
public PushpinBorder()
|
||||
var path = new Path
|
||||
{
|
||||
var path = new Path
|
||||
{
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
Stretch = Stretch.None
|
||||
};
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
VerticalAlignment = VerticalAlignment.Stretch,
|
||||
Stretch = Stretch.None
|
||||
};
|
||||
|
||||
path.SetBinding(Shape.FillProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Background)) });
|
||||
path.SetBinding(Shape.FillProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Background)) });
|
||||
|
||||
path.SetBinding(Shape.StrokeProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(BorderBrush)) });
|
||||
path.SetBinding(Shape.StrokeProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(BorderBrush)) });
|
||||
|
||||
path.SetBinding(Shape.StrokeThicknessProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(BorderWidth)) });
|
||||
path.SetBinding(Shape.StrokeThicknessProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(BorderWidth)) });
|
||||
|
||||
border.SetBinding(PaddingProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Padding)) });
|
||||
border.SetBinding(PaddingProperty,
|
||||
new Binding { Source = this, Path = new PropertyPath(nameof(Padding)) });
|
||||
|
||||
SetBorderMargin();
|
||||
SetBorderMargin();
|
||||
|
||||
var grid = new Grid();
|
||||
grid.Children.Add(path);
|
||||
grid.Children.Add(border);
|
||||
var grid = new Grid();
|
||||
grid.Children.Add(path);
|
||||
grid.Children.Add(border);
|
||||
|
||||
Content = grid;
|
||||
Content = grid;
|
||||
|
||||
SizeChanged += (_, _) => path.Data = BuildGeometry();
|
||||
}
|
||||
SizeChanged += (_, _) => path.Data = BuildGeometry();
|
||||
}
|
||||
|
||||
public UIElement Child
|
||||
{
|
||||
get => border.Child;
|
||||
set => border.Child = value;
|
||||
}
|
||||
public UIElement Child
|
||||
{
|
||||
get => border.Child;
|
||||
set => border.Child = value;
|
||||
}
|
||||
|
||||
private void SetBorderMargin()
|
||||
{
|
||||
border.Margin = new Thickness(
|
||||
BorderWidth, BorderWidth, BorderWidth, BorderWidth + ArrowSize.Height);
|
||||
}
|
||||
private void SetBorderMargin()
|
||||
{
|
||||
border.Margin = new Thickness(
|
||||
BorderWidth, BorderWidth, BorderWidth, BorderWidth + ArrowSize.Height);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,30 @@
|
|||
using System;
|
||||
|
||||
namespace MapControl
|
||||
namespace MapControl;
|
||||
|
||||
/// <summary>
|
||||
/// Replaces Windows.Foundation.Rect for double floating point precision.
|
||||
/// </summary>
|
||||
public readonly struct Rect(double x, double y, double width, double height) : IEquatable<Rect>
|
||||
{
|
||||
/// <summary>
|
||||
/// Replaces Windows.Foundation.Rect for double floating point precision.
|
||||
/// </summary>
|
||||
public readonly struct Rect(double x, double y, double width, double height) : IEquatable<Rect>
|
||||
{
|
||||
public double X => x;
|
||||
public double Y => y;
|
||||
public double Width => width;
|
||||
public double Height => height;
|
||||
public double X => x;
|
||||
public double Y => y;
|
||||
public double Width => width;
|
||||
public double Height => height;
|
||||
|
||||
public static implicit operator Windows.Foundation.Rect(Rect r) => new(r.X, r.Y, r.Width, r.Height);
|
||||
public static implicit operator Windows.Foundation.Rect(Rect r) => new(r.X, r.Y, r.Width, r.Height);
|
||||
|
||||
public static implicit operator Rect(Windows.Foundation.Rect r) => new(r.X, r.Y, r.Width, r.Height);
|
||||
public static implicit operator Rect(Windows.Foundation.Rect r) => new(r.X, r.Y, r.Width, r.Height);
|
||||
|
||||
public static bool operator ==(Rect r1, Rect r2) => r1.Equals(r2);
|
||||
public static bool operator ==(Rect r1, Rect r2) => r1.Equals(r2);
|
||||
|
||||
public static bool operator !=(Rect r1, Rect r2) => !r1.Equals(r2);
|
||||
public static bool operator !=(Rect r1, Rect r2) => !r1.Equals(r2);
|
||||
|
||||
public bool Equals(Rect r) => X == r.X && Y == r.Y && Width == r.Width && Height == r.Height;
|
||||
public bool Equals(Rect r) => X == r.X && Y == r.Y && Width == r.Width && Height == r.Height;
|
||||
|
||||
public override bool Equals(object obj) => obj is Rect r && Equals(r);
|
||||
public override bool Equals(object obj) => obj is Rect r && Equals(r);
|
||||
|
||||
public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode() ^ Width.GetHashCode() ^ Height.GetHashCode();
|
||||
public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode() ^ Width.GetHashCode() ^ Height.GetHashCode();
|
||||
|
||||
public bool Contains(Point p) => p.X >= X && p.X <= X + Width && p.Y >= Y && p.Y <= Y + Height;
|
||||
}
|
||||
public bool Contains(Point p) => p.X >= X && p.X <= X + Width && p.Y >= Y && p.Y <= Y + Height;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue