C++/CLI Graphics->DrawArc(DrawLine) in loop clear - winforms

Problem: I have collection of CircleSegment, when i trying to draw them all at PictureBox, i receive only last CircleSegment from collection on pictureBox. Why?
ref class CircleSegment
{
public:
array<double>^ massive;
Pen^ Blackpen;
int index;
CircleSegment^ SegmentCircleCollection::operator [] ( const int a )
{
return this->Alfa[a];
}
....
}
ref class SegmentCircleCollection
{
public:
Generic::List<CircleSegment^> ^Alfa;
...
}
private: System::Void pictureBox1_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e)
{
//Where SegmentCircleCollection^ myCollection;
for each(CircleSegment^ Selected in myCollection->Alfa)
{
e->Graphics->DrawLine(Selected->Blackpen,(int)Selected->massive[6],(int)Selected->massive[7],(int)Selected->massive[8],(int)Selected->massive[9]);
e->Graphics->DrawArc(Selected->Blackpen,(int)Selected->massive[0],(int)Selected->massive[1],(int)Selected->massive[2],(int)Selected->massive[3],(int)Selected->massive[4],(int)Selected->massive[5]);
}
...
}

Related

How to make UserControl initialization only once after property is set

Code:
public partial class MyControl : UserControl
{
int size = 8;
public int Size
{
get { return size; }
set { size = value; Initialize(); }
}
public MyControl()
{
InitializeComponent();
Initialize();
}
void Initialize()
{
// ...
}
}
XAML:
<local:MyControl"/>
or:
<local:MyControl Size="10"/>
When Size property is set in XAML, Initialize is called twice. If I remove Initialize call from InitializeComponent, Initialize is called once from Size setter. But in this case, if Size is not set in XAML, Initialize is not called at all.
Is there any way to write initialization function, which is executed once, after all control properties (if any) are set from XAML?
You may call the Initialize method in a Loaded event handler:
public partial class MyControl : UserControl
{
int size = 8;
public int Size
{
get { return size; }
set { size = value; }
}
public MyControl()
{
InitializeComponent();
Loaded += (o, e) => Initialize();
}
void Initialize()
{
// ...
}
}
In order to make sure the Initialize() method is called only once, although Loaded may be fired more than once, detach the event handler like this:
public MyControl()
{
InitializeComponent();
Loaded += MyControlLoaded;
}
private void MyControlLoaded(object sender, RoutedEventArgs e)
{
Loaded -= MyControlLoaded;
Initialize();
}

Transparency in animator control

