Click here to Skip to main content
15,893,487 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a Parent Window in my WPF project. The parent window has a tabbed interface. The TabItems are the different Pages that open on clicking different Menu options in the Window. Now I have some buttons in the Window, my motive is to create a common control like print or delete in the main window. When I click this buttons it will take its effect on the currently opened tabbed child page. Suppose I have two Child pages :-
1>Item Master
2>Account Master
both of these pages are opened in tabbed interface of the parent window, the Item Master page is currently being viewed/selected/active tabItem.
now I have the delete option from common controls panel in the Main window.
When I select any Item from a grid in the Item master and click delete button in Main window it will delete the Item from that Item Master page directly.

Now I select The Account Master Tabitem and its the active tabitem I want to print a record from the account Master page grid. I select a record from account master grid in its page and click the print button on the main window. That record from that account master gets printed.
I don't want a very complicated tool or round about way cause the print and delete methods are written in the page itself. All pages would have this methods and codes to perform the actions will be written in that method only. All i need is to fire this methods in the page on the click of window common control buttons. It would also be good if i get a way to disable this buttons from the page itself according to page requirement e.g. some page might not have any such data to print so that button from the window will be disabled while the page is active tabitem.

So this is total scenario I have no. of menu driven pages all opens as tab item. What I want to do is when I click a button from the common control of the main window it fires the event of the currently active tabitem page.

how can I achieve this, please help me out I am new to wpf. Explanation with some examples would be helpful.

Thank You
Posted
Updated 19-Feb-15 18:48pm
v2

Mr J Sinha wrote:

C#
private void MenuItem_Click_AcMap(object sender, RoutedEventArgs e)
{
    if (TabWindow.Items.Contains(tabAcMap) == false)
    {
        Frame tabFrame = new Frame();
        tabAcMap.Title = "AC Mapping Master";
        tabAcMap.IsEnabled = true;
        MstAccMapping DepCls = new MstAccMapping();
        tabFrame.Content = DepCls;
        tabAcMap.FontSize = 9;
        tabAcMap.Content = tabFrame;
        TabWindow.Items.Add(tabAcMap);
        TabWindow.SelectedItem = tabAcMap;
    }
    else
    {
        TabWindow.SelectedItem = tabAcMap;
    }
}


This is how i dynamically create the tab item and set a my page in that tab item in the main window.. I said I'm new to it... but giving up is not and option for me... so in this case how do i get to access the events in this page from the window button click... i cant find any possible way in which i can dynamically find the tabitem and its contents inside it
Not giving up? My respect.

Let's see. First of all, next time, don't put code in comment, where it is unreadable.I already suggested to use "Improve question", where you can format code properly (see above).

What is "access events"? As I explained, for the events you did not declare in your class, you can only handle them. You need to understand how and what it means. Basically, you create some delegate instance (to become an event handler), of required signature and add it to the invocation list of the event instance using the operator '+='. Then the method of the delegate instance added will be called every time the event is invoked. You can added several handles to the same delegate instance; they will be added as for delegate instances, as I explained in my article "Dynamic Method Dispatcher", in the section 4.1: Dynamic Method Dispatcher[^].

When something invokes the event, all you event handlers are called. You can add more or even remove some. If it was "regular" delegate instance in your own class, you could control this, but what you have will also call all handlers.

Now, you need to add a handler yourself, without the help of the designer (I actually nearly never allow the designer to add event handles for me, but this can be considered as a matter of individual taste). For example, it looks like your tabAcMap is of the type TabItem. Let's see how to add an event handler to be called each time this item gets focus:
C#
tabAcMap.GotFocus += (sender, eventArgs) => {
    // let's illustrate how to find the instance of TabItem inside the handler:
    TabItem senderAsTypeItem = (TabItem)sender;
    // eventArgs are insignificant here,
    // but in many other events that carry data,
    // for example, mouse coordinates
    // and, now:
    DoSomethingInResponseToGettingFocus(senderAsTypeItem);
};
The convenience of this lambda notation is that it includes type inference for the arguments, so you don't have to write the types of sender and eventArgs, but you can always read in the documentation on each event's delegate type what are they. More usually, people just look what intellisense shows. There are other forms:
C#
tabAcMap.GotFocus += MyMethodHandlingGotFocus; // no new required as many mistakenly think
// but you need to have some method MyMethodHandlingGotFocus with precisely correct signature
// (two parameters mentioned above)

