Setting Small Form Width Has Unexpected Results - c#

I am working on an application which requires sometimes to display an small error message on the desktop. To some reason which I could not identify yet, I was not able to create a window with a width smaller than 136px (but works fine with any larger widths).
I am running VS Community2019, v16.4.5; using .NET Framework 4.8 (.Net Framework 4.6.2 had the same result). Here's a small code example which reproduces my problem:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Diagnostics;
namespace TestWndSize
{
public static class Program
{
public static Form MyForm1;
public static int RqWidth = 120;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MyForm1 = new Form();
MyForm1.MouseEnter += MyForm1_MouseEnter;
MyForm1.SizeChanged += MyForm1_SizeChanged;
MyForm1.AutoSize = false;
MyForm1.FormBorderStyle = FormBorderStyle.None;
MyForm1.StartPosition = FormStartPosition.Manual;
MyForm1.Location = new Point(1400, 100);
Debug.WriteLine("--- Changing Width to " + RqWidth.ToString());
MyForm1.Size = new Size(RqWidth, 100);
Debug.WriteLine("--- Width should be now " + RqWidth.ToString()+"; is "+MyForm1.Width.ToString());
MyForm1.BackColor = Color.LightBlue;
Application.Run(MyForm1);
}
private static void MyForm1_SizeChanged(object sender, EventArgs e)
{
Debug.WriteLine("*** SizeChanged to Width=" + MyForm1.Width.ToString());
}
private static void MyForm1_MouseEnter(object sender, EventArgs e)
{
Debug.WriteLine("§§§ Current Width is " + MyForm1.Width.ToString());
}
}
}
The debug output is
*** SizeChanged to Width=300
--- Changing Width to 120
*** SizeChanged to Width=120
--- Width should be now 120; is 120
*** SizeChanged to Width=136 !!??!!
*** SizeChanged to Width=136 !!??!!
§§§ Current Width is 136 *Execution of MouseEnter*
The Width is changed to the requested value but then changed somehow (???) to 136px but only if the requested value is less than 136px.
As the debug output shows the SizeChanged event is executed two times for the undesired size but I do not see any reason why.
Does anybody have an idea what I am eventually missing?

Probably during the form rendering initialization something changes the size back to a minimum required size. (It seems like the missing borders are not considered).
However you can simply change your size in the Form Load event handler and then the new values are respected
private static void MyForm1_Load(object sender, EventArgs e)
{
Debug.WriteLine("*** FormLoad to Width=" + MyForm1.Width.ToString());
MyForm1.Size = new Size(RqWidth, 100);
}
Of course you need to manually add the event handler

Related

C# RLNET/OPENTK System.MissingMethodException during run-time