I'm writing a user control for animation.
Its uses an internal ImageList to store the animation images and paint one after the other in a loop.
This is the whole code:
public partial class Animator : UserControl
{
public event EventHandler OnLoopElapsed = delegate { };
private ImageList imageList = new ImageList();
private Timer timer;
private bool looping = true;
private int index;
private Image newImage;
private Image oldImage;
public Animator()
{
InitializeComponent();
base.DoubleBuffered = true;
timer = new Timer();
timer.Tick += timer_Tick;
timer.Interval = 50;
}
public bool Animate
{
get { return timer.Enabled; }
set
{
index = 0;
timer.Enabled = value;
}
}
public int CurrentIndex
{
get { return index; }
set { index = value; }
}
public ImageList ImageList
{
set
{
imageList = value;
Invalidate();
index = 0;
}
get { return imageList; }
}
public bool Looping
{
get { return looping; }
set { looping = value; }
}
public int Interval
{
get { return timer.Interval; }
set { timer.Interval = value; }
}
private void timer_Tick(object sender, EventArgs e)
{
if (imageList.Images.Count == 0)
return;
Invalidate(true);
index++;
if (index >= imageList.Images.Count)
{
if (looping)
index = 0;
else
timer.Stop();
OnLoopElapsed(this, EventArgs.Empty);
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
if (oldImage != null)
e.Graphics.DrawImage(oldImage, ClientRectangle);
else
e.Graphics.Clear(BackColor);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
if (imageList.Images.Count > 0)
{
newImage = imageList.Images[index];
g.DrawImage(newImage, ClientRectangle);
oldImage = newImage;
}
else
{
e.Graphics.Clear(BackColor);
}
}
}
The animation seems very nice and smooth,
but the problem is that its surrounding rectangle is painted black.
What am I missing here?
I've seen very smooth transparent animation done here in WPF,
I've placed some label behind it and they are seen thru the rotating wheel as I hoped.
But I don't know WPF well enough to build such a control in WPF.
Any idea or WPF sample code will be appreciated.
This was solved by removing this line from the constructor:
base.DoubleBuffered = true;
Now the control is fully transparent, even while changing its images.

Find Visible Child Window

I want to search any visible child window with this simple code but Message keep saying Window not found. Can anyone has an idea about searching visible child window in main window?
Here's the code:
private HomeWindow NewHomeWindow = new HomeWindow();
string ReturnWindowName;
private void btnhome_Click(object sender, RoutedEventArgs e)
{
ReturnWindowName = "NewHomeWindow";
NewHomeWindow.Owner = this;
NewHomeWindow.Show();
}
private void btnsearchwindow_Click(object sender, RoutedEventArgs e)
{
ChangeWindow();
}
public void ChangeWindow()
{
Window mySearchWindow = (Window)this.FindName(ReturnWindowName);
if (mySearchWindow != null)
{
MessageBox.Show("Window Found");
}
else
{
MessageBox.Show("Window Not Found");
}
}
Since you are assigning ownership to your Windows, can you make use of the OwnedWindows Property to iterate through the Parents Owned Windows to find the one you are looking for? In further looking at your code you are creating a class level variable named NewHomeWindow you are not assigning anything to the Name Property, FindName is searching for a child element, not an owned window. If you add a Name to your Window and use something like this you should be able to locate it.
public partial class MainWindow : Window
{
private HomeWindow NewHomeWindow = new HomeWindow();
string ReturnWindowName;
public MainWindow()
{
InitializeComponent();
NewHomeWindow.Name="NewHomeWindow";
}
private void btnhome_Click(object sender, RoutedEventArgs e)
{
ReturnWindowName = "NewHomeWindow";
NewHomeWindow.Owner = this;
NewHomeWindow.Show();
}
private void btnsearchwindow_Click(object sender, RoutedEventArgs e)
{
ChangeWindow();
}
public void ChangeWindow()
{
foreach (Window w in this.OwnedWindows)
{
if (w.Name == ReturnWindowName)
{
MessageBox.Show("Window Found");
}
else
{
MessageBox.Show("Window Not Found");
}
}
}
}
I'm not entirely sure of your question, but I think you're wanting to find the visual child of a control?
This is a helper function that I use frequently..
public IEnumerable<T> FindVisualChildren<T>( DependencyObject depObj ) where T : DependencyObject
{
if( depObj != null )
{
for( int i = 0; i < VisualTreeHelper.GetChildrenCount( depObj ); i++ )
{
DependencyObject child = VisualTreeHelper.GetChild( depObj, i );
if( child != null && child is T )
{
yield return (T)child;
}
foreach( T childOfChild in FindVisualChildren<T>( child ) )
{
yield return childOfChild;
}
}
}
}
In your example, you'd look for a window:
foreach (var window in FindVisualChildren<Window>(this))
{
if (window.ReturnWindowName == <insertNameHere>)
return window;
}
From there, you can loop through the windows found and match the name.

Updating UI from a background thread which is called in a loop in main UI when the thread finishes

I have a WinForms application that is calling a business class method that performs some heavy duty action taking about 5 seconds for each call. The main form calls this method in a loop. This loop can run from 10 times to maybe up to 10 thousand times.
The WinForms application sends a parameter to the business class and has an area to display the time taken for each method call and what the value returned by the method. How do I inform my main window and update a text area in the main winform with what the method has returned for each call?
Currently the data comes all at once after all the threads have finished. Is there a way to update the UI for all the iterations of the loop once the each call is done? I don't mind if it is done sequentially also.
The FORM
HeavyDutyClass hd;
public Form1()
{
InitializeComponent();
hd = new HeavyDutyClass();
}
//BUTTON CLICK
private void Start_Click(object sender, EventArgs e)
{
int filecount = 5000; //BAD - opening 5000 threads! Any other approach?
hd.FileProcessed += new EventHandler(hd_FileProcessed);
var threads = new Thread[filecount];
for (int i = 0; i < filecount; i++)
{
threads[i] = new Thread(() => { hd.LongRunningMethod(); });
threads[i].Start();
}
}
//BUSINESS CLASS EVENT THAT FIRES WHEN BUSINESS METHOD COMPELTES
void hd_FileProcessed(object sender, EventArgs e)
{
if (dgv.InvokeRequired)
{
dgv.Invoke((MethodInvoker)delegate { UpdateGrid(); });
}
}
private void UpdateGrid()
{
dgv.Rows.Add(1);
int i = dgv.Rows.Count;
dgv.Rows [ i-1].Selected = true;
dgv.FirstDisplayedScrollingRowIndex = i - 1;
}
The business HeavyDuty class
public event EventHandler FileProcessed;
public HeavyDutyClass()
{
}
protected virtual void OnMyEvent(EventArgs e)
{
if (FileProcessed != null)
{
FileProcessed(this, e);
}
}
public bool LongRunningMethod()
{
for (double i = 0; i < 199990000; i++)
{
//time consuming loop
}
OnMyEvent(EventArgs.Empty);
return true;
}
Add a Winforms Project, Drop a Label Control on the Form , Copy-Paste this code and Hit F5
[EDIT]: Updated with the business class comment from the user
NB: My form class is named Form3. You may have to change your Program.cs or vice-versa.
using System.ComponentModel;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class BusinessClass
{
public int MyFunction(int input)
{
return input+10;
}
}
public partial class Form3 : Form
{
private BackgroundWorker _worker;
BusinessClass _biz = new BusinessClass();
public Form3()
{
InitializeComponent();
InitWorker();
}
private void InitWorker()
{
if (_worker != null)
{
_worker.Dispose();
}
_worker = new BackgroundWorker
{
WorkerReportsProgress = true,
WorkerSupportsCancellation = true
};
_worker.DoWork += DoWork;
_worker.RunWorkerCompleted += RunWorkerCompleted;
_worker.ProgressChanged += ProgressChanged;
_worker.RunWorkerAsync();
}
void DoWork(object sender, DoWorkEventArgs e)
{
int highestPercentageReached = 0;
if (_worker.CancellationPending)
{
e.Cancel = true;
}
else
{
double i = 0.0d;
int junk = 0;
for (i = 0; i <= 199990000; i++)
{
int result = _biz.MyFunction(junk);
junk++;
// Report progress as a percentage of the total task.
var percentComplete = (int)(i / 199990000 * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
// note I can pass the business class result also and display the same in the LABEL
_worker.ReportProgress(percentComplete, result);
_worker.CancelAsync();
}
}
}
}
void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
// Display some message to the user that task has been
// cancelled
}
else if (e.Error != null)
{
// Do something with the error
}
}
void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
label1.Text = string.Format("Result {0}: Percent {1}",e.UserState, e.ProgressPercentage);
}
}
}
With this you can achieve Cancel functionality also very easily.
Observe that during initialisation, I set the WorkerSupportsCancellation = true & then I check for _worker.CancellationPending in the DoWork. So, if you want to cancel the process by a Cancel Button click, then you will write this code in the button handler- _worker.CancelAsync();