Another anonymous form, equivalent to the first sample:
C#
tabAcMap.GotFocus += delegate(/* with exact parameter type */) {/* ... */}


In both anonymous forms, you have access to "this", the reference to the instance of declaring class, that's why you can, for example, call its instance methods (such as "DoSomethingInResponseToGettingFocus"). And, naturally, you have the same if you handler method (2nd sample) is the instance method. With both anonymous method forms, you can also use the effect of closure: http://en.wikipedia.org/wiki/Closure_(computer_programming)[^].
But be careful with closures; if you poorly understand how it works, pass all objects needed for handling through "this".

You did not explain which events (did you mean all? this would be not how things work), so I've shown only one. Hope you can cope with EventArgs members if there is a need to use them. Something unclear? Ask further questions.

—SA
 
Share this answer
 
Comments
Mr J Sinha 21-Feb-15 1:23am    
Thank You very much.. I apologize for not using the Theoretical terms which would help others to understand. I now know the difference when I say "access" and when its actually called handlers. But honestly I owe you big time. I took the help from your
Dynamic Method Dispatcher article and using rest of the knowledge you gave about event handling I thought of a way in which I created an Interface. the Interface has methods. I added handlers for the main window control buttons as suggested by you. Found out the selected item from the tab and the page within it(little tricky though). Finally after that i called the interface method. This interface is also used in my page (inherited as i would as) and the method in the interface was overridden here in the page and all the code to perform some action was written in overridden method in the page.So when i invoke the interface method for the main window, after finding the selected page it goes to the interface method overridden in that page.. Thus providing my solution. I don't know how much i have been able to explain you, cause I m bad at theoretical terminology. but let me post wat i did in codes in a solution below.
Sergey Alexandrovich Kryukov 21-Feb-15 2:30am    
Sounds good so far. You are very welcome.
Good luck, call again.
—SA
Kuthuparakkal 21-Feb-15 15:54pm    
SA 5*, my +5
Sergey Alexandrovich Kryukov 21-Feb-15 20:33pm    
Thank you, Kuthuparakkal.
—SA
The question is formulated clearly, I appreciate it, but it is way more complicated that it has to be. This approach is wrong. You should capture the essence of the real problem and try to reduce your application to something as simple as possible still having the same problem. Ask yourself: "in what simplest possible application I would have the same problem" and then describe it, even better, with a comprehensive code sample.

But this is just about time. I clearly understood the problem (or its comprehensible part). Basically, you are missing two important things.

First thing is: there is no such thing as "method on a page". A TabPage is just one of the controls, which is a member of some class, which can be your window class, some you custom or user control class, or something else. A method specifically related to this page can be a method of this class, that is, a static method, which can accept references to any control instances via its parameters. Or it can be an instance method of this class, which means that it can have the same or other parameter, plus one extra method, implicit one, "this" which is the instance of this class you can access inside the body of this method. That's all. This is a key: you need to understand that the problem is somewhat artificial: 1) the scope of the method is the class which instance is a parent (direct + indirect) of many control instances; 3) control instance references can be passed to it as arguments.