I am trying to make a small 2d game in c# using the RLNET library. The RLNET library has OpenTK as a dependency, so I added the latest versions of both RLNET and OpenTK to my project using the NuGet packages manager in Visual Studio. I was following along with a tutorial explaining how to work with these libraries. But, when I got to running the code I ran into a MissingMethodException at run-time.
The tutorial I was following along with is here: https://roguesharp.wordpress.com/2016/03/02/roguesharp-v3-tutorial-creating-the-project/
The Solution Explorer shows both libraries included in the project under the References dropdown. And I also included them in my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RLNET;
using OpenTK;
namespace Rouge_Game
{
class Program
{
private static readonly int _screenWidth = 100;
private static readonly int _screenHeight = 70;
private static RLRootConsole _rootConsole;
static void Main(string[] args)
{
// This must be the exact name of the bitmap font file we are using or it will error.
string fontFileName = "terminal8x8.png";
// The title will appear at the top of the console window
string consoleTitle = "RougeSharp V3 Tutorial - Level 1";
// Tell RLNet to use the bitmap font that we specified and that each tile is 8 x 8 pixels
_rootConsole = new RLRootConsole(fontFileName, _screenWidth, _screenHeight,
8, 8, 1f, consoleTitle);
// Set up a handler for RLNET's Update event
_rootConsole.Update += OnRootConsoleUpdate;
// Set up a handler for RLNET's Render event
_rootConsole.Render += OnRootConsoleRender;
// Begin RLNET's game loop
_rootConsole.Run();
}
// Event handler for RLNET's Update event
private static void OnRootConsoleUpdate(object sender, UpdateEventArgs e)
{
_rootConsole.Print(10, 10, "It worked!", RLColor.White);
}
// Event handler for RLNET's Render event
private static void OnRootConsoleRender(object sender, UpdateEventArgs e)
{
// Tell RLNET to draw the console that we set
_rootConsole.Draw();
}
}
}
The part of the code that has a run time error is this:
// Event handler for RLNET's Render event
private static void OnRootConsoleRender(object sender, UpdateEventArgs e)
{
// Tell RLNET to draw the console that we set
_rootConsole.Draw();
}
When I run the project it compiles with no errors and the program launches, but then throws this exception:
System.MissingMethodException
HResult=0x80131513
Message=Method not found: 'Void
OpenTK.Graphics.OpenGL.GL.BlendFunc(OpenTK.Graphics.OpenGL.BlendingFactorSrc, OpenTK.Graphics.OpenGL.BlendingFactorDest)'.
Source=RLNET
StackTrace:
at RLNET.RLRootConsole.Draw()
at Rouge_Game.Program.OnRootConsoleRender(Object sender, UpdateEventArgs e) in C:\Users\pjmul\source\repos\Rouge Game\Rouge Game\Program.cs:line 45
at RLNET.RLRootConsole.window_RenderFrame(Object sender, FrameEventArgs e)
at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
at OpenTK.GameWindow.OnRenderFrame(FrameEventArgs e)
at OpenTK.GameWindow.RaiseRenderFrame(Double elapsed, Double& timestamp)
at OpenTK.GameWindow.DispatchRenderFrame()
at OpenTK.GameWindow.Run(Double updates_per_second, Double frames_per_second)
at OpenTK.GameWindow.Run(Double updateRate)
at RLNET.RLRootConsole.Run(Double fps)
at Rouge_Game.Program.Main(String[] args) in
C:\Users\pjmul\source\repos\Rouge Game\Rouge Game\Program.cs:line 32
I don't understand this error however as when I use the object viewer built into Visual Studio I can find the "missing" function when I open OpenTK.dll. Any suggestions as to how I might fix this error are greatly appreciated. I would also like to thank anyone who takes the time to help me in advance.
There is something wrong with the 3.x branch of OpenTK. Try downgrading your OpenTK package back to 2.x and it will work.

Storyboard.Completed Event Handler Preventing Code From Executing

I am trying to create a simulation program that animates based on the user's input. I am running into an error when I try and create an eventhandler for mystoryboard.completed event. I have read numerous different API articles and forum posts on eventhandling and storyboards but I can't seem to find the cause of my error.
My code compiles and the window displays but anything after the line where I set up the eventhandler doesn't get executed. My MainWindow where I set everything up is shown below.
public MainWindow()
{
InitializeComponent();
titleTextBlock.Text = "MainWindow()";
//this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
mainSystem = new BalanceSystem(3);
leftBlock = new SystemComponents.Block(0, 100, 150, 100, mainSystem);
rightBlock = new SystemComponents.Block(1, 100, 150, 100, mainSystem);
balanceBeam = new SystemComponents.Bar(0, 0, 250, 150, 100, mainSystem);
mainSystem.addComponent(leftBlock, leftWeight);
mainSystem.addComponent(rightBlock, rightWeight);
mainSystem.addComponent(balanceBeam, balanceBar);
titleTextBlock.Text = "LOADED";
}
The constructor for "BalanceSystem" is when things start to go wrong. It steps into the constructor shown below:
public BalanceSystem(int count)
{
componentCount = count;
masterTimeline = new MovementTimeline(1);
}
After entering the constructor for "BalanceSystem" it moves on to the constructor for my custome class "MovementTimeline". The line that breaks everything is the creation and subscription of the eventhandler for masterStoryboard.Completed.
class MovementTimeline
{
private Storyboard masterStoryboard;
private Duration systemDuration;
public MovementTimeline(int totalTime)
{
systemDuration = new Duration(TimeSpan.FromSeconds(totalTime));
masterStoryboard.Completed += new EventHandler(masterStoryboard_Completed);
}
void masterStoryboard_Completed(object sender, EventArgs e)
{
masterStoryboard.Children.Clear();
//masterStoryboard.Completed -= masterStoryboard_Completed;
}
}
Once the compiler or program hits the line where the new EventHandler is created it stops executing the rest of my code and loads the window as is. I cannot for the life of me figure out why this is happening.
it looks to me like you are adding an eventhandler without ever creating a StoryBoard object

