Desktop App dev guidance needed

Thor

Honorary Master
Joined
Jun 5, 2014
Messages
44,413
Reaction score
7,522
Location
Bellville
Hello everyone.

Every time I get excited and want to try out desktop app development and then I open visual studio open a WPF project and just like that I close the IDE, open PHPStorm and continue to work on whatever php site I am busy with at the time, it's my comfort zone.

So now I have some questions, wtf do you guys use to build desktop apps, as in full-blown GUI?

From my own personal attempts with JavaFX, QT and WPF desktop app development seem like a horror show and absolute torture.

What am I missing?
 
Winforms... Never moved to WPF as I was unsure of it's future.
 
Still feels like a headache vs CSS/HTML and a backend like PHP with a DB.
 
Still feels like a headache vs CSS/HTML and a backend like PHP with a DB.

If you're comfortable with Web Development technologies, have you considered something like Electron?
 
I tend to use winforms when I need to interface to hardware devices & run on WM6. Most ppl doing Winforms just moer code together in the control event handlers even SQL right there in the form :sick:. That is bad practice actually.

You need separation of concerns just like in any other well design app. Abstraction of persistence, domain, services etc. Not that hard. The form is actually only there for presentation. The behaviour behind the form should not sit in the form. It should sit in a ViewModel. The form and controls use databinding to hook up to the ViewModel to display info and react the user input/clicks. Very much like WPF but way easier.
 
I tend to use winforms when I need to interface to hardware devices & run on WM6. Most ppl doing Winforms just moer code together in the control event handlers even SQL right there in the form :sick:. That is bad practice actually.

You need separation of concerns just like in any other well design app. Abstraction of persistence, domain, services etc. Not that hard. The form is actually only there for presentation. The behaviour behind the form should not sit in the form. It should sit in a ViewModel. The form and controls use databinding to hook up to the ViewModel to display info and react the user input/clicks. Very much like WPF but way easier.

I understand that 100%
 
OK here goes

First you create the DTO (DataTransferObject) that will represent each row.
Code:
  public class CoinInfoDto
  {
    public string Rank { get; set; }
    public string Name { get; set; }
    public string NameAndSymbol => $"{Name} ({Symbol})";
    public string Symbol { get; set; }
    public string USD_Price { get; set; }
    public string ZAR_Price { get; set; }
    public string Change_1h { get; set; }
    public string Change_24h { get; set; }
    public string Volume_24h { get; set; }
  }

Not sure why all the values are string type, but that is what the source data contains.

Then you create an interface to abstract the data source from the rest of the app. This allows you to mock the data source to test the app itself and then later just switch to the proper data source.

Code:
  public interface ICoinInfoService
  {
    IList<CoinInfoDto> GetTopCoins();
  }

then we create a mock data source to supply sample (test) data

Code:
  public class MockCoinInfoService :
    ICoinInfoService
  {
    public IList<CoinInfoDto> GetTopCoins()
    {
      List<CoinInfoDto> coins = new List<CoinInfoDto>();

      coins.Add(new CoinInfoDto
      {
        Rank = "1",
        Name = "Bitcoin",
        Symbol = "BTC",
        USD_Price = "7571.12USD",
        ZAR_Price = "75710ZAR",
        Change_1h = "-0.3%",
        Change_24h = "-2.64%",
        Volume_24h = "20000.64",
      });

      coins.Add(new CoinInfoDto
      {
        Rank = "2",
        Name = "Ethereum",
        Symbol = "ETH",
        USD_Price = "420.25USD",
        ZAR_Price = "4200ZAR",
        Change_1h = "-0.17%",
        Change_24h = "3.29%",
        Volume_24h = "30000.29",
      });


      return coins;
    }
  }
 
Last edited:
Ok so next we want to create the ViewModel that will manage the bahaviour and abstract the form from any other application elements.

