System.MissingMethodException: Method not found - windows-10-universal

On Windows 10 I'm developing a universal app. I have a project targeting from build 10240 to the Anniversary Edition(14393). I'm using the nuget Win2d.uwp and whilst developing the app in debug and release everything works fine. I can generate a Store package, deploy it through HockeyApp and it work just fine. When I upload it to the store, and wait until it has been approved, download it, and start to use it, as soon as I draw a shadow in some controls using Win2d.uwp
and this code:
public static void InitializeDropShadow(UIElement shadowHost, UIElement shadowTarget, Color color, ShadowPosition position)
{
var offset = GetOffset(position);
var hostVisual = ElementCompositionPreview.GetElementVisual(shadowHost);
var compositor = hostVisual.Compositor;
// Create a drop shadow
var dropShadow = compositor.CreateDropShadow();
dropShadow.Color = Color.FromArgb(color.A, color.B, color.G, color.R);
dropShadow.BlurRadius = 25.0f;
dropShadow.Offset = offset;
// Associate the shape of the shadow with the shape of the target element
// dropShadow.Mask = shadowTarget.GetAlphaMask();
// Create a Visual to hold the shadow
var shadowVisual = compositor.CreateSpriteVisual();
shadowVisual.Shadow = dropShadow;
// Add the shadow as a child of the host in the visual tree
ElementCompositionPreview.SetElementChildVisual(shadowHost, shadowVisual);
// Make sure size of shadow host and shadow visual always stay in sync
var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size");
bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);
shadowVisual.StartAnimation("Size", bindSizeAnimation);
}
private static Vector3 GetOffset(ShadowPosition position)
{
var result = new Vector3();
switch (position)
{
case ShadowPosition.Center:
result = new Vector3(0, 0, 0);
break;
case ShadowPosition.Top:
result = new Vector3(0, -SHADOW_OFFSET, 0);
break;
case ShadowPosition.Left:
result = new Vector3(-SHADOW_OFFSET, 0, 0);
break;
case ShadowPosition.Right:
result = new Vector3(SHADOW_OFFSET, 0, 0);
break;
case ShadowPosition.Bottom:
result = new Vector3(0, SHADOW_OFFSET, 0);
break;
case ShadowPosition.TopLeft:
result = new Vector3(-SHADOW_OFFSET, -SHADOW_OFFSET, 0);
break;
case ShadowPosition.BottomRight:
result = new Vector3(SHADOW_OFFSET, SHADOW_OFFSET, 0);
break;
default:
result = new Vector3(0, 0, 0);
break;
}
return result;
}
it breaks miserably and throw this exception breaking the whole app:
System.MissingMethodException: Method not found: 'Void Windows.UI.Composition.DropShadow.put_Offset(System.Numerics.Vector3)'.
It only happens from the STORE version and I'm not compiling it with .Net Native. Any Ideas?

Related

Form design via Region property in winform getting removed

