Exchanging data between dialogs and document. How!?.
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 16

Thread: Exchanging data between dialogs and document. How!?.

  1. #1
    Join Date
    Dec 2005
    Posts
    9

    Exchanging data between dialogs and document. How!?.

    I've just started writing an SDI project (tabCtrl with child dialogs) and the gui bit went alright after an initial struggle. However what has me stumped despite googling etc for days is how exactly data is exchanged from the dialog into the document and from the document into all the dialogs. I can't make heads or tails of it.

    My understanding is that the View is responsible as the interface between the document and the dialog but exactly how this exchange occurs I have no idea. It really is a missing link.

    If anyone can explain it to me (keeping in mind I'm a newb to MFC) or can point me to a demo with source that actually stores data in data structures located in the document and exchanges it with the dialogs the view manages I'd really appreciate it.

    I would have thought this was a common question but my google/search abilities have failed me in finding anything that makes sense to me.

    TIA

  2. #2
    Join Date
    May 2006
    Location
    Dresden, Germany
    Posts
    458

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by jbem
    I would have thought this was a common question but my google/search abilities have failed me in finding anything that makes sense to me.

    TIA
    Maybe this is too simple for experienced MFC users...

    There are many solutions to solve this, I prefer the following:

    From my point of view the easiest way is:
    - add a (public) member variable to each dialog holding a pointer to the document
    - In the dialog's constructor initialze this member to NULL
    - in OnInitdialog (or better in DoDataExchange) use this ptr (carefully checking it against NULL first)

    This approach is suitable for many situations, you can even call UpdateAllViews() since it is a public member function of the document.

    If you want to encapsulate the doc's data more seriosly then you could change this approach: Add other member variables to the dialog.

    I always try to implement the setting/changing doc's data in the OnOk() handler of the dialog to ensure that clicking the Cancel button will not change anything in the document's data. Therefore I sometimes need copies of the doc's data in the dialog... If this will make it too complex I change the design: The dialog holds a copy to the doc's data and the calling function is responsible to change/reset the doc's data.

    How can the view be the deliverer?

    Easy:

    In a handler of the view you can call GetDocument(), give the returning value to the dialog.

    With regards
    Programartist

  3. #3
    Join Date
    Dec 2005
    Posts
    9

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by ProgramArtist
    Maybe this is too simple for experienced MFC users...

    There are many solutions to solve this, I prefer the following:

    From my point of view the easiest way is:
    - add a (public) member variable to each dialog holding a pointer to the document
    - In the dialog's constructor initialze this member to NULL
    - in OnInitdialog (or better in DoDataExchange) use this ptr (carefully checking it against NULL first)
    True but then that would break modularity and not make your dialogs re-usable.

    Since posting the question I've been doing some thinking and if I think if you want to maintain modularity the dialog would have to send a message to the view containing the relevant information the dialog has access to. The view would then be able to update the document through it's access to the document handle. I really need to read up more on messaging.

    Quote Originally Posted by ProgramArtist
    This approach is suitable for many situations, you can even call UpdateAllViews() since it is a public member function of the document.
    Modularity issues aside, if my understanding is correct then since this is an SDI document with only one view UpdateAllViews() wouldn't trigger anything because it only sends messages to the views the change did not originate in. Might be mistaken and need to read the API a bit more closely.


    I think I have the dialog->view->document side sussed out through the use of messages to maintian modularity of the dialogs and separation of GUI vs data. Now I have to work out how a change in the document or more precisely how a change to the data a thread is working on triggers the data to be sent to the view. I have a feeling another message posted from the thread to a handler in the view which then accesses the doc for data and then access the dialog to GUI update when the data changed.

    I've come across an example or two where people do pass document ptrs to the constructors when they create the dialog but that brings up alarm bells to me because it breaks modularity and it doesn't seem to be the way MS intended the architecture of SDI/MDI to function because if it was they would of provided the dialog with access to the document in the first place given that it's such a common action.

    What I'm really after is the modular and MS's intended way the architecture should be used. I have a feeling the key is in message handlers being processed by the view which is used to glue the data to the GUI. If anyone has any other ways that don't break modularity (since I do anticipate that I might be creating dialogs in the future that will be re-used) I'd be interested.

    Can anyone confirm that what I proposed above is the way MS intended it's architecture to be used so that modularity and encapsulation goals are maintained? Any other ways? It really is frustrating that MS don't seem to provide a clear discussion on this given it's a fundemental part of their framework.

    ProgramArtist, thanks for the input. It's always interesting seeing the approaches people take but due to the modularity issues with storing Doc pointers and the dialog knowing explicitly the datastructure of the document it's not really going to be the answer I need although it would work.
    Last edited by jbem; July 4th, 2008 at 02:37 AM.

  4. #4
    Join Date
    Nov 2002
    Location
    Los Angeles, California
    Posts
    3,863

    Re: Exchanging data between dialogs and document. How!?.

    Bravo to you for being concerned about modularity. That should be a primary
    issue. Separation of concerns.

    by dialog do you mean a modal dialog or a modeless dialog?
    Wakeup in the morning and kick the day in the teeth!! Or something like that.

    "i don't want to write leak free code or most efficient code, like others traditional (so called expert) coders do."

  5. #5
    Join Date
    Dec 2005
    Posts
    9

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by souldog
    Bravo to you for being concerned about modularity. That should be a primary
    issue. Separation of concerns.

    by dialog do you mean a modal dialog or a modeless dialog?
    A modeless dialog that is a child of a "page" in a CtabCtrl in my case though the dialog itself calls another modal dialog (CFileDialog) to provide me the path to a b-encoded file that contains data my document will need to parse and extract relevant info out of to fill in and create it's data structures which will be used by worker threads.

    So in my case it's
    child modeless dialog contains button which opens up a file dialog which is modal which upon completion (ID_OK) the child dialog is able to obtain the path. The child dialog then pass this path to my document which contains methods to open and parse the encoded file and update it's own data structures.

    My approach at the moment, theoretically, is to send a message to the view with the path from the modeless child dialog. The view will access the document and call the appropriates method in the document to load/parse the file and update relevant data structures in the document based on the bencoded file. Once complete the document will send another message to the view and the view will directly access the document and update the controls that it has accessed to based on the data stored in the document. I think this is the correct way to do it but since I'm an MFC newb I'm open to alternate better methods.

    I still have a tonne of reading to do on messaging and then I need to implement it to see whether my idea of how things are supposed to work really can be done.
    Last edited by jbem; July 4th, 2008 at 04:37 AM.

  6. #6
    Join Date
    May 2006
    Location
    Dresden, Germany
    Posts
    458

    Re: Exchanging data between dialogs and document. How!?.

    Hi,

    to get more information about the concepts of the MFC Architecture I recommend reading books. You can either read some books about MS Windows programming (since MFC is in general a collection of wrapper classes for the MS Windows API) or some books about MFC itself (the one I purchased, read and heavily used is "MFC Internals" by George Shepherd and Scott Wingo).

    To create your app with a maximum modularity you should follow the intentions of the MFC framework (and I do so - except in small, fast written tools):

    - The DocTemplate('s) hold general information about which data has to be stored in a document.

    - The document class(es) hold the data itself. Methods for manipulating the data (Set(), Reset(), Recalc() or so...) should also be implemented there. I don't see the modularity broken if a dialog calls such methods of a document class.

    - The view class(es) should implement the way how the data of the document could be viewed to the user. That's why some "data" has to be stored there: Cursors, scrolling positions, zoom levels...

    What is the role of a (modal) dialogue?

    Answer (IMHO): Show (= View) some data to the user and give him the possibility to change the data. That's sounds a little bit curious: Is it a thing somewhere in the no-mans-land between a document and a view?

    That's why a good application design claims a decision from you: Where and how to implement the dialog class(es). The wizzard suggests to implement each dialog class in a separate file (of course two: .h and .cpp), but this is sometimes annoying to me (and can be avoided when creating the dialog class).

    With regards
    Programartist

  7. #7
    Join Date
    May 2006
    Location
    Dresden, Germany
    Posts
    458

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by jbem
    I still have a tonne of reading to do on messaging and then I need to implement it to see whether my idea of how things are supposed to work really can be done.
    Do you really think that you can improve the modularity by using messages instead of using pointers to certain classes?

    Then you have to implement really general messages. In case you send a message with the ptr as LPARAM you have to cast it back and forth and it is in no way better then having a pointer.

    Data commiting in a typical (appwizzard generated) MFC application uses messaging for updating status bars, menu items and so on. But not for getting / setting data between views / dialogs and documents.

    If I understand you correctly you want to implement messages to send data from the doc to (modeless and modal) dialogues.
    IMHO:
    - This will increase the modularity only in case you are able to have really general messages (e.g. "SendString2ListBox"). A message like "SetMySpecialMemberOfMyDoc" is not better than having a pointer to the doc class.
    - Sending messages via SendMessage() is an OOP-like virtual function call without using OOP language features since that will call the message handler immediatly. If you use PostMessage instead you have to be careful by implementing your data sending algorithms: It is dangerous to get data from the doc while there is a message in the queue which will tell the doc to change his data. Do you need this behavior? What for?

    With regards
    Programartist

  8. #8
    Join Date
    Dec 2005
    Posts
    9

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by ProgramArtist
    Do you really think that you can improve the modularity by using messages instead of using pointers to certain classes?

    Then you have to implement really general messages. In case you send a message with the ptr as LPARAM you have to cast it back and forth and it is in no way better then having a pointer.
    The idea, at least for me when I write modular code is that the code has no idea about the data structures it doesn't own. If your dialog knows about your data structure in the document which it doesn't own then there is a rigid constraint and the dialog can't be re-used easily unless you rewrite your document each time to be compatible. Thus you can't re-use the document without the dialog and vice versa. Creating a flexible component library that speeds up your development commercially becomes impossible.

    With a messaging system you abstact the data into it's simplest form and allow an intermediary (Cview in MFC's case) register interest and if desired to translate between the two independent entities. That is what is is there for if I'm understanding the concept. I've used frameworks before which have a similar concept abeit the "msging" is exceuted differently.

    Quote Originally Posted by ProgramArtist
    If I understand you correctly you want to implement messages to send data from the doc to (modeless and modal) dialogues.
    IMHO:
    - This will increase the modularity only in case you are able to have really general messages (e.g. "SendString2ListBox"). A message like "SetMySpecialMemberOfMyDoc" is not better than having a pointer to the doc class.
    Modularity is about boundaries. Much like declaring something private/public/protected in a class. If you adopt your approach it's like defining everything public. Everything still works but it's not exactly the way it was intended to be used and you lose "protection". The equivalient here of losing protection is losing modularity

    Ideally the idea is that the message should be handled by the owner of the control. I wouldn't for example send the message from the dialog straight to the document. In SDI architecture this responsibility would be with the CView/CMainFrame because it owns the GUI elements, not the document because the document has no clue about the GUI or more correctly it shouldn't. Conversely the GUI shouldn't know about the document. The only things that know about both are the frames and the views and that is the custom bit of code in every app.

    If for example I decided that my data structure was not designed correctly in the document because it didn't scale and I wished to rewrite it then in effect by not using messaging I would then need to alter the dialog code to handle the new methods etc in the redesigned document. At that point I would break any other applications that where re-using that dialog because the API had changed into the Doc even though functionally there was no change in the GUI elements. There wouldn't be many happy managers if this happened. The workaround is that the company now needs to support two different flavours of identical GUI's or restrict the document datastructure to maintain a set API's which assume a GUI which may in the future not even exist and clutters it.

    Quote Originally Posted by ProgramArtist
    - Sending messages via SendMessage() is an OOP-like virtual function call without using OOP language features since that will call the message handler immediatly. If you use PostMessage instead you have to be careful by implementing your data sending algorithms: It is dangerous to get data from the doc while there is a message in the queue which will tell the doc to change his data. Do you need this behavior? What for?
    I guess the answer is that I am used to working for large software companies and in my time I've come to appreciate that one should always strive to make things extensible and modular so that you don't impact other groups should a redesign be necessary and if you do those changes should be well contained to mimimise testing resources.

    As for danger you miss the fact that if someone closes the document and opens a new one you are also screwed. Now you have to go to all your GUI data structures and update the pointer. All in all it's like anything in programming, you need to know what you are doing regardless whether you use messages or whether you use direct pointers.

    Also it kind of breaks the concept of OO programming if an object is having to deal with concepts/datastructures that it does not directly own nor need to for it to do it's work. A dialog should obtain and display data not manage your document. How that data is used external to the control should not matter to it. At best it should just post an event and let whomever is interested work out what needs to be done and what methods are best used to do it.

    If you are writing an app for yourself and no one else is going to have to maintain and add stuff over the years or re-use portions of it then I guess the issue on modularity is not that important. It's kind of like documentation . At the moment I'm trying to take the approach as if I am writing this as part of a commercial project which may have re-use requirements. I know that this little project I set for myself will never be that and I could take shortcuts to make life easy but if I should find myself having to program in MFC commercially modularity really plays an important role so I need to do it right and go through the pain now to undestand the options I have at my disposal and boundaries in the framework so that when the pressure is on there is one less thing to worry about. Nothing is worse than going to a code review and getting your arse chewed out because you broke modularity and need to rewrite it all again

    Cheers
    Last edited by jbem; July 4th, 2008 at 10:54 AM.

  9. #9
    Join Date
    Nov 2002
    Location
    Los Angeles, California
    Posts
    3,863

    Re: Exchanging data between dialogs and document. How!?.

    if you are feeling uncomfortable about the document/view architecture, you should.

    IMO it is a bad design and forces/encourages over coupling between the GUI and the data. The MFC version of RTTI and dynamic object creation disallows RAII for things like views and forces the programmer into two step initialization.

    You do not need to use the document/view architecture. I personally view MFC as a framework for displaying and managing windows through its wrappers around HWND and HDC. I would never use any of the business logic wrappers provided by MFC.
    Wakeup in the morning and kick the day in the teeth!! Or something like that.

    "i don't want to write leak free code or most efficient code, like others traditional (so called expert) coders do."

  10. #10
    Join Date
    Dec 2005
    Posts
    9

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by souldog
    IMO it is a bad design and forces/encourages over coupling between the GUI and the data.
    I think the biggest problem is that they haven't produced a decent example of how the framework should be used. They crap on about the theory of what a View is, a frame and a document but fail to show how to correctly exchange data in this framework between the elements assuming best programming practices. When I started this I was surprised that I wasn't stumbling over articles on how this data exchange in the frame work occurs between the GUI and user defined data structures. I think that is why it produces over coupling. It leaves it to the developers imagination which is all well and good but some direction is needed for people when presented with a framework of what an ideal way of doing things should be.
    Last edited by jbem; July 4th, 2008 at 01:23 PM.

  11. #11
    Arjay's Avatar
    Arjay is online now Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    11,289

    Re: Exchanging data between dialogs and document. How!?.

    Help me understand your application.

    Do you have a standard SDI application (SDI app with a menu, status bar, and CFormview derived view)?

    Or do you have a app that displays a property sheet with pages (i.e. no status bar or menu)?

  12. #12
    Join Date
    Dec 2005
    Posts
    9

    Re: Exchanging data between dialogs and document. How!?.

    Quote Originally Posted by Arjay
    Help me understand your application.

    Do you have a standard SDI application (SDI app with a menu, status bar, and CFormview derived view)?

    Or do you have a app that displays a property sheet with pages (i.e. no status bar or menu)?
    Ok the breakdown is...

    I am using the standard templates the wizard generated for me for an SDI application. The only difference is that I've replaced the view to be a CTabCtrl explained below.

    CtabCtrl inherits from CScrollView and is used as the view in the SDI application. Within the tab control view class are 3 variables representing modeless dialogs designed in the resource wizard each containing controls to do a job. Dialogs consist mostly of listviews, comboboxes etc. The standard fair. Each of these dialogs is classed as a child and is a child of CTabCtrl. Each child dialog is contained in it's own class which has methods and variables to manage the elements.

    When the view is created Create() is called on all 3 variables representing the dialogs. This is done in OnInitialUpdate() of the view. I have a handler OnNotify() in the TabCtrl View which hides/shows the child dialogs depending which tab is selected.

    One child modeless dialog has a button to load a b-encoded file containing data. When the button is pushed it invokes a modal dialog which brings up a file browser (CFileDialog). Upon exit from CFileDialog if OK was selected a path/filename was selected and the value is read. This then needs to be passed to my document somehow which contains methods on how to parse a b-encoded file and extract relevant information to create data structures which worker threads will later use.

    Thats a simple explaination of how I want it to work from dialog ->..->document. I also don't want the dialog to have to know anything about the structure of the document for modularity reasons.

    The other path is that some worker threads based on the b-encoded data produce results and stores it in the document. When results are added/modified I then need to display them in one of the child dialogs CTabCtrl is managing so I need to shift data from CDocument->..->dialog. Again I don't want the document to have to know anything about the GUI for modularity reasons.

    Hope that is realitvely clear. I tried my best ..
    Last edited by jbem; July 5th, 2008 at 01:29 AM.

  13. #13
    Arjay's Avatar
    Arjay is online now Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    11,289

    Re: Exchanging data between dialogs and document. How!?.

    I can appreciate the concept of loose coupling, but I haven't seen folks pull it off in MFC unless the view is completely dynamic (say like in a list control that is getting data from a db).

    There really has to be some coupling between the doc and the view especially in the case of dialogs. After all, if the doc exposes some data, the dialog needs to know the type of controls needed to present the data.

    However you can achieve a degree of loose coupling with regard to documents and dialogs if you leverage the DDX mechanism.

    Consider a resusable 'person' dialog that contains first and last name edit controls.

    If we were to go the traditional MFC route, we would use the Add Member variable menu item to add a CString member variable to the first and last name edit controls (You do this be selecting the edit control, right click, choose Add Variable. From there you change the Category to Value and enter a variable name). The end result would be two DDX entries:

    Code:
    void CPersonDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT1, m_sNameFirst );
    	DDX_Text(pDX, IDC_EDIT2, m_sNameLast );
    }
    This is fine and we now have the edit control wired up to CString variables. It's a big improvement over using GetDialogItem and GetWindowText each time we need to retrieve the first and last name text. However it doesn't help us much with getting data to and from the document.

    What can solve this by passing a document pointer to the person dialog. I've created an SDI application called DocInterface (see the attached source), so we are going to pass in a CDocInterfaceDoc pointer to the dialog constructor and store it in the dialog as a m_pDocInterfaceDoc variable.

    Next we add some Person related data variables and method accessors to the document.

    Code:
    \\ Person data and accessors
    public:
      CString& GetNameFirst() { return m_sNameFirst; }
      CString& GetNameLast() { return m_sNameLast; }
    private:
      CString m_sNameFirst;
      CString m_sNameLast;
    Then we modify the DDX OnDataExchange to point to the data in the document (rather than the variables contained within the dialog).

    Code:
    void CPersonDlg::DoDataExchange(CDataExchange* pDX)
    {
    	CDialog::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT1, m_pDocInterfaceDoc->GetNameFirst( ) );
    	DDX_Text(pDX, IDC_EDIT2, m_pDocInterfaceDoc->GetNameLast( ) );
    }
    For cleanup, you can remove the first and last name CString variables from the dialog.

    I haven't shown the code to display the dialog, but I just created a 'Person...' entry in the Edit menu and created a handler in the document class. Where as initially we didn't pass any parameters to the constructor, now we pass the this pointer of the CDocInterfaceDoc class:
    Code:
    void CDocInterfaceDoc::OnEditPerson()
    {
    	CPersonDlg dlg( this );
    	dlg.DoModal( );
    }
    Btw, I launched the dialog from the view because of convenience and you may wish to launch it from a view or a frame class (but still pass in the CDocument point).

    At this point, when the person dlg is opened the first and last name edit boxes will be initialized from the document. When the user clicks OK, the first name values will be stored in the document. This happens without any additional code via DDX.

    That's great, but since we are passing a CDocInterfaceDoc pointer to the dialog, it is still tightly coupled.

    Let's look how we can reduce this coupling further.

    What we are going to do is to create an IPerson interface and derive the CDocInterfaceDoc class from this interface.

    Code:
    __interface IPerson
    {
    public:
     CString& GetNameFirst( );
     CString& GetNameLast( );
    };
    Code:
    class CDocInterfaceDoc : public CDocument, public IPerson
    {
    ...
    }
    We already have the GetNameFirst and GetNameLast accessors in the document so we don't need to implement those.

    Finally we modify the CPersonDlg. Instead of passing in and storing a CDocInterfaceDoc pointer, we change this to a generic CDocument pointer (see the code for the details).

    Then we modify OnDataExchange to use the person interface
    Code:
    void CPersonDlg::DoDataExchange(CDataExchange* pDX)
    {
    	// Use the IPerson interface in the document
    	// to retrieve the person related data accessors.
    	IPerson* iPerson = dynamic_cast< IPerson* > (m_pDocument);
    	CDialog::DoDataExchange(pDX);
    	DDX_Text(pDX, IDC_EDIT1, iPerson->GetNameFirst( ) );
    	DDX_Text(pDX, IDC_EDIT2, iPerson->GetNameLast( ) );
    }
    So now you have a bit less coupling and more reusability in the dialog. You can create common libraries with your custom dialogs paired with the corresponding interface.

    To use, you just derive the document from the interface and pass the generic document pointer to the [reusable] dialog.
    Attached Files Attached Files
    Last edited by Arjay; July 5th, 2008 at 04:13 PM.

  14. #14
    Arjay's Avatar
    Arjay is online now Moderator / MS MVP Power Poster
    Join Date
    Aug 2004
    Posts
    11,289

    Re: Exchanging data between dialogs and document. How!?.

    Years ago, there wasn't much talk of separating the data from the view and for a while MFC seemed to be the only framework that took a stab at it.

    Now there's quite a few design patterns to choose from:

    Model View Controller

    Model View Presenter

    Model View Controller/ViewModel (WPF)

  15. #15
    Join Date
    Dec 2005
    Posts
    9

    Re: Exchanging data between dialogs and document. How!?.

    Thanks for all the input. It certainly has given me something to think about. I'm not entirely sure I'm happy with the DDX alternative but it's interesting nonetheless. You are technically coupling the dialog to the end datastructure not associated with it so in a way it's not much better tha a pDocPtr passed in however it's nicer in that you let DDX do the work for you. It's interesting for the fact that I hadn't even though of using ddx that way. The idea will come in handy I'm sure going forward.

    I might go ahead with trying to use messaging as per original idea and see how it works in reality as the project gets more complex. I still think it's cleaner to just GetParent->Sendmessage() from the dialog and use a few structs and msgtypes to act as an event API to decouple the system. The interested party can then register for the messages and act on them anyway it wants. This way my dialog doesn't need to be used in a SDI/MDI app architecture even or be reliant on CDocument let alone a rigid datastructure defined external to the dialog and is as decoupled as you can get in my books.
    Last edited by jbem; July 7th, 2008 at 10:47 AM.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center