Code:
  public class CoinInfoViewModel:
    ObservableObject
  {
    public CoinInfoViewModel(ICoinInfoService coinInfoService)
    {
      this.coinInfoService = coinInfoService;
    }

    public IList<CoinInfoDto> CoinInfo
    {
      get { return coinInfo; }
      private set
      {
        coinInfo = value;
        OnPropertyChanged(nameof(CoinInfo));
      }
    }

    public void InitialView()
    {
      CoinInfo = coinInfoService.GetTopCoins();
    }

    private readonly ICoinInfoService coinInfoService;

    private readonly IList<CoinInfoDto> coinInfo = new List<CoinInfoDto>();

  }

We use DI to inject the CoinInfo service implementation of choice. I.e. the ViewModel is not dependent on any service implementation. We inject the one we want.

The form hooks up to the ViewModel by means of data binding. DataBinding relies on the INotifyPropertyChange interface. We create a base class to implement this interface and provide some helper methods.

Code:
  public class ObservableObject: 
    INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler == null)
        return;

      handler(this,new PropertyChangedEventArgs(propertyName));
    }
  }

Ok so next the form.
We create a Windows Form and put a DataGridView on it in the designer.

Code:
  public partial class frmCoinInfo : Form
  {
    public frmCoinInfo()
    {
      InitializeComponent();
    }
    public frmCoinInfo(CoinInfoViewModel dataContext)
    {
      InitializeComponent();

      this.dataContext = dataContext;

      CreateBindings();
    }

    private void CreateBindings()
    {
      dataGridView1.DataBindings.Add("DataSource", dataContext, "CoinInfo");
    }

    private readonly CoinInfoViewModel dataContext;
  }

Above is the form code. You will see I use DI to inject the Viewmodel into the form. Do not remove the default ctor as this will break the form designer. In the ctor with DI, we just set the local field variable and do the binding.

More >>>
 
Last edited:
That is it. Now we just need to wire up all the pieces using DI. The Program.cs is what is known as the Composition Root. This is where we wire up everything.

To use the mock data source we code Program.cs as follows:

Code:
  static class Program
  {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      ICoinInfoService coinInfoService = new MockCoinInfoService();

      CoinInfoViewModel viewModel = new CoinInfoViewModel(coinInfoService);

      frmCoinInfo form = new frmCoinInfo(viewModel);
      viewModel.InitialView();

      Application.Run(form);
    }
  }

When you run the app it will display the sample data.

So now we want to display the data from the live source.
We do not need to change anything apart from adding a new implementation for the ICoinInfoService that will get the data from the web:

Code:
  public class WebServiceCoinInfoService :
    ICoinInfoService
  {
    public IList<CoinInfoDto> GetTopCoins()
    {
      List<CoinInfoDto> coins = new List<CoinInfoDto>();

      HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://coindata.co.za/api.php");
      request.Method = "GET";

      using (WebResponse webResponse = request.GetResponse())
      {
        using (Stream responseStream = webResponse.GetResponseStream())
        {
          if (responseStream == null)
            throw new InvalidOperationException("No response stream");

          using (StreamReader responseStreamReader = new StreamReader(responseStream))
          {
            string jsonResult = responseStreamReader.ReadToEnd();

            return JsonConvert.DeserializeObject<List<CoinInfoDto>>(jsonResult);
          }
        }
      }


      return coins;
    }
  }


To now finally run the app with the live data:
change this line in Program.cs:

Code:
      ICoinInfoService coinInfoService = new WebServiceCoinInfoService();
Boom and that is it.

So we have completely separated the various layers and concerns and used SOLID principles:

S: Single Responsibility Principle. Each of the classes has one responsibility. The form only does presentation. The ViewMoel gets data and notifies the view that there is new data. The WebService class gets data from the web ect ect.

O: Open Closed Principle. To make changes to the app from displaying mock data to displaying live data, I did not have to change any working code expect for the Composition Root where the components are wired up. I.e. the other classes are Closed for changes. Especially the form and viewmodel. Nothing else needed to change.

L: Liskov's Substitution Principle. I could exchange the mock service and live web service without an issue as they adhered to the same interface contract, the ICoinInfoService .

I: Interface Segregation. Not used here