I have customized winform-design using region property as follows,
Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(0, 0, varPassedInConstructor * 9, Height, 10, 10));
And here calling winform through following code in a new thread
new Thread(new ThreadStart(() => {
toast toast = new toast(message);
toast.Show(nativeWindow);
toast.Refresh();
Thread.Sleep(3000);
while (toast.Opacity > 0)
{
toast.Opacity -= 0.04;
Thread.Sleep(100);
}
toast.Close();
toast.Dispose();
})).Start();
Everything goes well, form is displayed properly initially, but before closing all of sudden, changes applied via Region gets disappeared and form appears like the one that is at design time.
Image one, When initially form displayed,
Image two, just before form is getting closed,
I tried lots of diff thing, I am not getting what exactly problem is, so all help will be appreciated.
Finally, I got the fix, instead of using CreateRoundRectRgn from GDI32 used a GraphicsPath approach as follows,
private void SetRegion()
{
var GP = RoundedRect(this.ClientRectangle, 5);
this.Region = new Region(GP);
}
And here is code for RoundRect function (Credit goes to https://stackoverflow.com/a/33853557/3531672),
public static GraphicsPath RoundedRect(Rectangle bounds, int radius)
{
int diameter = radius * 2;
Size size = new Size(diameter, diameter);
Rectangle arc = new Rectangle(bounds.Location, size);
GraphicsPath path = new GraphicsPath();
if (radius == 0)
{
path.AddRectangle(bounds);
return path;
}
// top left arc
path.AddArc(arc, 180, 90);
// top right arc
arc.X = bounds.Right - diameter;
path.AddArc(arc, 270, 90);
// bottom right arc
arc.Y = bounds.Bottom - diameter;
path.AddArc(arc, 0, 90);
// bottom left arc
arc.X = bounds.Left;
path.AddArc(arc, 90, 90);
path.CloseFigure();
return path;
}
then in constructor simply had set size of form itself and called SetRegion defined above,
this.Width = toastMessage.Length * 9;
SetRegion();
Please note additionally, I would recommend to override OnSizeChanged and simply call SetRegion in it.

GlyphRun and the exact position of the cursor (WPF)

I would like to draw a text exactly in the place of the mouse cursor.
Because I need very high performance, I would like to use GlyphRun.
Everything works almost well, but unfortunately my text is slightly below the cursor.
Can someone help me modify this method to eliminate this vertical shift?
Now it looks like this
My expectation (the text touches the cursor)
My code:
void MyDrawer_MouseMove(object sender, MouseEventArgs e)
{
Test1();
}
void Test1()
{
MyDrawer.DeleteVisual(Dv);
MyDrawer.Cursor = Cursors.Cross;
string text = "Hello Word";
double size = 40;
Dv = new DrawingVisual();
using (var dc = Dv.RenderOpen())
{
Typeface typeface = new Typeface("Arial");
if (typeface.TryGetGlyphTypeface(out GlyphTypeface glyphTypeface))
{
ushort[] glyphIndexes = new ushort[text.Length];
double[] advanceWidths = new double[text.Length];
for (int i = 0; i < text.Length; i++)
{
ushort glyphIndex = glyphTypeface.CharacterToGlyphMap[text[i]];
glyphIndexes[i] = glyphIndex;
double width = glyphTypeface.AdvanceWidths[glyphIndex] * size;
advanceWidths[i] = width;
}
Point origin = Mouse.GetPosition(MyDrawer);
//Move text belowe the cursor
origin = new Point { X = origin.X, Y = origin.Y + (glyphTypeface.Baseline * size) };
GlyphRun glyphRun = new GlyphRun(glyphTypeface, 0, false, size,
glyphIndexes, origin, advanceWidths, null, null, null, null,
null, null);
dc.DrawGlyphRun(Brushes.Red, glyphRun);
MyDrawer.AddVisual(Dv);
}
}
}
Of course, this is only a test, in practice it will not affect the cursor, but the indicated point and text will be much more than in this example.
I bumped into this question in search for the same issue.
Glyph content (GlyphRun for that matter) is wrapped in a black-box.
The black-box contain a bit of padding on the top.
Like so : Rought skecth of the glyph run
// To get the box size
var blackBoxHeight = glyphTypeface.Height * fontSize;
// To get the actual character height
var characterHeight = glyphTypeface.Baseline * fontSize;
// To get the padding inside the black box
var blackBoxPadding = blackBoxHeight - characterHeight;
// set the point to draw a little bit up (skip the padding)
origin.Y -= blackBoxPadding;
// Create the glyph
var run = new GlyphRun
(
glyphTypeface: glyphTypeface,
bidiLevel: 0,
isSideways: false,
renderingEmSize: fontSize,
pixelsPerDip: 1.0f,
glyphIndices: indices,
baselineOrigin: origin, /* The point containing the padding offset */
advanceWidths: widths,
glyphOffsets: null,
characters: null,
deviceFontName: null,
clusterMap: null,
caretStops: null,
language: null
);
The other answer lacks of some details.
There is actually no magic or unreasoned paddings. The picture shows relations of glyphTypeface height parameters to the displayed GlyphRun.
The code that calculates corresponding line vertical positions based on the GlyphRun origin Y is shown below:
var baseLine = origin.Y;
var boxTop = baseLine - glyphTypeface.Baseline * FontSize;
var boxBottom = boxTop + glyphTypeface.Height * FontSize;
var capsHeight = baseLine - glyphTypeface.CapsHeight * FontSize;
var lowHeight = baseLine - glyphTypeface.XHeight * FontSize;

Animation in WPF showing images one by one

I would like to create something like this
animateit.net/categories.php?cat_id=218&page=11 -
Frog Gets Spider Animated Gif ...
I have a frog image, a tongue image and a bug image separate, but not able to put it in animation using WPF.
Any ideas on how to do it?
If you'd like to animate an image in the code-behind, you'll set it up something like this:
MyImage is where you're displaying the "gif".
FrogImage is the image of just the frog.
TongueImage is the image of the tongue coming out.
BugImage is the image of the frog with the bug.
First, initialize a timer like this, perhaps in 'MainWindow()' or at the global level:
DispatcherTimer tmrBlinkImage = new DispatcherTimer()
{ IsEnabled = false, Interval = TimeSpan.FromMilliseconds(500) };
tmrBlinkImage.Tick += new EventHandler(tmrBlinkImage_Tick);
public int _ImageBlinkIndex = 0;
Then, set up the event handler like this:
private void tmrBlinkImage_Tick(object sender, EventArgs e)
{
try
{
if (null == MyImage)
return;
if (MyImage.IsDisposed)
return;
switch (_ImageBlinkIndex)
{
case 0:
if (MyImage.Source != FrogImage)
MyImage.Source = FrogImage;
_ImageBlinkIndex++;
break;
case 1:
if (MyImage.Source != TongueImage)
MyImage.Source = TongueImage;
_ImageBlinkIndex++;
break;
case 2:
if (MyImage.Source != BugImage)
MyImage.Source = BugImage;
_ImageBlinkIndex = 0;
break;
default:
_ImageBlinkIndex = 0;
break;
}
}
catch (Exception ex)
{
tmrBlinkImage.Stop();
//woops....
}
}
This will cycle through the images and update the frame every half second. Adjust the values as you best see fit.

Any way to access mouse Raw Input from WPF?

I'm currently using a global mouse hook to make an app appear if it the mouse cursor reaches the corner of the screen. I just read about the existence of Raw Input and from what I understand, this is a more robust method as a slowdown in my hook will not impact the overall system.
Problem is I can't find any examples anywhere about using Raw Input in WPF.
Closest I got was SlimDX with the following code:
Device.RegisterDevice(UsagePage.Generic, UsageId.Mouse,
DeviceFlags.None);
Device.MouseInput += new EventHandler<MouseInputEventArgs>(mouse_MouseInput);
But that does not seem to work in WPF, only winforms.
Those DeviceFlags.None need to be InputSink to capture input in the background. SharpDX flags there are actually a wrapper for the RAWINPUTDEVICEFLAGS (InputSink = 0x00000100).
In WPF, you want to 1) override OnSourceInitialized and 2) hook WndProc there. While the window pointer is available you need to define the RAWINPUTDEVICE's you want to watch, flag InputSink.
It will look something like
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
var win = source.Handle;
RAWINPUTDEVICE[] rid = new RAWINPUTDEVICE[2];
rid[0].UsagePage = (HIDUsagePage)0x01;
rid[0].Usage = (HIDUsage)0x05; // adds game pad
rid[0].Flags = RawInputDeviceFlags.InputSink; // accept input in background
rid[0].WindowHandle = win;
rid[1].UsagePage = (HIDUsagePage)0x01;
rid[1].Usage = (HIDUsage)0x04; // adds joystick
rid[1].Flags = RawInputDeviceFlags.InputSink; // accept input in background
rid[1].WindowHandle = win;
if (RegisterRawInputDevices(rid, (uint)rid.Length, (uint)Marshal.SizeOf(rid[0])) == false)
{
var err = Marshal.GetLastWin32Error();
if (err > 0)
{
throw new Win32Exception($"GetLastWin32Error: {err}");
}
else
{
throw new Win32Exception("RegisterRawInputDevices failed with error code 0. Parameter count mis-match?");
}
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_INPUT:
{
System.Diagnostics.Debug.WriteLine("Received WndProc.WM_INPUT");
DoTheThing(lParam);
}
break;
}
return hwnd;
}