How do I capture key down in WPF?

How do I capture a key down event in WPF even if my application is not focused?
For me, the best way is this:
public MainWindow()
{
InitializeComponent();
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
if ((Keyboard.GetKeyStates(Key.W) & KeyStates.Down) > 0)
{
player1.walk();
}
}
The rendering event runs every time.
Global keyboard hook can slow down your debugging.
I prefer to use this approach:
Create KeyboardListener class
public class KeyboardListener : IDisposable
{
private readonly Thread keyboardThread;
//Here you can put those keys that you want to capture
private readonly List<KeyState> numericKeys = new List<KeyState>
{
new KeyState(Key.D0),
new KeyState(Key.D1),
new KeyState(Key.D2),
new KeyState(Key.D3),
new KeyState(Key.D4),
new KeyState(Key.D5),
new KeyState(Key.D6),
new KeyState(Key.D7),
new KeyState(Key.D8),
new KeyState(Key.D9),
new KeyState(Key.NumPad0),
new KeyState(Key.NumPad1),
new KeyState(Key.NumPad2),
new KeyState(Key.NumPad3),
new KeyState(Key.NumPad4),
new KeyState(Key.NumPad5),
new KeyState(Key.NumPad6),
new KeyState(Key.NumPad7),
new KeyState(Key.NumPad8),
new KeyState(Key.NumPad9),
new KeyState(Key.Enter)
};
private bool isRunning = true;
public KeyboardListener()
{
keyboardThread = new Thread(StartKeyboardListener) { IsBackground = true };
keyboardThread.Start();
}
private void StartKeyboardListener()
{
while (isRunning)
{
Thread.Sleep(15);
if (Application.Current != null)
{
Application.Current.Dispatcher.Invoke(() =>
{
if (Application.Current.Windows.Count > 0)
{
foreach (var keyState in numericKeys)
{
if (Keyboard.IsKeyDown(keyState.Key) && !keyState.IsPressed) //
{
keyState.IsPressed = true;
KeyboardDownEvent?.Invoke(null, new KeyEventArgs(Keyboard.PrimaryDevice, PresentationSource.FromDependencyObject(Application.Current.Windows[0]), 0, keyState.Key));
}
if (Keyboard.IsKeyUp(keyState.Key))
{
keyState.IsPressed = false;
}
}
}
});
}
}
}
public event KeyEventHandler KeyboardDownEvent;
/// <summary>
/// Состояние клавиши
/// </summary>
private class KeyState
{
public KeyState(Key key)
{
this.Key = key;
}
public Key Key { get; }
public bool IsPressed { get; set; }
}
public void Dispose()
{
isRunning = false;
Task.Run(() =>
{
if (keyboardThread != null && !keyboardThread.Join(1000))
{
keyboardThread.Abort();
}
});
}
}
Subscribe to KeyboardDownEvent in code-behind (or where you need it).
public partial class MainWindow : Window
{
private KeyboardListener listener;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
listener = new KeyboardListener();
listener.KeyboardDownEvent += ListenerOnKeyPressed;
}
private void ListenerOnKeyPressed(object sender, KeyEventArgs e)
{
// TYPE YOUR CODE HERE
}
private void Window_OnUnloaded(object sender, RoutedEventArgs e)
{
listener.KeyboardDownEvent -= ListenerOnKeyPressed;
}
}
Done
See this questions for hooking the keyboard Using global keyboard hook (WH_KEYBOARD_LL) in WPF / C#

Resources