I use MVP pattern in my WinForms app. I've problem with implementation Real-Time data drawing Chart (MSChart).
I've some algorithm and presenter class:
public class Algorithm
{
private double parameter1;
public void Execute()
{
for (int i = 0; i < 1000; i++)
{
...
if (i % 10 == 0)
{
parameter1 = parameter1 * 0.95;
}
...
}
}
public class MainWindowPresenter
{
public void RunAlgorithm()
{
Algorithm alg = new Algorithm();
alg.Execute();
}
}
I execute this algorithm in Presenter class. I want to notify View of change parameter1 and pass this change to chart (MSChart) and of course draw in Chart. This is my Form class:
public partial class MainWindow : Form, IMainWindowView
{
private MainWindowPresenter presenter;
...
private void btn_Start_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() => presenter.RunAlgorithm());
}
}
Drawing in Real-Time is no problem - I use Task, but how to notify View and Form ?
It is not entirely clear to me just exactly what you are trying to achieve from your example code, but based on the information provided, something alongs the lines of the following should work:
Change Algorithm to expose its parameter1 value (e.g. by making it a public property).
Your current design has one Algorithm instance per invocation of RunAlgorithm and thus possibly multiple parameter1 values simultaneously, which seems unintended. Make alg a member of the MainWindowPresenter class so that you have one instance that is no longer scoped to the RunAlgorithm method. Add appropriate locking to prevent concurrency issues.
Add events to the Algorithm and MainWindowPresenter classes to notify observers (the form/view) of changes to parameter1. The MainWindowPresenter can forward the events fired by the Algorithm class. Note that these events will run on the thread that your Task is running on. In order to update controls in event handlers attached to these events you will then typically have to Invoke the UI thread.
Related
I'd like to find how to separate my GUI and work code.
The contrived example code, below, is the smallest starting point that
I can think of that covers the idea.
The example uses a Windows Form as the source of commands and as display
(consumer) of results. I want the work code to be capable of getting commands from, say, a command line interface instead. The work code should not depend on knowledge of the Form. The Form should know little about the work code. I'd like to have several consumers "see" when the property in the work code changes value.
I'm guessing this means using events for communication, and perhaps Interfaces as well, but I'm open to anything.
There are a million different suggestions out there. I've read the design pattern books, and I have tried many, and have yet to find a set that is well enough explained that I can fully implement it.
I don't want a universal solution. I want one as simple as possible
to implement and maintain for small, personal projects. I'm not
designing for a large corporation.
Most solutions I've found will hint at what to do, but not cover
the specifics like where an event is declared, and how the other
piece of code finds out about the event's existence so it can either issue
the event or respond to the event. I always end up needing, somewhere, what amounts to a global variable to hook things together.
The closest match I can find, here, to my question is this: C# Windows Forms App: Separate GUI from Business Logic But the solution uses the form to create an instance of the worker and returns a value directly, rather than informing any interested observers. The provided solution tightly bound the two classes.
The closest solution I've found anywhere is this: https://www.codeproject.com/Articles/14660/WinForms-Model-View-Presenter
which does some really cool work with interfaces and reflection, but didn't seem too maintainable nor flexible.
The comment lines in the source code below show the desired interaction
points but without the implementation.
File #1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// tell an instance of JustCounts to increment by 10
}
// Here, allow JustCounts to cause a call to this (or something
// similar, perhaps a property) to inform this code that the TotalCount
// property has changed.
public void ShowNewTotalCount(int NewTotal)
{
Console.WriteLine("New Total Count = {0}", NewTotal);
}
}
File #2
class JustCounts
{
private int m_TotalCount = 100;
// Inform other classes when the following property changes value,
// preferably including the value in the notification.
public int TotalCount { get => m_TotalCount; }
// The code in File #1 needs to result in a call to this method
// along with the correct argument value.
public void AddThisMuch(int increment)
{
m_TotalCount += increment;
}
}
I'm basing this on the current version of .Net (4.6.2).
If we implement INotifyPropertyChanged then we have an event that we can listen to for property changes. A bit like listening for key presses, we can filter then for the specific property that we want.
public class JustCounts : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int m_totalCount = 100;
public int TotalCount
{
get { return m_totalCount; }
set
{
if (value != m_totalCount)
{
m_totalCount = value;
NotifyPropertyChanged();
}
}
}
}
There's no need to create a method to manipulate the TotalCount property as we're exposing it.
public class Form1 : Form
{
// justCounts is a reference to the object wherever it is coming from
justCounts.PropertyChanged += new PropertyChangedEventHandler(JustCountsChangedHandler);
private void JustCountsChangedHandler(object sender, PropertyChangingEventArgs e)
{
// process on event firing
Debug.WriteLine($"justCounts TotalCount changed value to {justCounts.TotalCount}");
}
// Example of where the handler will fire when called
private void button1_click(object sender, EventArgs e)
{
justCounts.TotalCount++;
}
}
In the code above, we've created an event in JustCounts to which listeners can subscribe.
Using the INotifyPropertyChanged interface, we fire the event each time TotalCount is changed.
In form 1 we create the handler to listen for property changes, and the handler then carries out any processing.
One note. You say
I'd like to have several consumers "see" when the property in the work
code changes value
so in order for this to work we have to assume that the work code can run independently of it's subscriber (something like a server). Otherwise, we'd have different instances for different subscribers.
You also mention interfaces, and they could be used but are not necessary in this instance.
This is probably a really basic question, please bear with me, I'm still very new to the world of WPF/C#.
I have a WPF app where I open a new window if a button is clicked.
The window is called Sync and all it does is instantiate a viewmodel class which contains some public properties that are bound to my view.
The viewmodel also instantiates a class containing a lot of business logic, this updates the ViewModel's bound properties, the aim being to update the content of my window.
This sort of works, but only when all of the (sometimes quite lengthy) processing is completed does the window load and the view is populated with the last value of the ViewModel's properties.
I think I'm missing something pretty basic here. How do I get my window to instantly load and then have the view update when any of the properties have changed? Should I be listening for a PropertyChanged event and then updating the view? Where do i do this? Within the view model's setter?
Here's some simplified code:
Calling my window from my main window's View Model
public void SyncAction()
{
Sync syncWindow = new Sync();
syncWindow.Show();
syncWindow.Activate();
}
The window
public partial class Sync : Window
{
public Sync()
{
InitializeComponent();
var viewModel = new SyncViewModel();
}
}
The view model
class SyncViewModel
{
private string _miscStatus = "";
public SyncViewModel()
{
var sync = new SyncLogic();
sync.SyncAll(this);
}
public string MiscStatus
{
get
{
return _miscStatus;
}
set
{
_miscStatus += value;
}
}
}
Some business logic
class SyncLogic
{
private ViewModel.SyncViewModel _syncViewModel;
public void SyncAll(ViewModel.SyncViewModel syncViewModel)
{
_syncViewModel = syncViewModel;
// lock our synctime
var syncTime = DateTools.getNow();
_syncViewModel.MiscStatus = "Sync starting at " + syncTime.ToString();
// Do lots of other stuff
_syncViewModel.MiscStatus = String.Format("Sync finished at at {0}, total time taken {1}",
DateTools.getNow().ToString(), (DateTools.getNow() - syncTime).ToString());
}
}
Bonus question: The way I'm updating the view from within my business logic (by passing in a reference to the viewmodel and updating its properties from there) seems a bit kludgy. I definitely want to keep the business logic separate, but am not sure how I can pass any output back out to the viewmodel. What would be a better way of doing this please?
Why do you care whether the update takes visual effect before or after the code finishes executing? The internal properties are updated immediately; any code that queries the UI will see the new values.
The only time the user will be able to perceive a difference between an update during execution vs after execution is if you have a long-running computation on the UI thread. Don't do that.
Instead, run the computation asynchronously with the UI, so that repaint messages can be processed meanwhile. You can do this using a background thread, but the new easier way with C# 4 and later is async. Because async is implemented using continuation messages to the UI thread, you don't need to synchronize data access or marshal UI access between threads. It just works, and very well. The only thing you need to do is to break your code into small enough chunks, each implemented as an async method, that you don't cause noticeable delay.
What I would do:
Don't do any heavy logic in the ViewModel constructor. Constructor should only initialize object and do nothing else. In your example, constructor should be empty.
public SyncViewModel()
{
}
SyncLogic should not be aware of the ViewModel. Introduce some other class to communicate input arguments and sync results. Let's say SyncArguments and SyncResult.
class SyncLogic
{
public SyncResult SyncAll(SyncArguments syncArgs)
{
var syncResult = new SyncResult();
// Do lots of other stuff
// populate syncResult
return syncResult;
}
}
Introduce a method in the viewmodel that should be called to do the "sync" logic, and make that method async. That way it's very easy to do the heavy stuff in the background and leave the UI thread to do the job it should do, draw the UI.
public async Task Sync()
{
// lock our synctime
var syncTime = DateTools.getNow();
MiscStatus = "Sync starting at " + syncTime.ToString();
var sync = new SyncLogic();
var syncArgs = new SyncArguments();
//populate syncArgs from ViewModel data
//call the SyncAll as new Task so it will be executed as background operation
//and "await" the result
var syncResults = await Task.Factory.StartNew(()=>sync.SyncAll(syncArgs));
//when the Task completes your execution will continue here and you can populate the
//ViewModel with results
MiscStatus = String.Format("Sync finished at at {0}, total time taken {1}",
DateTools.getNow().ToString(), (DateTools.getNow() - syncTime).ToString());
}
Make the button click event handler that creates and shows the window async, so you can call Sync method on the ViewModel
private void async Button_click(object sender, EventArgs e)
{
Sync syncWindow = new Sync();
var viewModel = new SyncViewModel();
syncWindow.DataContext = viewModel;
syncWindow.Show();
syncWindow.Activate();
await viewModel.Sync();
}
That will draw the Window without waiting on the Sync method. When the Sync taks completes, viewmodel properties will be populated from the SyncResult and the Bindings will draw them on screen.
Hope you get the idea, sorry if there are some errors in my code, not sure that it all compiles.
First, make sure to set the viewmodel as the view's DataContext:
public partial class Sync : Window
{
public Sync()
{
InitializeComponent();
var viewModel = new SyncViewModel();
DataContext = viewModel;
}
}
Second, you'll have to run the "sync" stuff on a background thread. This is easiest with the async+await keywords in .Net 4.5:
public async void SyncAll(ViewModel.SyncViewModel syncViewModel)
{
_syncViewModel = syncViewModel;
// lock our synctime
var syncTime = DateTools.getNow();
_syncViewModel.MiscStatus = "Sync starting at " + syncTime.ToString();
await Task.Factory.StartNew(() => {
// Do lots of other stuff
});
_syncViewModel.MiscStatus = String.Format("Sync finished at at {0}, total time taken {1}",
DateTools.getNow().ToString(), (DateTools.getNow() - syncTime).ToString());
}
With databinding your Window will automatically updated as long as it notified that properties it bound to has been changed. So what you need is implement INotifyPropertyChanged in the viewmodel and raise property changed event whenever binding source property value changed. For example:
public class SyncViewModel : INotifyPropertyChanged
{
private string _miscStatus = "";
public string MiscStatus
{
get{ return _miscStatus; }
set
{
_miscStatus += value;
OnPropertyChanged("MiscStatus");
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
In case somebody else comes across this issue in WPF, the solution described here is really simple and just worked fine for me. It uses an extension method to force an UIElement to be rendered:
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
}
Then, simply use as:
private void SomeLongOperation()
{
// long operations...
// UI update
label1.Content = someValue;
label1.Refresh();
// continue long operations
}
}
Quoting the original author:
The Refresh method is the extension method that takes any UI element and then calls that UIElement's Dispatcher's Invoke method. The trick is to call the Invoke method with DispatcherPriority of Render or lower. Since we don't want to do anything, I created an empty delegate. So how come this achieves refresh functionality?
When the DispatcherPriority is set to Render (or lower), the code will then execute all operations that are of that priority or higher. In the example, the code already sets label1.Content to something else, which will result in a render operation. So by calling Dispatcher.Invoke, the code essentially asks the system to execute all operations that are Render or higher priority, thus the control will then render itself (drawing the new content). Afterwards, it will then execute the provided delegate (which is our empty method).
I'm having a bit of a problem with implementing an event architecture in C#. The basic layout is like this:
We have a network-layer(dll) that communicates with a server. This layer has made several interfaces for events of changes within the database. A database-field changes and the dll calls my implementation of the appropriate interface. I have a GUI, and within it's main method a data-object, which stores lists of temporary data I display until something gets changed by my user, in which case I'll send the changes to the database.
The problem is now that I can't implement an event-handler within the network-layer, or my implementation of it's interfaces, because my data-object(which should get the results of the events) only exists within my GUI, and it's main method, and as such is not known to the appropriate objects.
I'll make an example as pseudo-code:
namespace ClientConnection
{
public class DataListener : IDataListener
{
public delegate void SomethingReceivedHandler(object sender, SomethingData packet);
public event SomethingReceivedHandler somethingRecievedHandler;
public void SomethingReceived(SomethingData packet)
{
if (SomethingRecievedHandler != null)
{
SomethingRecievedHandler(this, packet);
}
}
Is my current implementation of the interface. The Layer has something akin to:
private void ProcessPacket(SomethingData packet)
{
if (packet == null)
return;
try
{
if (packet is SomethingData)
DataListener.SomethingReceived(packet as SomethingData);
//snip
And my main-method is:
public partial class Main : FormMain
{
Data ClientData; //Contains all temporary data within the GUI
public frmMain()
{
ClientData = new Data();
DataListener dataListener = newDataListener();
InitializeComponent();
}
And if the event fires I want to do something like:
ClientData.SomeList.Add(packet)
depending on the context.
The problem is now that I can't implement an event-handler within the network-layer, or my implementation of it's interfaces, because my data-object(which should get the results of the events) only exists within my GUI, and it's main method, and as such is not known to the appropriate objects.
Not sure I see the problem. The publisher of the event doesn't need to know anything about the subscriber of the event - that's what makes them useful.
Based on your pseudo-code, it should be as simple as:
public partial class Main : FormMain
{
Data ClientData; //Contains all temporary data within the GUI
public frmMain()
{
ClientData = new Data();
DataListener dataListener = new DataListener();
// Add an event handler
dataListener.somethingReceivedHandler +=
(object sender, SomethingData packet)
{
if (someContext) ClientData.SomeList.Add(packet);
};
InitializeComponent();
}
You probably want to elevate dataListener to a field (instead of a local) so that it stays alive outside of the ctor (and you can unsubscribe when your form closes).
I have multiple classes that do lengthy tasks in threads and want them to output some kind of progress, so i can display it to a progress bar or a counter.
I could use an event or a delegate, defined in an interface, but it seems for every implementation I will need to write the exact same FireEvent code to check if the event is null and raise it, if it's not.
Using an abstract class seems bad too, since functionality like that does not belong in the top most class, which means I have to implement it at different places again.
How do I do that in the most reusable way, without duplicate code everywhere?
If you're using a BackgroundWorker for your other threads, you can use the ReportProgress method, which will raise the ProgressChanged event.
http://msdn.microsoft.com/en-us/library/cc221403%28v=vs.95%29.aspx
I usually reverse the relationship between the view and the model so that the view knows about the model. In this example the progress dialog would have a reference to a IProgress interface. It then hooks up to a ProgressChanged event and the view can thus update itself when it needs to. The main advantage of this is the code inside the various classes are not duplicated - Only the code that tells how much is left is inside those classes. This way it is also very easy to clamp progress updates of classes that emit progress status very often.
Just to give you an idea what I usually do:
interface IProgress
{
event EventHandler ProgressChanged;
int ProgressTarget { get; }
int CurrentProgress { get; }
}
And a implementing class. I don't even know if it works as it should - It's just to give an impression on how to implement this interface.
class StreamCopier: IProgress
{
private Stream _source;
private Stream _destination;
public StreamCopier(Stream source, Stream destination)
{
_source = source;
_destination = destination;
}
public void WriteAll()
{
int b;
while ((b = _source.ReadByte()) != -1)
{
_destination.WriteByte((byte)b);
EventRaiser.Raise(ProgressChanged, this); // Just one call here! Can't be less
}
}
public event EventHandler ProgressChanged;
public int ProgressTarget {
get { return (int)_source.Length; }
}
public int CurrentProgress {
get { return (int)_destination.Position; }
}
}
And then the EventRaiser class. Note how the handler reference is passed on the parameter stack, and therefor no thread-safe copy to a 'tmp' is necessary! :)
static class EventRaiser
{
public static void Raise(EventHandler handler, object sender, EventArgs args)
{
handler(sender, args);
}
public static void Raise(EventHandler handler, object sender)
{
Raise(handler, sender, EventArgs.Empty);
}
}
I got an object, which is called in my form1-window. How can I change anything from the form1-object from within this object, for example a label or a processbar?
It would be a bad (circular) design to give your object a reference to your form. Use an interface or a delegate (callback).
// untested code
class MyObjectClass
{
public delegate void Reportback(int percentage);
public void DoSomething(Reportback callBack) { ...; callback(i*100F/total); ...}
}
class Form1: Form
{
private void reportProgress(int percent) { ...; progressbar1.value = percent; }
void SomeMethod() { myObject1.DoSomething(reportprogress); }
}
Generally speaking, when you find yourself with a need for one object to manipulate the private fields of another, your design needs work.
For instance, an class that's performing some kind of long-running business logic shouldn't be updating a ProgressBar. First, that's not its job. Second, that couples the functioning of the business logic to the implementation details of the user interface.
It's much better if the class simply raises events as it performs its long-running task. For instance, look at this class:
public class BusinessLogic
{
public event EventHandler ProgressChanged;
private int _Progress;
public int Progress
{
get { return _Progress; }
private set
{
_Progress = value;
EventHandler h = ProgressChanged;
if (h != null)
{
h(this, new EventArgs());
}
}
}
}
Whenever any method in this class sets the Progress property, the ProgressChanged event gets raised. In your form, you can instantiate the object with logic like this:
private BusinessLogic Task;
private void Form1_Load(object sender, EventArgs e)
{
Task = new BusinessLogic();
Task.ProgressChanged += Task_ProgressChanged;
}
void Task_ProgressChanged(object sender, EventArgs e)
{
taskProgessBar.Value = ((BusinessLogic) sender).Progress;
}
Now, every time a method in the Task object sets the Progress property, the ProgressBar in the form will get updated.
This is quite a bit more code to write than just having the object update the ProgressBar, sure. But look what you get out of it. If you have to refactor your form into two forms, and move the task to a new form, you don't have to touch the BusinessLogic class. If you move your ProgressBar from being a control on the form to being a ToolStripProgressBar on a ToolStrip, you don't have to touch the BusinessLogic class. If you decide that progress reporting isn't important, you don't have to touch the BusinessLogic class.
Essentially, this approach protects the BusinessLogic class from having to know anything about the user interface. This makes it a lot easier to change both the business logic and the user interface as your program evolves.
I agree with Henk... but anyway, you can modify any item on a form if you change the visibility of the controls, there is even a property for doing this.