Background image shows, but pen lines don't

I set a background of a picturebox as an image, which is fine.
I try to draw pen lines over the background image, but the lines do not appear on top of the image
This should happen: (I changed the code and not a clue what I changed to get this to happen, but this is without resetting the picturebox)
The picturebox is updated every 2000ms to show the flag signals, but can't for the life of me get the lines to appear.
Here are the bits of code:
lblSelectedChar.Text = inputchar.ToString();
picSemaphore.BackgroundImage = semaphore.Properties.Resources.human;
leftHandDown();
rightHandLow();
The leftHandDown() and rightHandLow() methods draw the lines, but I think they are drawn behind the image. I would like them drawn in front. Any idea how I would do this?
private void leftHandDown()
{
lblLeftHand.Hide();
display.DrawLine(penLeftArm, centXCoord, centYCoord, LHDownXCoord, LHDownYCoord);
lblLeftHand.Top = LHDownYCoord + 74;
lblLeftHand.Left = LHDownXCoord + 13;
lblLeftHand.Show();
lblLeftHand.Update();
}
Also, when the label is moved, it leaves a white space where it last was. Any idea how to stop this happening?
As LarsTech suggested, use the Paint() event of your PictureBox to draw the lines with the supplied Graphics via the e.Graphics value. You'd call picSemaphore.Refresh(); to make the lines update.
Here's a quick example to give you the basic idea:
public partial class Form1 : Form
{
private bool displayLeftArmLine = false;
private bool displayRightArmLine = false;
public Form1()
{
InitializeComponent();
picSemaphore.Paint += new PaintEventHandler(picSemaphore_Paint);
}
void picSemaphore_Paint(object sender, PaintEventArgs e)
{
if (displayLeftArmLine)
{
e.Graphics.DrawLine(penLeftArm, centXCoord, centYCoord, LHDownXCoord, LHDownYCoord);
}
if (displayRightArmLine)
{
e.Graphics.DrawLine(penRightArm, centXCoord, centYCoord, RHDownXCoord, RHDownYCoord);
}
}
private void leftHandDown()
{
lblLeftHand.Hide();
lblLeftHand.Top = LHDownYCoord + 74;
lblLeftHand.Left = LHDownXCoord + 13;
lblLeftHand.Show();
lblLeftHand.Update();
displayLeftArmLine = true;
picSemaphore.Refresh(); // force Paint() event for "picSemaphore" to fire
}
}

How to slow down animated gif