D: Dependency Injection. I used DI to ctor-inject services into the classes that depended on them. This of course allowed me to inject any compatible service interchangably without changing any code except the wiring up.

This looks like a lot of work for a little app like this but it illustrates the principles. And it is actually not that much work. Took me 10 mins. You just have to plan and get into that mindset. When you have an enterprise level app, these techniques become very important to keep your app extensible. It also allows easy mocking for testing.

In the case where I develop WM6 apps, this works like a charm as all code is shared between WM6 and Windows desktop. Hence I can write and debug all code on desktop without having the painfully slow Code/Deploy/Run/Debug on the device. The only diff between the 2 code bases is the actual form that is laid out for the device instead of the desktop.

Now when you start using DI and dynamically loaded assemblies, that is where it starts to get awesome. Support for different hardware device protocols, easy support for integration with e.g. financial systems, etc etc...

The biggest take-away from this is that SOLID is not specific to WinForms or C#. These techniques can be applied to all stacks and languages.

In the case of MVC with typical WebApi and web page controllers, the real work is deferred to services and domain classes. It is not the controllers' responsibility to do the work. The MVC framework and controllers' only responsibility is to marshall the web request and the routing into a code entry point. Typically the controller should contain minimal code and use DI to get access to a service to do the real work.

Project files VS2015 at https://www.dropbox.com/s/zbfk9ia3vq4e6bo/MyBBCoin.zip?dl=0
 
Last edited:
Hello everyone.

Every time I get excited and want to try out desktop app development and then I open visual studio open a WPF project and just like that I close the IDE, open PHPStorm and continue to work on whatever php site I am busy with at the time, it's my comfort zone.

So now I have some questions, wtf do you guys use to build desktop apps, as in full-blown GUI?

From my own personal attempts with JavaFX, QT and WPF desktop app development seem like a horror show and absolute torture.

What am I missing?

JavaFX with Scenebuilder is my approach to desktop apps. SceneBuilder makes everything so easy when we talk about FXML and styling your gui.

As for .Net related desktop apps, I use wpf. It's easy once you invest time in it, but I still prefer javafx with Scenebuilder.
 
I tend to use winforms when I need to interface to hardware devices & run on WM6. Most ppl doing Winforms just moer code together in the control event handlers even SQL right there in the form :sick:. That is bad practice actually.

You need separation of concerns just like in any other well design app. Abstraction of persistence, domain, services etc. Not that hard. The form is actually only there for presentation. The behaviour behind the form should not sit in the form. It should sit in a ViewModel. The form and controls use databinding to hook up to the ViewModel to display info and react the user input/clicks. Very much like WPF but way easier.
+1 for this post as well.
 
JavaFX with Scenebuilder is my approach to desktop apps. SceneBuilder makes everything so easy when we talk about FXML and styling your gui.

As for .Net related desktop apps, I use wpf. It's easy once you invest time in it, but I still prefer javafx with Scenebuilder.
...and for [MENTION=304573]Thor[/MENTION] JavaFX employs a derivative of CSS that would be easy to pick up, and the XML in the FXML files is no more challenging to edit than an HTML file, and as you mentioned one can always fall back on Scenebuilder.

Not that I'm punting this over .Net alternatives or any other. Simply use what makes sense in the particular context and / or what you're comfortable most productive with.
 
[)roi(];21890533 said:
...and for [MENTION=304573]Thor[/MENTION] JavaFX employs a derivative of CSS that would be easy to pick up, and the XML in the FXML files is no more challenging to edit than an HTML file, and as you mentioned one can always fall back on Scenebuilder.

Not that I'm punting this over .Net alternatives or any other. Simply use what makes sense in the particular context and / or what you're comfortable most productive with.
This makes sense. I have Java and I have NetBeans.

When I I searched for JavaFX the oracle website said its replaced with open something (just did a quick search few days ago).

Is JavaFX still current?

Can you guys maybe give me what you believe to be a good tutorial for Java (I've used it 7 years ago, so forgotten most of it.)

Maybe I should buy a Lynda tutorial for Java first.
 
Top
Sign up to the MyBroadband newsletter
X