There is another thing you are missing? Did you notice that in the title of the question you are asking about method, and at the end, you are asking about "firing an event"? Those are very different things. You cannot really "fire" and event (correct terminology is "invoke event"). More exactly, you can only invoke the event in the method of the type declaring this event. Even if one class declared event instance, and you derive a class from it, you cannot invoke this event in the derived class. This is an important fool-proof feature of .NET. Why so? Because it protects you from doing something which is really never needed. This is a mean of inversion of control: you only invoke some events in some declaring class (most likely, you don't do it at all, so you cannot invoke them, too; most likely, you are talking about events which are not yours), you only handle the event in the code of other types. Instead, you really need to call some methods or properties related to the page in your handler of the Click events. By the way, in WPF its better to use its commanding system: https://msdn.microsoft.com/en-us/library/ms752308%28v=vs.110%29.aspx[^].

I called your problems "artificial" but they are not completely artificial; there are no the obstacles you imagined, but some problems still exist: there is always a problem to organize the code in a neat way. You mentioned enabling and disabling some control. Again, this is not "firing events" but is calling IsVisible properties. You can write the Name attributes in your XAML, to make it generating instance names for the controls you want to operate, and set the property of each instance individually, by name, but this would be way to much of ad-hoc approach in many cases, and quite poorly maintainable if you have many such controls. Instead, you can group those controls and enable/disable the whole group. For example, you could put some control in the same Panel. By the way, you don't need to disable control on a hidden (non-selected) TabPage: they are invisible and cannot be used.

Well, some ideas… And no, we did not yest came to the point of showing you some code samples. I would prefer if you showed some code sample and asked some questions based on that. Note that your questions not only formulated in a complicated way, but also not specific enough for that. It's all right, you can ask your follow-up questions later. You can use "Improve question" any time.

—SA
 
Share this answer
 
Comments
Mr J Sinha 20-Feb-15 2:10am    
I'd very happy to provide you an example of code for your better understanding of my problems.. but i am new to this and i dont have much of idea where to start from. I jus simply need to know how do I fire an event in a page on the click of a button from the window? to be clear I need to know how the button click event finds the active tab page and fires the event that wants it to... So it will be a great help if you could give me a start or something that tells me where to start from
Sergey Alexandrovich Kryukov 20-Feb-15 2:47am    
Well, the problem is: it's hard to figure out what can help you. You are diffused between several different kinds of confusion. Events don't "find" anything. In a handler, you ask the instance of TabContol the index of its active page. Did you see the MSDN page on TabControl. And so on. Now, after you another question, I don't understand if you know how to handle events at all. If not, you would need to set aside WPF (or any other UI) for a while...
—SA
Mr J Sinha 20-Feb-15 3:58am    
private void MenuItem_Click_AcMap(object sender, RoutedEventArgs e)
{
if (TabWindow.Items.Contains(tabAcMap) == false)
{
Frame tabFrame = new Frame();
tabAcMap.Title = "AC Mapping Master";
tabAcMap.IsEnabled = true;
MstAccMapping DepCls = new MstAccMapping();
tabFrame.Content = DepCls;
tabAcMap.FontSize = 9;
tabAcMap.Content = tabFrame;
TabWindow.Items.Add(tabAcMap);
TabWindow.SelectedItem = tabAcMap;
}
else
{
TabWindow.SelectedItem = tabAcMap;
}
}


This is how i dynamically create the tab item and set a my page in that tab item in the main window.. I said I'm new to it.. but giving up is not and option for me... so in this case how do i get to access the events in this page from the window button click... i cant find any possible way in which i can dynamically find the tabitem and its contents inside it
This is the interface
C#
 public interface ChildPageNav
    {
        /// <summary>
     /// For New Button Event
     /// </summary>
        void New();
}


Now the main window
C#
 internal void btnAdd_Click(object obj, EventArgs e)
        {
            TabItem ti = TabWindow.SelectedItem as TabItem;
            Frame f = ti.Content as Frame;
            ChildPageNav page = f.Content as ChildPageNav;
           
            if (page != null) page.New();
        }

private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
        {
            btnAdd.Click += new RoutedEventHandler(btnAdd_Click);
          
            Application.Current.MainWindow = this;
        }


Finally the page where I used the interface

C#
public partial class MstAccMapping : System.Windows.Controls.Page, ChildPageNav
   {
 public MstAccMapping()
        {
            InitializeComponent();
        }

 public void New()
        {
            //Actions I needed to perform on button click
        }

}


I hope this is the right way as it works just fine. The interface acts as a bridge between the window and page
 
Share this answer
 
v2
Comments
Kuthuparakkal 21-Feb-15 15:55pm    
Self goal ?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900