I have a WinForms app that displays an animated gif in the simplest possible way - there is a PictureBox that loads the .gif directly.
The code generated by the WinForms designer looks like this:
//
// pictureBoxHomer
//
this.pictureBoxHomer.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
this.pictureBoxHomer.Dock = System.Windows.Forms.DockStyle.Fill;
this.pictureBoxHomer.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxHomer.Image")));
this.pictureBoxHomer.Location = new System.Drawing.Point(3, 3);
this.pictureBoxHomer.Name = "pictureBoxHomer";
this.pictureBoxHomer.Size = new System.Drawing.Size(905, 321);
this.pictureBoxHomer.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
this.pictureBoxHomer.TabIndex = 0;
this.pictureBoxHomer.TabStop = false;
The image is, of course, this: http://media.tumblr.com/tumblr_m1di1xvwTe1qz97bf.gif
Problem: while this animated gif displays wondrously in the browser, it is running way too fast in the WinForms app, which is not as happy as needed. So:
Question: is there a way to slow down an animated gif in a WinForms app?
I believe the answer is rather image-related than C#. If you edit that specific image in a tool like GIMP and take a look at the layers, you'll see it's a composition of 10 layers (frames) but no "delay time" between them is set - it has (0ms) in layer's attribute. You can edit layer's attribute and change it by right-clicking on it and selecting that option in menu. Of course, at the end you have to export your new image and save it as a GIF, selecting "animated" in options.
I believe in this case (when no delay time between frames is specified) web browser and C# PicutureBox force their own,different, default values. So, if you put a delay let say 100ms, like described here in step 3, you'll make the animation slow down.
For future reference, it is possible to override the delay time of a GIF in a picture box. Here is a rough example:
public partial class Form1 : Form
{
private FrameDimension dimension;
private int frameCount;
private int indexToPaint;
private Timer timer = new Timer();
public Form1()
{
InitializeComponent();
dimension = new FrameDimension(this.pictureBox1.Image.FrameDimensionsList[0]);
frameCount = this.pictureBox1.Image.GetFrameCount(dimension);
this.pictureBox1.Paint += new PaintEventHandler(pictureBox1_Paint);
timer.Interval = 100;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
indexToPaint++;
if(indexToPaint >= frameCount)
{
indexToPaint = 0;
}
}
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
this.pictureBox1.Image.SelectActiveFrame(dimension, indexToPaint);
e.Graphics.DrawImage(this.pictureBox1.Image, Point.Empty);
}
}

Windows Forms Opacity After Shown- C#

I am tryig to fade-in a windows form using c# but it doesnt seem to work after I have shown the form. Is it possible to change the forms opacity after Ive shown it?
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
namespace ToolStrip
{
public partial class Form1 : Form
{
Form ToolForm = new ToolForm();
Form PropForm = new PropertyGrid();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ToolForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
ToolForm.Owner = this;
ToolForm.Show();
ToolForm.Location = new Point(50, 50);
}
private void button2_Click(object sender, EventArgs e)
{
PropForm.FormBorderStyle = FormBorderStyle.FixedToolWindow;
PropForm.Owner = this;
PropForm.Show();
PropForm.Location = new Point(50, 50);
System.Timers.Timer aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
PropForm.Opacity = PropForm.Opacity - 0.25;
Console.WriteLine(PropForm.Opacity);
}
}
}
because you r using System.Timers.Timer which is a multithread timer, in it's OnTimedEvent() it calls control created by another thread, which cause exception.
If you use System.Windows.Forms.Timer, it will work. i tested.
Using your code (and creating the other necessary Form classes), I get a cross-threading exception the first time the timer fires and the event handler is called, as Benny suggests.
Making changes to your code to check InvokeRequired in the timer event handler, and use Invoke if necessary to change PropForm.Opacity, results in the opacity changing after the form is shown, as required.
Note that you probably want to start with an Opacity of 0, and increase it gradually - otherwise your form will start off completely solid and gradually fade out
I will mention in passing that Opacity will have no effect on some versions of Windows, though you say you have Opacity effects working elsewhere, so it shouldn't be that in this case.
Ive gotten it to work without timers:
int Loop = 0;
for (Loop = 100; Loop >= 5; Loop -= 10)
{
this.PropForm.Opacity = Loop / 95.0;
this.PropForm .Refresh();
System.Threading.Thread.Sleep(100);
}
but i cant seem to change this example to fade-in instead of out.

Categories