Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. WPF
  4. WPF TabControl Events

WPF TabControl Events

Scheduled Pinned Locked Moved WPF
wpfcsharpdatabasedesignarchitecture
27 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    Tom Delany
    wrote on last edited by
    #1

    This may be rather long. Please bear with me. I am working on a WPF app. I am trying very hard to follow MVVM design practices as I understand them. The MainWindow contains a TabControl. For each TabItem, I have created a separate UserControl in order to split things out logically and to make the XAML more manageable (there are going to be several tabs). Each UserControl has its own ViewModel, which is instantiated in the code behind for the particular UserControl. Each UserControl/ViewModel pair is pretty much self-contained, independent of the others. There is a common Model for all of the above that handles the database end of things (each ViewModel talks to its own instance of the Model). The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl). The thing that I am wrestling with is this: I would like to be able to prompt the end user to save any pending changes if they click into a different tab. Apparently, whenever you click on a different tab, the TabControl unloads the UserControl of the previously selected tab. The only event that seems to let me know that the user has clicked away into another tab is the Unloaded event for the UserControl. At that point, it appears to be too late to pop up a message from the User Control because it has, well, unloaded. :) I discovered that I can handle the SelectionChanged event for the TabControl in the MainWindow, but the way my code is structured, there is no way to get back to the ViewModel of the tab that was deselected to make it save the changes from there. Suggestions please... :-O

    WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

    L 1 Reply Last reply
    0
    • T Tom Delany

      This may be rather long. Please bear with me. I am working on a WPF app. I am trying very hard to follow MVVM design practices as I understand them. The MainWindow contains a TabControl. For each TabItem, I have created a separate UserControl in order to split things out logically and to make the XAML more manageable (there are going to be several tabs). Each UserControl has its own ViewModel, which is instantiated in the code behind for the particular UserControl. Each UserControl/ViewModel pair is pretty much self-contained, independent of the others. There is a common Model for all of the above that handles the database end of things (each ViewModel talks to its own instance of the Model). The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl). The thing that I am wrestling with is this: I would like to be able to prompt the end user to save any pending changes if they click into a different tab. Apparently, whenever you click on a different tab, the TabControl unloads the UserControl of the previously selected tab. The only event that seems to let me know that the user has clicked away into another tab is the Unloaded event for the UserControl. At that point, it appears to be too late to pop up a message from the User Control because it has, well, unloaded. :) I discovered that I can handle the SelectionChanged event for the TabControl in the MainWindow, but the way my code is structured, there is no way to get back to the ViewModel of the tab that was deselected to make it save the changes from there. Suggestions please... :-O

      WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      Tom Delany wrote:

      The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl).

      I think you just found yourself a need for it ;P If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs). The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.) If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates. I prefer this method (VM before View*) as it seems cleaner to me (no code behind) and often not doing it this way you run into such quirks as you have. You would not have even stumbled (most likely) if you coded VM before View *VM before View vs View before VM is one of those religous arguments of MVVM

      Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

      P T 3 Replies Last reply
      0
      • L Lost User

        Tom Delany wrote:

        The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl).

        I think you just found yourself a need for it ;P If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs). The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.) If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates. I prefer this method (VM before View*) as it seems cleaner to me (no code behind) and often not doing it this way you run into such quirks as you have. You would not have even stumbled (most likely) if you coded VM before View *VM before View vs View before VM is one of those religous arguments of MVVM

        Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

        P Offline
        P Offline
        Pete OHanlon
        wrote on last edited by
        #3

        There is a *gotcha* to this approach though (actually, there are a couple). First of all, when the selection changes, the TabControl has the unfortunate habit of unloading the View (hence unloading the DataContext), and rendering the new view. Second, how does he know that there's unsaved information - this relies on the binding being refreshed, which in turn, relies on the property update mechanism (in other words, is he relying on the focus being lost before the property updates).

        Forgive your enemies - it messes with their heads

        "Mind bleach! Send me mind bleach!" - Nagy Vilmos

        My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

        T L 2 Replies Last reply
        0
        • P Pete OHanlon

          There is a *gotcha* to this approach though (actually, there are a couple). First of all, when the selection changes, the TabControl has the unfortunate habit of unloading the View (hence unloading the DataContext), and rendering the new view. Second, how does he know that there's unsaved information - this relies on the binding being refreshed, which in turn, relies on the property update mechanism (in other words, is he relying on the focus being lost before the property updates).

          Forgive your enemies - it messes with their heads

          "Mind bleach! Send me mind bleach!" - Nagy Vilmos

          My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

          T Offline
          T Offline
          Tom Delany
          wrote on last edited by
          #4

          Thanks Pete. If there was just an "UnloadedPreview" event... :sigh:

          WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

          1 Reply Last reply
          0
          • L Lost User

            Tom Delany wrote:

            The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl).

            I think you just found yourself a need for it ;P If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs). The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.) If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates. I prefer this method (VM before View*) as it seems cleaner to me (no code behind) and often not doing it this way you run into such quirks as you have. You would not have even stumbled (most likely) if you coded VM before View *VM before View vs View before VM is one of those religous arguments of MVVM

            Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

            T Offline
            T Offline
            Tom Delany
            wrote on last edited by
            #5

            Thanks Collin. Thanks for the tip. Sounds like I need to seriously rethink my way of doing things. :confused: You have given me food for thought. :thumbsup:

            WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

            L P 2 Replies Last reply
            0
            • P Pete OHanlon

              There is a *gotcha* to this approach though (actually, there are a couple). First of all, when the selection changes, the TabControl has the unfortunate habit of unloading the View (hence unloading the DataContext), and rendering the new view. Second, how does he know that there's unsaved information - this relies on the binding being refreshed, which in turn, relies on the property update mechanism (in other words, is he relying on the focus being lost before the property updates).

              Forgive your enemies - it messes with their heads

              "Mind bleach! Send me mind bleach!" - Nagy Vilmos

              My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              I am not seeing how those are 'gotchas', unless one uses code behind. The DataContext will be unloaded from the view binding, however the 'MainViewModel' will still have its previous selected item in the setter call.

              public ITabItem SelectedItem
              {
              get{return _selectedItem;}
              set
              {
              if(_selectedItem == value)return;

                 //have to have some sort of check or you can blindly prompt always
                 PromptUserIfNeedBe(); 
                 
                 //Now it is safe to update the local value
                 \_selectedItem = value;    
              
                RaisePropertyChanged("SelectedItem");
              }
              

              }

              As for how to know if there is unsaved information, I did breeze over that. I guess I assumed he had some sort of business object tracking that (bad assumption though). I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though). He of course needs to be doing something along those lines in order to properly prompt the user. Perhaps you could share that posting with him.

              Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

              P T 2 Replies Last reply
              0
              • T Tom Delany

                Thanks Collin. Thanks for the tip. Sounds like I need to seriously rethink my way of doing things. :confused: You have given me food for thought. :thumbsup:

                WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #7

                You are welcome. Are you using a base business object that tracks changes? This will allow you to do a simple check in the "SelectedItem" setter to prompt the user (in responce to Pete's comments). If not you may want to look into using some implimentation of IEditableObject or something similar.

                Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

                1 Reply Last reply
                0
                • L Lost User

                  I am not seeing how those are 'gotchas', unless one uses code behind. The DataContext will be unloaded from the view binding, however the 'MainViewModel' will still have its previous selected item in the setter call.

                  public ITabItem SelectedItem
                  {
                  get{return _selectedItem;}
                  set
                  {
                  if(_selectedItem == value)return;

                     //have to have some sort of check or you can blindly prompt always
                     PromptUserIfNeedBe(); 
                     
                     //Now it is safe to update the local value
                     \_selectedItem = value;    
                  
                    RaisePropertyChanged("SelectedItem");
                  }
                  

                  }

                  As for how to know if there is unsaved information, I did breeze over that. I guess I assumed he had some sort of business object tracking that (bad assumption though). I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though). He of course needs to be doing something along those lines in order to properly prompt the user. Perhaps you could share that posting with him.

                  Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

                  P Offline
                  P Offline
                  Pete OHanlon
                  wrote on last edited by
                  #8

                  Collin Jasnoch wrote:

                  I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though).

                  No, you're right - it was me. As for the other part, I'm sorry - I misunderstood what you'd pointed out - you're entirely right that the previously selected value will be in there. I glossed right over you talking about needing a main VM, so I apologise; I really should read things more carefully.

                  Forgive your enemies - it messes with their heads

                  "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                  My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                  L 1 Reply Last reply
                  0
                  • T Tom Delany

                    Thanks Collin. Thanks for the tip. Sounds like I need to seriously rethink my way of doing things. :confused: You have given me food for thought. :thumbsup:

                    WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                    P Offline
                    P Offline
                    Pete OHanlon
                    wrote on last edited by
                    #9

                    Tom - the IEditableObject info that Collin was talking about was covered in a blog post that I wrote here[^].

                    Forgive your enemies - it messes with their heads

                    "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                    My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                    T 1 Reply Last reply
                    0
                    • P Pete OHanlon

                      Collin Jasnoch wrote:

                      I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though).

                      No, you're right - it was me. As for the other part, I'm sorry - I misunderstood what you'd pointed out - you're entirely right that the previously selected value will be in there. I glossed right over you talking about needing a main VM, so I apologise; I really should read things more carefully.

                      Forgive your enemies - it messes with their heads

                      "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                      My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                      L Offline
                      L Offline
                      Lost User
                      wrote on last edited by
                      #10

                      No problem :)

                      Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

                      1 Reply Last reply
                      0
                      • L Lost User

                        I am not seeing how those are 'gotchas', unless one uses code behind. The DataContext will be unloaded from the view binding, however the 'MainViewModel' will still have its previous selected item in the setter call.

                        public ITabItem SelectedItem
                        {
                        get{return _selectedItem;}
                        set
                        {
                        if(_selectedItem == value)return;

                           //have to have some sort of check or you can blindly prompt always
                           PromptUserIfNeedBe(); 
                           
                           //Now it is safe to update the local value
                           \_selectedItem = value;    
                        
                          RaisePropertyChanged("SelectedItem");
                        }
                        

                        }

                        As for how to know if there is unsaved information, I did breeze over that. I guess I assumed he had some sort of business object tracking that (bad assumption though). I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though). He of course needs to be doing something along those lines in order to properly prompt the user. Perhaps you could share that posting with him.

                        Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

                        T Offline
                        T Offline
                        Tom Delany
                        wrote on last edited by
                        #11

                        Collin Jasnoch wrote:

                        As for how to know if there is unsaved information, I did breeze over that. I guess I assumed he had some sort of business object tracking that (bad assumption though).

                        I'm using DevForce for the Model end of things. I can tell if there is unsaved data or not. That should not be a problem.

                        Collin Jasnoch wrote:

                        I think you and I conversed about this before (I believe you have a blog post about using IEditableObject... It might have been someone else though). He of course needs to be doing something along those lines in order to properly prompt the user. Perhaps you could share that posting with him.

                        I would be interested in seeing that discussion. :thumbsup: [Edit: Pete gave me the link.]

                        WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                        1 Reply Last reply
                        0
                        • P Pete OHanlon

                          Tom - the IEditableObject info that Collin was talking about was covered in a blog post that I wrote here[^].

                          Forgive your enemies - it messes with their heads

                          "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                          My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                          T Offline
                          T Offline
                          Tom Delany
                          wrote on last edited by
                          #12

                          Thanks Pete. :)

                          WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                          P 1 Reply Last reply
                          0
                          • T Tom Delany

                            Thanks Pete. :)

                            WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                            P Offline
                            P Offline
                            Pete OHanlon
                            wrote on last edited by
                            #13

                            No problem. Glad to be able to help.

                            Forgive your enemies - it messes with their heads

                            "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                            My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                            1 Reply Last reply
                            0
                            • L Lost User

                              Tom Delany wrote:

                              The MainWindow does NOT have a MainWindowViewModel as I have found no need for it (all the MainWindow does is hold a text heading and the TabControl).

                              I think you just found yourself a need for it ;P If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs). The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.) If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates. I prefer this method (VM before View*) as it seems cleaner to me (no code behind) and often not doing it this way you run into such quirks as you have. You would not have even stumbled (most likely) if you coded VM before View *VM before View vs View before VM is one of those religous arguments of MVVM

                              Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.

                              T Offline
                              T Offline
                              Tom Delany
                              wrote on last edited by
                              #14

                              Collin, I've been mulling over your post. It has brought more questions to mind. (Sorry. :-O) Let me preface what follows with: If I ask something really obvious or stupid, please forgive me. I have been programming for quite a few years, but I am a WPF neophyte. Ditto, if I use the wrong terminology for something. I'm not a GUI programmer ( :doh: ), but I am the only PC programmer in our group, and have been forced to jump into this with both feet. I don't really mind as I like to learn new things, but the WPF / MVVM learning curve has been frustrating for me. :sigh:

                              Collin Jasnoch wrote:

                              If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs).
                              The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.)

                              That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class (yeah, I should have done that from the outset) that they are all derived from, so that I can create an ObservableCollection of the base class objects? Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?

                              Collin Jasnoch wrote:

                              If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates.

                              Right now, each TabItem in my TabControl is populated with a separate (but very similar) UserControl that consists of a 3 column Grid with a ListBox in column 0, a GridSplitter in column 1, and another Grid in Column 2. The second Grid in column 2 is a 3 row Grid with the first row containing a TextBlock that is basically a header, the 2nd row containing various TextBlocks and TextBoxes for displaying/entering data, and the last row holding several Buttons. Clicking on an item in the ListBox on the left brings up the corresponding data in the fields on the right. How would I turn this into a DataTemplate? What about the buttons?

                              Collin Jasnoch wrote:

                              I prefer this method (VM before View*) as it seems cleaner to me (no code behind)

                              Dumb question: isn't a certain amount of code behind unavoidable?

                              M L 2 Replies Last reply
                              0
                              • T Tom Delany

                                Collin, I've been mulling over your post. It has brought more questions to mind. (Sorry. :-O) Let me preface what follows with: If I ask something really obvious or stupid, please forgive me. I have been programming for quite a few years, but I am a WPF neophyte. Ditto, if I use the wrong terminology for something. I'm not a GUI programmer ( :doh: ), but I am the only PC programmer in our group, and have been forced to jump into this with both feet. I don't really mind as I like to learn new things, but the WPF / MVVM learning curve has been frustrating for me. :sigh:

                                Collin Jasnoch wrote:

                                If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs).
                                The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.)

                                That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class (yeah, I should have done that from the outset) that they are all derived from, so that I can create an ObservableCollection of the base class objects? Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?

                                Collin Jasnoch wrote:

                                If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates.

                                Right now, each TabItem in my TabControl is populated with a separate (but very similar) UserControl that consists of a 3 column Grid with a ListBox in column 0, a GridSplitter in column 1, and another Grid in Column 2. The second Grid in column 2 is a 3 row Grid with the first row containing a TextBlock that is basically a header, the 2nd row containing various TextBlocks and TextBoxes for displaying/entering data, and the last row holding several Buttons. Clicking on an item in the ListBox on the left brings up the corresponding data in the fields on the right. How would I turn this into a DataTemplate? What about the buttons?

                                Collin Jasnoch wrote:

                                I prefer this method (VM before View*) as it seems cleaner to me (no code behind)

                                Dumb question: isn't a certain amount of code behind unavoidable?

                                M Offline
                                M Offline
                                Mycroft Holmes
                                wrote on last edited by
                                #15

                                Tom Delany wrote:

                                Like for Button Click and other event handlers

                                Most if not all of these can be handled by the VM, we use the MVVMLight framework and it does the job nicely, and once you have the pattern set it does not vary much.

                                Tom Delany wrote:

                                I have been trying to keep what I do there to a bare minimum

                                While this probably should be the goal of all of us I don't think it should be religious. I'm always pleased to move something into the VM but I'm not distressed if there is code behind. I figure there must be a balance of ROI on time spent figuring out how to move something into the VM and getting the job done.

                                Never underestimate the power of human stupidity RAH

                                T 1 Reply Last reply
                                0
                                • M Mycroft Holmes

                                  Tom Delany wrote:

                                  Like for Button Click and other event handlers

                                  Most if not all of these can be handled by the VM, we use the MVVMLight framework and it does the job nicely, and once you have the pattern set it does not vary much.

                                  Tom Delany wrote:

                                  I have been trying to keep what I do there to a bare minimum

                                  While this probably should be the goal of all of us I don't think it should be religious. I'm always pleased to move something into the VM but I'm not distressed if there is code behind. I figure there must be a balance of ROI on time spent figuring out how to move something into the VM and getting the job done.

                                  Never underestimate the power of human stupidity RAH

                                  T Offline
                                  T Offline
                                  Tom Delany
                                  wrote on last edited by
                                  #16

                                  Thanks. It's nice to see common sense applied when blogs, etc. that I have read on the subject sometimes almost take on religious zealotry. :)

                                  WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                                  1 Reply Last reply
                                  0
                                  • T Tom Delany

                                    Collin, I've been mulling over your post. It has brought more questions to mind. (Sorry. :-O) Let me preface what follows with: If I ask something really obvious or stupid, please forgive me. I have been programming for quite a few years, but I am a WPF neophyte. Ditto, if I use the wrong terminology for something. I'm not a GUI programmer ( :doh: ), but I am the only PC programmer in our group, and have been forced to jump into this with both feet. I don't really mind as I like to learn new things, but the WPF / MVVM learning curve has been frustrating for me. :sigh:

                                    Collin Jasnoch wrote:

                                    If you had a MainViewModel then the TabControl could have its ItemSource bound to a collection of your viewmodels (the data contexts of the Tabs).
                                    The Tab Control can also maintain binding of "SelectedItem". When it changes you could then run any logic you wanted to (prompt user to save etc.)

                                    That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class (yeah, I should have done that from the outset) that they are all derived from, so that I can create an ObservableCollection of the base class objects? Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?

                                    Collin Jasnoch wrote:

                                    If you choose this path, rather than having the View instantiate the VM*, the MainVM does the work. Then you just need to tell the renderer how to render the object using DataTemplates.

                                    Right now, each TabItem in my TabControl is populated with a separate (but very similar) UserControl that consists of a 3 column Grid with a ListBox in column 0, a GridSplitter in column 1, and another Grid in Column 2. The second Grid in column 2 is a 3 row Grid with the first row containing a TextBlock that is basically a header, the 2nd row containing various TextBlocks and TextBoxes for displaying/entering data, and the last row holding several Buttons. Clicking on an item in the ListBox on the left brings up the corresponding data in the fields on the right. How would I turn this into a DataTemplate? What about the buttons?

                                    Collin Jasnoch wrote:

                                    I prefer this method (VM before View*) as it seems cleaner to me (no code behind)

                                    Dumb question: isn't a certain amount of code behind unavoidable?

                                    L Offline
                                    L Offline
                                    Lost User
                                    wrote on last edited by
                                    #17

                                    Tom Delany wrote:

                                    That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class

                                    While you should always be trying to find commonalities etc (re-factoring) don't worry about it to much. Remember you can always do this...

                                    public interface ITabItem
                                    {
                                    //Don't need anything, but here is where you can put your new event
                                    }

                                    Then just have all your VMs with in the collection use it. Then your collection is just ObservableCollection<ITabItem>

                                    Tom Delany wrote:

                                    Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?

                                    Not exactly. When doing VM first, you really don't bind the data context object to the view's data context property. Instead you use DataTemplates. There are a couple (er many) ways to acheive this. The simplest to understand IMO is to define the DataTemplate to target that type of object, and pop in the view.

                                    *No VS right now, but I am pretty sure this is right. Place this DataTemplate in a resource dictionary and reference the dictionary in the UserControl that has the TabControl. It will then render the "OneOfYourViewModel" object as a "TheCorrespondingView" user control. Another way is to define the DataTemplate with a key and then reference it for your "ItemTemplate". This is why it is VM first. The VM is actually built first, and then when the UI wants to render it checks its datatemplate. If one is not set it will do what it knows how to, ToString and you will end up with the object name. The way you have explained is another methodology where the UserControls are constructed then they each (or some injection using a pattern) construct their datacontext.

                                    Tom Delany wrote:

                                    How would I turn this into a DataTemplate? What about the buttons?

                                    I hope it is clear about the user control. Just pop it into a DataTemplate and you are good to go. As for Buttons, they have a property 'Command' that is a DP which you can bind an ICommand object to (i.e. your RelayCommand in your VMs). For the most part you can avoid using 'events' they w

                                    T 2 Replies Last reply
                                    0
                                    • L Lost User

                                      Tom Delany wrote:

                                      That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class

                                      While you should always be trying to find commonalities etc (re-factoring) don't worry about it to much. Remember you can always do this...

                                      public interface ITabItem
                                      {
                                      //Don't need anything, but here is where you can put your new event
                                      }

                                      Then just have all your VMs with in the collection use it. Then your collection is just ObservableCollection<ITabItem>

                                      Tom Delany wrote:

                                      Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?

                                      Not exactly. When doing VM first, you really don't bind the data context object to the view's data context property. Instead you use DataTemplates. There are a couple (er many) ways to acheive this. The simplest to understand IMO is to define the DataTemplate to target that type of object, and pop in the view.

                                      *No VS right now, but I am pretty sure this is right. Place this DataTemplate in a resource dictionary and reference the dictionary in the UserControl that has the TabControl. It will then render the "OneOfYourViewModel" object as a "TheCorrespondingView" user control. Another way is to define the DataTemplate with a key and then reference it for your "ItemTemplate". This is why it is VM first. The VM is actually built first, and then when the UI wants to render it checks its datatemplate. If one is not set it will do what it knows how to, ToString and you will end up with the object name. The way you have explained is another methodology where the UserControls are constructed then they each (or some injection using a pattern) construct their datacontext.

                                      Tom Delany wrote:

                                      How would I turn this into a DataTemplate? What about the buttons?

                                      I hope it is clear about the user control. Just pop it into a DataTemplate and you are good to go. As for Buttons, they have a property 'Command' that is a DP which you can bind an ICommand object to (i.e. your RelayCommand in your VMs). For the most part you can avoid using 'events' they w

                                      T Offline
                                      T Offline
                                      Tom Delany
                                      wrote on last edited by
                                      #18

                                      Thanks Collin. Clear as mud. ;) Actually, I think I understand what you mean. A couple of things I feel a little fuzzy about, but I think I have enough info. to sort it out. If I run up against something I can't figure out, hopefully you won't mind if I bug you again. :-O

                                      WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                                      L 1 Reply Last reply
                                      0
                                      • L Lost User

                                        Tom Delany wrote:

                                        That sounds very sensible to me. Obviously (?) my ViewModels are not exactly the same. I guess I should find what is common among them and turn that into a base class

                                        While you should always be trying to find commonalities etc (re-factoring) don't worry about it to much. Remember you can always do this...

                                        public interface ITabItem
                                        {
                                        //Don't need anything, but here is where you can put your new event
                                        }

                                        Then just have all your VMs with in the collection use it. Then your collection is just ObservableCollection<ITabItem>

                                        Tom Delany wrote:

                                        Since the ItemSource is bound to the ObservableCollection, this would take care of setting the DataContext for each TabItem?

                                        Not exactly. When doing VM first, you really don't bind the data context object to the view's data context property. Instead you use DataTemplates. There are a couple (er many) ways to acheive this. The simplest to understand IMO is to define the DataTemplate to target that type of object, and pop in the view.

                                        *No VS right now, but I am pretty sure this is right. Place this DataTemplate in a resource dictionary and reference the dictionary in the UserControl that has the TabControl. It will then render the "OneOfYourViewModel" object as a "TheCorrespondingView" user control. Another way is to define the DataTemplate with a key and then reference it for your "ItemTemplate". This is why it is VM first. The VM is actually built first, and then when the UI wants to render it checks its datatemplate. If one is not set it will do what it knows how to, ToString and you will end up with the object name. The way you have explained is another methodology where the UserControls are constructed then they each (or some injection using a pattern) construct their datacontext.

                                        Tom Delany wrote:

                                        How would I turn this into a DataTemplate? What about the buttons?

                                        I hope it is clear about the user control. Just pop it into a DataTemplate and you are good to go. As for Buttons, they have a property 'Command' that is a DP which you can bind an ICommand object to (i.e. your RelayCommand in your VMs). For the most part you can avoid using 'events' they w

                                        T Offline
                                        T Offline
                                        Tom Delany
                                        wrote on last edited by
                                        #19

                                        Collin Jasnoch wrote:

                                        Place this DataTemplate in a resource dictionary and reference the dictionary in the UserControl that has the TabControl. It will then render the "OneOfYourViewModel" object as a "TheCorrespondingView" user control.

                                        Create a ResourceDictionary under Application.Resources or in the MainWindows under Window.Resources, or does it really matter as long as it's closer to the root than where it is used?

                                        Collin Jasnoch wrote:

                                        reference the dictionary in the UserControl that has the TabControl.

                                        Will you show me a XAML example of what you mean?

                                        Collin Jasnoch wrote:

                                        Another way is to define the DataTemplate with a key and then reference it for your "ItemTemplate".

                                        I thought I had figured this way out, but then I stumbled because I have multiple DataTemplates and I was not sure if I still created a ResourceDictionary and gave it a key, and then bound that to the "ItemTemplate" of the TabControl, or if I had to assign a key to each template and somehow bind each one to ... something :confused:? Sorry. I'm a moron... :sigh:

                                        WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                                        P 1 Reply Last reply
                                        0
                                        • T Tom Delany

                                          Collin Jasnoch wrote:

                                          Place this DataTemplate in a resource dictionary and reference the dictionary in the UserControl that has the TabControl. It will then render the "OneOfYourViewModel" object as a "TheCorrespondingView" user control.

                                          Create a ResourceDictionary under Application.Resources or in the MainWindows under Window.Resources, or does it really matter as long as it's closer to the root than where it is used?

                                          Collin Jasnoch wrote:

                                          reference the dictionary in the UserControl that has the TabControl.

                                          Will you show me a XAML example of what you mean?

                                          Collin Jasnoch wrote:

                                          Another way is to define the DataTemplate with a key and then reference it for your "ItemTemplate".

                                          I thought I had figured this way out, but then I stumbled because I have multiple DataTemplates and I was not sure if I still created a ResourceDictionary and gave it a key, and then bound that to the "ItemTemplate" of the TabControl, or if I had to assign a key to each template and somehow bind each one to ... something :confused:? Sorry. I'm a moron... :sigh:

                                          WE ARE DYSLEXIC OF BORG. Refutance is systile. Your a$$ will be laminated. There are 10 kinds of people in the world: People who know binary and people who don't.

                                          P Offline
                                          P Offline
                                          Pete OHanlon
                                          wrote on last edited by
                                          #20

                                          Tom Delany wrote:

                                          Create a ResourceDictionary under Application.Resources

                                          Typically, you create an external ResourceDictionary file and then reference it in your App.Xaml (in the ResourceDictionary section). This would look something like this:

                                          <Application.Resources>
                                          <ResourceDictionary>
                                          <ResourceDictionary.MergedDictionaries>
                                          <ResourceDictionary Source="AppResources.xaml" />
                                          </ResourceDictionary.MergedDictionaries>
                                          </ResourceDictionary>
                                          </Application.Resources>

                                          Forgive your enemies - it messes with their heads

                                          "Mind bleach! Send me mind bleach!" - Nagy Vilmos

                                          My blog | My articles | MoXAML PowerToys | Mole 2010 - debugging made easier - my favourite utility

                                          T 1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular
                                          • World
                                          • Users
                                          • Groups