Determine if an open WPF window is visible on any monitor

Is there a way to determine if an open WPF window is currently visible in any of the desktop's connected monitors? By visible I mean that the window's bounds rectangle intersects with the desktop rectangle of any of the monitors.
I need this functionality to determine if a window needs to be repositioned because the monitor configuration (working areas bounds, monitor count) changed between restarts of my application (which saves window positions).
I have come up with the code below and it seems to work, but it has several problems:
I need to reference windows forms.
I need the desktop's DPI settings and transform the windows forms actual pixels to WPF virtual pixels.
I need an acutal Visual instance that already has been rendered to perform the transformation.
Do you know of a solution that gets rid of some or all of the 3 issues above?
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Media;
internal static class Desktop
{
private static Size dpiFactor = new Size(1.0, 1.0);
private static bool isInitialized;
public static IEnumerable<Rect> WorkingAreas
{
get
{
return
Screen.AllScreens.Select(
screen =>
new Rect(
screen.WorkingArea.Left * dpiFactor.Width,
screen.WorkingArea.Top * dpiFactor.Height,
screen.WorkingArea.Width * dpiFactor.Width,
screen.WorkingArea.Height * dpiFactor.Height));
}
}
public static void TryInitialize(Visual visual)
{
if (isInitialized)
{
return;
}
var ps = PresentationSource.FromVisual(visual);
if (ps == null)
{
return;
}
var ct = ps.CompositionTarget;
if (ct == null)
{
return;
}
var m = ct.TransformToDevice;
dpiFactor = new Size(m.M11, m.M22);
isInitialized = true;
}
}
Usage of the (initialized) Desktop class:
private bool IsLocationValid(Rect windowRectangle)
{
foreach (var workingArea in Desktop.WorkingAreas)
{
var intersection = Rect.Intersect(windowRectangle, workingArea);
var minVisible = new Size(10.0, 10.0);
if (intersection.Width >= minVisible.Width &&
intersection.Height >= minVisible.Height)
{
return true;
}
}
return false;
}
Update
Using the virtual screen (SystemParameters.VirtualScreen*) does not work because when using multiple monitors the "desktop" is not a simple rectangle. It might be a polygon. There will be blind spots in the virtual screen because
the connected screens can have different resolutions
you can configure the position of each screen.
The code we use to do something similar uses information from SystemParameters, in particular SystemParameter.VirtualScreenLeft, Top, Width and Height.
If we have a saved Location and Size then we determine if the window is out of bounds like this:
bool outOfBounds =
(location.X <= SystemParameters.VirtualScreenLeft - size.Width) ||
(location.Y <= SystemParameters.VirtualScreenTop - size.Height) ||
(SystemParameters.VirtualScreenLeft +
SystemParameters.VirtualScreenWidth <= location.X) ||
(SystemParameters.VirtualScreenTop +
SystemParameters.VirtualScreenHeight <= location.Y);
I use this code snipped in my WPF project on startup; it's written in vb.net:
If My.Settings.RememberWindowPositionAndSize Then
If My.Settings.winMainWinState > 2 Then My.Settings.winMainWinState = WindowState.Normal
If My.Settings.winMainWinState = WindowState.Minimized Then My.Settings.winMainWinState = WindowState.Normal
Me.WindowState = My.Settings.winMainWinState
If My.Settings.winMainWinState = WindowState.Normal Then
Dim winBounds As New System.Drawing.Rectangle(CInt(My.Settings.winMainPosX), CInt(My.Settings.winMainPosY),
CInt(My.Settings.winMainSizeB), CInt(My.Settings.winMainSizeH))
For Each scr As System.Windows.Forms.Screen In System.Windows.Forms.Screen.AllScreens
If winBounds.IntersectsWith(scr.Bounds) Then
Me.Width = My.Settings.winMainSizeB
Me.Height = My.Settings.winMainSizeH
Me.Top = My.Settings.winMainPosY
Me.Left = My.Settings.winMainPosX
Exit For
End If
Next
End If
End If
and here is same (converted) code in C#
if (My.Settings.RememberWindowPositionAndSize) {
if (My.Settings.winMainWinState > 2)
My.Settings.winMainWinState = WindowState.Normal;
if (My.Settings.winMainWinState == WindowState.Minimized)
My.Settings.winMainWinState = WindowState.Normal;
this.WindowState = My.Settings.winMainWinState;
if (My.Settings.winMainWinState == WindowState.Normal) {
System.Drawing.Rectangle winBounds = new System.Drawing.Rectangle(Convert.ToInt32(My.Settings.winMainPosX), Convert.ToInt32(My.Settings.winMainPosY), Convert.ToInt32(My.Settings.winMainSizeB), Convert.ToInt32(My.Settings.winMainSizeH));
foreach (System.Windows.Forms.Screen scr in System.Windows.Forms.Screen.AllScreens) {
if (winBounds.IntersectsWith(scr.Bounds)) {
this.Width = My.Settings.winMainSizeB;
this.Height = My.Settings.winMainSizeH;
this.Top = My.Settings.winMainPosY;
this.Left = My.Settings.winMainPosX;
break;
}
}
}
}
This code checks if a window top left corner is inside the Virtual Screen box (the rectangle that includes all the available screens). It also takes care of multimonitor set ups where coordinates can be negative, for example primary monitor on the right or on the bottom.
bool valid_position =
SystemParameters.VirtualScreenLeft <= saved_location.X &&
(SystemParameters.VirtualScreenLeft + SystemParameters.VirtualScreenWidth) >= saved_location.X &&
SystemParameters.VirtualScreenTop <= saved_location.Y &&
(SystemParameters.VirtualScreenTop + SystemParameters.VirtualScreenHeight) >= saved_location.Y;

Resources