I have the following code, I would like to call the function RefreshProcess(SaveEventTriggerModelArgs obj) from MainWindow_Loaded.
However the problem I am running into due to lack of knowledge working with window apps I calling this method inside.
It will not let me because of the arguments SaveEventTriggerModelArgs obj and if I add those into RefreshProcess, they are different from void MainWindow_Loaded(object sender, RoutedEventArgs e). How to do it?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded+= Window_Loaded;
}
private void RefreshProcess(SaveEventTriggerModelArgs obj)
{
var rect = new Rect();
Dispatcher.Invoke(() =>
{
obj.CurrentEventTriggerModel.ProcessInfo = new ProcessInfo()
{
ProcessName = "Nox" != null ? $"Nox" : "",
Position = rect,
};
});
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
}
public class SaveEventTriggerModelArgs : INotifyEventArgs
{
public Model CurrentEventTriggerModel { get; set; }
}
public class MousePointEventArgs : INotifyEventArgs
{
public ViewModel MousePointViewMode { get; set; }
}
public class ViewModel
{
}
public class Model
{
public ProcessInfo ProcessInfo { get;set;}
}
public class ProcessInfo
{
public string ProcessName { get;set;}
public Rect Position { get;set;}
}
Related
I am using Windows Form;
I want to set TextBox tbCommandName1.Text which is on my Form;
I got the value from GetInfo() and how can I send string from Second.GetInfo() to my main Form like to class Favorit ?
I don't want to create an instance of Form; Because it makes to Initialize all my components again.
I bet I have to use get/set.
Give me please, a few hints;
THanks a lot to you, my guru!
namespace ParserFavorit
{
public partial class Favorit : Form, IForm
{
public Favorit()
{
InitializeComponent();
}
public string CommandName1
{
get { return tbCommandName1.Text; }
set { tbCommandName1.Text = value; }
}
private void bStart_Click(object sender, EventArgs e)
{
string ID = tbGetID.Text;
Second.StartBrowser(Second.GetDriver(), ID);
}
}
public class Second : Form
{
private static ChromeDriver driver = null;
public static ChromeDriver GetDriver()
{
if (driver == null)
{
driver = new ChromeDriver();
}
return driver;
}
public static void StartBrowser(ChromeDriver driver, string IDevent)
{
driver.Navigate().GoToUrl("myURL" + IDevent);
GetInfo();
}
public static void GetInfo()
{
System.Threading.Thread.Sleep(2000);
string CommandName1 = driver.FindElement(By.XPath(".//*[#id='react-root']/div/div[2]/div/div[1]/div/div[1]/div/div[1]/div/header/div[2]/span[1]")).Text;
string CommandName2 = driver.FindElement(By.XPath(".//*[#id='react-root']/div/div[2]/div/div[1]/div/div[1]/div/div[1]/div/header/div[2]/span[2]")).GetAttribute("innerHTML");
}
}
interface IForm
{
string CommandName1 { get; set; }
}
}
I am sure that I have a TextBox with name tbCommandName1;
My form doesn't show the value which I got from website, but method PrintName got it.
How so?
namespace ParserFavorit
{
public partial class Favorit : Form
{
public Favorit()
{
InitializeComponent();
}
private void bStart_Click(object sender, EventArgs e)
{
string ID = tbGetID.Text;
Second.StartBrowser(Second.GetDriver(), ID);
}
public void PrintName(string Command1Name)
{
string Name = Command1Name;
tbCommandName1.Text = Name;
}
}
public class Second
{
private static ChromeDriver driver = null;
public static ChromeDriver GetDriver()
{
if (driver == null)
{
driver = new ChromeDriver();
}
return driver;
}
public static void StartBrowser(ChromeDriver driver, string ID)
{
driver.Navigate().GoToUrl("https://m.favorit.com.ua/uk/live/events/" + ID);
GetInfo();
}
public static void GetInfo()
{
System.Threading.Thread.Sleep(2000);
string CommandName1 = driver.FindElement(By.XPath(".//*[#id='react-root']/div/div[2]/div/div[1]/div/div[1]/div/div[1]/div/header/div[2]/span[1]")).Text;
Favorit favorit = new Favorit();
favorit.PrintName(CommandName1);
}
}
}
I would like to use MVP Design pattern for a WinForm App but i'm facing the problem of calling a View Update from another thread.
Here's my code
MODEL
public class Model : IModel
{
public string Status { get; set; }
public async void LongOperation(IHomeView View)
{
for (int i = 0; i < 1000; i++)
{
View.StatusListView = i.ToString();
}
}
}
PRESENTER
public class HomePresenter
{
IHomeView _IView;
IModel _IModel;
Model _Model = new Model();
public HomePresenter(IHomeView IView)
{
_IView = IView;
}
public async void LaunchLongOperation()
{
await Task.Run(() => _Model.LongOperation(_IView));
}
}
INTERFACE VIEW-PRESENTER
public interface IHomeView
{
string StatusListView { get; set; }
}
INTERFACE PRESENTER-MODEL
public interface IModel
{
string Status { get; set; }
}
FORM:
public partial class frmMain : Form, IHomeView
{
HomePresenter _Presenter;
public frmMain()
{
InitializeComponent();
_Presenter = new HomePresenter(this);
}
public string StatusListView
{
get
{
return lstActivityLog.Text;
}
set
{
lstActivityLog.Items.Add(value);
}
}
private void btnAvvia_Click(object sender, EventArgs e)
{
_Presenter.launchLongOperation();
}
}
i would like to update a list view in the Main form during the long operations of the Model class.
Which is the best way to do that?
Try this code without debugging, you'll be surprised about it works!
The quick and dirty way to make it work in debugging mode as well is to add Control.CheckForIllegalCrossThreadCalls = false; into the constructor of your form.
public partial class MainForm : Form, IHomeView
{
HomePresenter _Presenter;
public MainForm()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false; //<-- add this
_Presenter = new HomePresenter(this);
}
public string StatusListView
{
get
{
return lstActivityLog.Text;
}
set
{
lstActivityLog.Items.Add(value);
}
}
private void button1_Click(object sender, EventArgs e)
{
_Presenter.LaunchLongOperation();
}
}
I'm trying to get notified when the title of a UIViewController changes.
I tried adding an observer to the title of a UIViewController subclass but it never gets triggered. What's strange about this, is that it works on a plain UIViewController. Am I doing something wrong?
Here's a code example explaining my issue (Xamarin.iOS C#):
using System;
using UIKit;
using System.Collections.Generic;
namespace ObserverTests
{
public partial class ViewController : UIViewController
{
List<UIViewController> viewControllers = new List<UIViewController>();
public override void ViewDidLoad()
{
UIViewController controller1 = new UIViewController() { Title = "Controller1" };
UIViewController controller2 = new Test() { Title = "Controller2" };
this.viewControllers.Add(controller1);
this.viewControllers.Add(controller2);
foreach(UIViewController viewController in viewControllers)
{
viewController.AddObserver("title", Foundation.NSKeyValueObservingOptions.New, (changes) =>
{
Console.WriteLine(viewController.Title);
Console.WriteLine("Title Changed!");
});
}
controller1.Title = "TitleChanged1"; // Works
controller2.Title = "TitleChanged2"; // Fails
}
private class Test : UIViewController
{
}
}
}
In Xamarin the best way might be using inheritance and adding such a feature. For this you derive from UIViewController
public class UIObserveTitleChangedViewController : UIViewController
{
public event TitleChangedEvent TitleChanged;
public override string Title
{
get
{
return base.Title;
}
set
{
var oldTitle = base.Title;
if (oldTitle == value)
return;
base.Title = value;
OnTitleChanged(new TitleChangedEventArgs(value, oldTitle));
}
}
protected virtual void OnTitleChanged(TitleChangedEventArgs args)
{
TitleChanged?.Invoke(this, args);
}
#region ctor
public UIObserveTitleChangedViewController() { }
public UIObserveTitleChangedViewController(NSCoder coder) : base(coder) { }
protected UIObserveTitleChangedViewController(NSObjectFlag t) : base(t) { }
protected internal UIObserveTitleChangedViewController(IntPtr handle) : base(handle) { }
public UIObserveTitleChangedViewController(string nibName, NSBundle bundle) : base(nibName, bundle) { }
#endregion
}
and implement missing event types
public delegate void TitleChangedEvent(object sender, TitleChangedEventArgs args);
public class TitleChangedEventArgs : EventArgs
{
public string NewTitle { get; set; }
public string OldTitle { get; set; }
public TitleChangedEventArgs(string newTitle, string oldTitle)
{
NewTitle = newTitle;
OldTitle = oldTitle;
}
}
You can then subscribe to this event and get notified of changes
public partial class ViewController : UIObserveTitleChangedViewController
{
public ViewController(IntPtr handle) : base(handle)
{
this.TitleChanged += ViewController_TitleChanged; // Subscribe to TitleChanged
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Title = "Some title"; // triggers TitleChanged
Title = "Another new title"; // triggers TitleChanged
}
private void ViewController_TitleChanged(object sender, TitleChangedEventArgs args)
{
Debug.WriteLine("Title changed from {0} to {1}", args.OldTitle, args.NewTitle);
}
}
You could set the title like so and it will work:
controller2.SetValueForKey(new NSString("TitleChangedHAHA"), new NSString("title"));
You could do this. First define a new event argument that will hold the new title when it changes.
public class TitleChangedEventArgs: EventArgs
{
public string Title { get; private set; }
public TitleChangedEventArgs(string title)
{
Title = title;
}
}
In your test class, add a new Event Handler for TitleChanged and override Title to raise an event when the new title for the view controller.
public class Test : UIViewController
{
public event EventHandler<TitleChangedEventArgs> TitleChanged;
public override string Title {
get {
return base.Title;
}
set {
base.Title = value;
OnTitleChanged();
}
}
public virtual void OnTitleChanged()
{
if (TitleChanged != null) {
TitleChanged.Invoke(this, EventArgs.Empty);
}
}
}
and finally in your Main View Controller you can do something like this:
public class ViewController : UIViewController
{
private Test _test;
public override void ViewDidLoad()
{
_test = new Test();
base.ViewDidLoad();
}
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
_test.TitleChanged += Test_TitleChanged;
}
public override void ViewDidDisappear(bool animated)
{
_test.TitleChanged -= Test_TitleChanged;
base.ViewDidDisappear(animated);
}
void Test_TitleChanged(object sender, TitleChangedEventArgs e)
{
Console.WriteLine("Title Changed! " + e.Title);
}
public override void ViewWillDisappear(bool animated)
{
base.ViewWillDisappear(animated);
}
}
The Title property in UIViewController is marked virtual...so as an alternative solution, you could define a BaseViewController class and override Title and call a method in the Setter:
Public class BaseViewController : UIViewController
{
....
public override string Title {
get {
return base.Title;
}
set {
base.Title = value;
OnTitleChanged();
}
}
protected virtual void OnTitleChanged()
{
......
}
}
Then you can override OnTitleChanged on any of your UIViewControllers to have a callback when the Title is changed.
I want to add an observer in my model, i try to generic delegate but here is problem when invoke.
Here is my code and it works when I use 'handler.DynamicInvoke(this)' instead of 'Invoke'
but I know DynamicInvoke is slow... I want to know is here a right way to use Invoke.
public class Model<T>
{
public delegate void UpdatePrototype<T>(T mdl);
private List<UpdatePrototype<T>> listeners = new List<UpdatePrototype<T>>();
public void Bind(UpdatePrototype<T> handler)
{
listeners.Add(handler);
}
public void Sync()
{
foreach(UpdatePrototype<T> handler in listeners)
{
handler.Invoke((T)this); // << ERROR: can not convert Model<T> to T
}
}
public string Name = "Model";
}
public class MyModel : Model<MyModel>
{
public string Name = "MyModel";
}
public class YourModel : Model<YourModel>
{
public string Name = "YourModel";
}
void Main()
{
MyModel mdl = new MyModel();
mdl.Bind(MyUpdate);
mdl.Sync();
YourModel your = new YourModel();
your.Bind(YourUpdate);
your.Sync();
}
void MyUpdate(MyModel mdl)
{
Debug.Log(mdl.Name);
}
void YourUpdate(YourModel mdl)
{
Debug.Log(mdl.Name);
}
============
thanks #IVAAAN123 i modify my code as follow.
it is fine for me, although mdl.Sync<MyModel>() has a little odd ;)
public class Model<T>
{
public delegate void UpdatePrototype<T>(T mdl);
private List<UpdatePrototype<T>> listeners = new List<UpdatePrototype<T>>();
public void Bind(UpdatePrototype<T> handler)
{
listeners.Add(handler);
}
public void Sync()
{
foreach(UpdatePrototype<T> handler in listeners)
{
handler.DynamicInvoke(this);
}
}
public void Sync<T>() where T : Model<T>
{
foreach(UpdatePrototype<T> handler in listeners)
{
handler.Invoke((T)this);
}
}
public string Name = "Model";
}
public class MyModel : Model<MyModel>
{
public string Name = "MyModel";
}
public class YourModel : Model<YourModel>
{
public string Name = "YourModel";
}
void Main()
{
MyModel mdl = new MyModel();
mdl.Bind(MyUpdate);
mdl.Sync<MyModel>();
mdl.Sync();
YourModel your = new YourModel();
your.Bind(YourUpdate);
your.Sync<YourModel>();
your.Sync();
}
void MyUpdate(MyModel mdl)
{
Debug.Log(mdl.Name);
}
void YourUpdate(YourModel mdl)
{
Debug.Log(mdl.Name);
}
}
public class Model<T>
{
public delegate void UpdatePrototype<S>(S mdl);
private List<UpdatePrototype<Model<T>>> listeners = new List<UpdatePrototype<Model<T>>>();
public void Bind(UpdatePrototype<Model<T>> handler)
{
listeners.Add(handler);
}
public void Sync()
{
foreach (UpdatePrototype<Model<T>> handler in listeners)
{
handler(this);
}
}
public virtual string Name
{
get
{
return "Model";
}
}
}
public class MyModel : Model<MyModel>
{
public override string Name
{
get
{
return "MyModel";
}
}
}
public class YourModel : Model<YourModel>
{
public override string Name
{
get
{
return "YourModel";
}
}
}
void main()
{
MyModel mdl = new MyModel();
mdl.Bind(MyUpdate);
mdl.Sync();
YourModel your = new YourModel();
your.Bind(YourUpdate);
your.Sync();
}
void MyUpdate(Model<MyModel> mdl)
{
Console.WriteLine("MY MODEL HANDLER");
Console.WriteLine(mdl.Name);
}
void YourUpdate(Model<YourModel> mdl)
{
Console.WriteLine("YOUR MODEL HANDLER");
Console.WriteLine(mdl.Name);
}
I have a background process that i want to regularly maintain the state of gps location. I am not clear on how to invoke a delegate on the main thread in the ui layer when the threaded method is in another class. Here is sample code. My form launches the thread on load:
public partial class MainScreen : Form
{
.
. // form stuff
.
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
Thread t = new Thread(gpsStatusManager.UpdateLocation);
t.IsBackground = true;
t.Start();
}
delegate void GpsDataParameterDelegate(GpsStatus value);
public void UpdateGpsStatus(GpsStatus value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
gpsStatus.SetGpsStatus(value);
}
}
I have a domain object class for the gps information:
public class GpsStatus
{
public void SetGpsStatus(GpsStatus gpsStatus)
{
Latitude = gpsStatus.Latitude;
Longitude = gpsStatus.Longitude;
CurrentDateTime = gpsStatus.CurrentDateTime;
NumberOfSatellites = gpsStatus.NumberOfSatellites;
TotalNumberSatellites = gpsStatus.TotalNumberSatellites;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
public DateTime CurrentDateTime { get; private set; }
public int NumberOfSatellites { get; private set; }
public int TotalNumberSatellites { get; private set; }
}
Then, my manager class where i update status in the secondary thread:
public class GpsStatusManager
{
private GpsStatus _gpsStatus;
public void UpdateLocationx()
{
while (UpdateGpsData())
{
Thread.Sleep(2000);
}
}
private bool UpdateGpsData()
{
SError error;
SGpsPosition gpsPosition;
try
{
if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1)
return false;
}
catch (Exception)
{
return false;
}
var numberOfSatellites = gpsPosition.Satellites;
var totalSatellites = gpsPosition.satellitesInfo;
var datetime = gpsPosition.Time;
var lat = gpsPosition.Latitude;
var lon = gpsPosition.Longitude;
_gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites);
//How do I invoke the delegate to send the _gpsStatus data to my main thread?
return true;
}
}
Thanks for any assistance.
Here's one way to do it, just off the top of my head:
public class GpsStatusEventArgs : EventArgs
{
public GpsStatus Status { get; private set; }
public GpsStatusEventArgs(GpsStatus status)
{
Status = status;
}
}
public class GpsStatusManager
{
...
public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated;
private void OnGpsStatusUpdated(GpsStatus gpsStatus)
{
EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated;
if (temp != null)
temp.Invoke(this, new GpsStatusEventArgs(gpsStatus));
}
}
public partial class MainScreen : Form
{
...
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated);
...
}
private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e)
{
UpdateGpsStatus(e.Status);
}
...
}
Then add this to the bottom of UpdateGpsData:
OnGpsStatusUpdated(_gpsStatus);
You should use the SynchronizationContext class.
In the UI thread (in any class), set a field (perhaps static) to SynchronizationContext.Current.
You can then call Send or Post on the saved instance to execute code on the UI thread.
Here is another approach using the ISynchronizeInvoke interface. This is the same pattern the System.Timers.Timer class uses to raise the Elapsed event.
public class GpsStatusManager
{
public ISynchronizeInvoke SynchronizingObject { get; set; }
public event EventHandler Update;
public void UpdateGpsData()
{
// Code omitted for brevity.
OnUpdate(_gpsStatus);
return true;
}
private OnUpdate(GpsStatus status)
{
if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired)
{
ThreadStart ts = () => { OnUpdate(status); };
SynchronizingObject.Invoke(ts, null);
}
else
{
if (Update != null)
{
Update(this, status);
}
}
}
public class UpdateEventArgs : EventArgs
{
public GpsStatus Status { get; set; }
}
}