1

I have MainWindow.xaml and another Page.xaml in same namespace

On MainWindow are textblock and frame.

Frame on MainWindow showing Page.xaml and on that Page is one Button.

I want Call non-static method in MainWindow with that Button, but i dont know how :(

For example:

MainWindow.xaml.cs

    namespace wpfapp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            openframe();
        }

        private void openframe()
        {
            frame1.Source = new Uri("testapge.xaml", UriKind.Relative);

        }
        public void MyMethod()
        {
            textblock1.Text = "This text is showed on MainWindow if i click to the Button";
        }    
    }
}

Page.xaml.cs

    namespace wpfapp
{
    public partial class Page : Page
    {
        public Page()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MainWindow trytocallit = new MainWindow();
            trytocallit.MyMethod();
        }
    }
}

This of course doesnt work. Thank for your help!

5 Answers5

3

As alternative and fast solution, you can use following code

Usage:

   MainWindow mainWindow = GetMainWindow();

Method:

    public static MainWindow GetMainWindow() 
    {
        MainWindow mainWindow=null;

        foreach (Window window in Application.Current.Windows)
        {
            Type type = typeof(MainWindow);
            if (window != null && window.DependencyObjectType.Name == type.Name)
            {
                 mainWindow = (MainWindow)window;
                if (mainWindow != null)
                {
                    break;
                }
            }
        }


        return mainWindow;

    }
Ugur
  • 1,257
  • 2
  • 20
  • 30
  • Thank you, i am try it, but i have a problem with it: The name 'ParentFinder' does not exist in the current context .. i try change it for something, for example MainWindow, now program can start, but button1 dont working, sorry this, you can try show me whole and functional code? I would like to understand – John Majlstounn Mar 19 '15 at 07:28
  • Ah sorry buddy, Just u should put the above method into any class to call it. For me it was ParentFinder.cs. So I have edited again, please have a look. – Ugur Mar 19 '15 at 07:47
  • okay, but what now? i try do some changes, it not working :( – John Majlstounn Mar 19 '15 at 07:55
  • Now its going without errors, its great, but how can i change texblock value with it? i am try it, but i dont know – John Majlstounn Mar 19 '15 at 08:03
  • Please modify the method "public void MyMethod()" . It can take string argument like public void MyMethod(string text). Normally you should bind the Text property of the Textblock and update via properties. – Ugur Mar 19 '15 at 08:06
  • Okay, i edited MyMethod() to MyMethod(string text) in MainWindows.xaml, now now it wants give some arguments to `private void button1_Click(object sender, RoutedEventArgs e) { MainWindow trytocallit = new MainWindow(); trytocallit.MyMethod(); }` in Page.xaml, but what? – John Majlstounn Mar 19 '15 at 08:14
  • In your page or mainwindow, please create a string property field , before clicking the button , update this string field and use as argument in MyMethod(string text). – Ugur Mar 19 '15 at 08:16
  • and sorry, i don't understand it so much, but i try to learn it, i started with C# recently – John Majlstounn Mar 19 '15 at 08:17
  • Make a string field in page class . like : string TextTest = "test" ; and update this field before button click to like TextTest = "abc" ; and use it in trytocallit.MyMethod(TextTest ) ; – Ugur Mar 19 '15 at 08:24
2

You can do a couple of different things. You can implement something like Muds' answer, which is similar to the Singleton pattern.

Another alternative is to use dependency injection to give your Page class an instance of MainWindow when it is created.

public class Page : Page
{
  private MainWindow MainWindow;

  public Page(MainWindow mainWindow)
  {
    InitializeComponent();

    this.MainWindow = mainWindow;

    // Other constructor stuff
  } 

  // Other methods, event handlers, etc.
}

Typically with dependency injection, we rely on abstractions rather than concrete implementations (to reduce coupling).

public interface IMainWindowThatDoesSomething
{
  void DoSomething();
}

public class MainWindow : Window, IMainWindowThatDoesSomething
{
  // Constructor, methods, event handlers, etc. go here.

  public void DoSomething()
  {
    // Implementation here.
  } 
}

public class Page : Page
{    
  private IMainWindowThatDoesSomething mainWindow;

  public Page(IMainWindowThatDoesSomething mainWindow)
  {
    InitializeComponent();

    this.mainWindow = mainWindow;

    // Other constructor jazz.
  }

  private void UserDidSomethingAndMainWindowNeedsToReact()
  {
    mainWindow.DoSomething();
  }
}
Community
  • 1
  • 1
Cameron
  • 2,574
  • 22
  • 37
0

well it doesn't sound right to do this, but if you have to get the object in memory rather than creating a new one..

but this dosent sound right .. tell us why u wanna do this so that we can suggest a better way

--- just to make your case work .. do this ..

In main window --

public static MainWindow Instance { get; private set; }

    static MainWindow()
{
    Instance = new MainWindow();
}

private MainWindow()
{
    InitializeComponent();
}

in app.xaml remove StartupUri="MainWindow.xaml"

public App()
{
    Startup += App_Startup;        
}

void App_Startup(object sender, StartupEventArgs e)
{
    TestApp.MainWindow.Instance.Show();
}

and in Page now you have access to static Instance ... call method on that

Muds
  • 4,006
  • 5
  • 31
  • 53
  • I know, that is so wrong and it can't work. I am work on small program, I have method on MainWindow which can change grid background, but i must call that method from another page and i don't know how :( – John Majlstounn Mar 18 '15 at 11:35
  • whats the relation between page and mainwindow ? – Muds Mar 18 '15 at 11:41
  • my program have menu on left side, each item on this menu show another page in frame which is on the right side and each page show different things – John Majlstounn Mar 18 '15 at 11:53
  • if i call static method, so it works, but with static method i can't define xaml tools (i mean textbloc, label etc.) and their value :( – John Majlstounn Mar 18 '15 at 11:56
  • that's y we have design principles :) – Muds Mar 18 '15 at 12:01
  • no, i must define it in code behind because i want a dynamically change it, this do that method and its work, but i don't know how call it from another Page :/ – John Majlstounn Mar 18 '15 at 12:04
  • okay, so, how can i define new tools on MainWindow if i click to the button on another Page? I need this way, i can't change whole program :( – John Majlstounn Mar 18 '15 at 12:10
  • I posted a patch commonly known as singleton.. use it and tell me if you have issues – Muds Mar 18 '15 at 12:11
  • I'm sorry, but the program does not start after I add your code :( and i must remove last line of code, it's same as first line... VS now write: _An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll_ – John Majlstounn Mar 18 '15 at 12:32
  • I am try it, but "TestApp" is wrong word and i dnon't know what what there is to be :( sorry i am beginer – John Majlstounn Mar 18 '15 at 13:01
  • just write mainwindow and let intellisense find that for u :) – Muds Mar 18 '15 at 13:10
  • 'mainwindow' does not exist in the current context :D :( – John Majlstounn Mar 18 '15 at 13:15
0

Consider leveraging messaging with parameters to pass around data between your objects.

You can use an EventAggregator or MessageBus.

The idea is to have your user controls subscribe to events that they would like to respond to.

NOTE:

I do this with viewmodels. However, I think it is a code-smell when adding this code to user-controls that are meant to have general use regardless of the application employing them.

I use the Publish Subscribe pattern for complicated class-dependencies:

ViewModel:

    public class ViewModel : ViewModelBase
    {
        public ViewModel()
        {
            CloseComand = new DelegateCommand((obj) =>
                {
                    MessageBus.Instance.Publish(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, null);
                });
        }
}

Window:

public partial class SomeWindow : Window
{
    Subscription _subscription = new Subscription();

    public SomeWindow()
    {
        InitializeComponent();

        _subscription.Subscribe(Messages.REQUEST_DEPLOYMENT_SETTINGS_CLOSED, obj =>
            {
                this.Close();
            });
    }
}

You can leverage Bizmonger.Patterns to get the MessageBus.

MessageBus

public class MessageBus
{
    #region Singleton
    static MessageBus _messageBus = null;
    private MessageBus() { }

    public static MessageBus Instance
    {
        get
        {
            if (_messageBus == null)
            {
                _messageBus = new MessageBus();
            }

            return _messageBus;
        }
    }
    #endregion

    #region Members
    List<Observer> _observers = new List<Observer>();
    List<Observer> _oneTimeObservers = new List<Observer>();
    List<Observer> _waitingSubscribers = new List<Observer>();
    List<Observer> _waitingUnsubscribers = new List<Observer>();

    int _publishingCount = 0;
    #endregion

    public void Subscribe(string message, Action<object> response)
    {
        Subscribe(message, response, _observers);
    }

    public void SubscribeFirstPublication(string message, Action<object> response)
    {
        Subscribe(message, response, _oneTimeObservers);
    }

    public int Unsubscribe(string message, Action<object> response)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Respond == response).ToList());
        observers.AddRange(_waitingSubscribers.Where(o => o.Respond == response));
        observers.AddRange(_oneTimeObservers.Where(o => o.Respond == response));

        if (_publishingCount == 0)
        {
            observers.ForEach(o => _observers.Remove(o));
        }

        else
        {
            _waitingUnsubscribers.AddRange(observers);
        }

        return observers.Count;
    }

    public int Unsubscribe(string subscription)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription).ToList());
        observers.AddRange(_waitingSubscribers.Where(o => o.Subscription == subscription));
        observers.AddRange(_oneTimeObservers.Where(o => o.Subscription == subscription));

        if (_publishingCount == 0)
        {
            observers.ForEach(o => _observers.Remove(o));
        }

        else
        {
            _waitingUnsubscribers.AddRange(observers);
        }

        return observers.Count;
    }

    public void Publish(string message, object payload)
    {
        _publishingCount++;

        Publish(_observers, message, payload);
        Publish(_oneTimeObservers, message, payload);
        Publish(_waitingSubscribers, message, payload);

        _oneTimeObservers.RemoveAll(o => o.Subscription == message);
        _waitingUnsubscribers.Clear();

        _publishingCount--;
    }

    private void Publish(List<Observer> observers, string message, object payload)
    {
        Debug.Assert(_publishingCount >= 0);

        var subscribers = observers.Where(o => o.Subscription.ToLower() == message.ToLower());

        foreach (var subscriber in subscribers)
        {
            subscriber.Respond(payload);
        }
    }

    public IEnumerable<Observer> GetObservers(string subscription)
    {
        var observers = new List<Observer>(_observers.Where(o => o.Subscription == subscription));
        return observers;
    }

    public void Clear()
    {
        _observers.Clear();
        _oneTimeObservers.Clear();
    }

    #region Helpers
    private void Subscribe(string message, Action<object> response, List<Observer> observers)
    {
        Debug.Assert(_publishingCount >= 0);

        var observer = new Observer() { Subscription = message, Respond = response };

        if (_publishingCount == 0)
        {
            observers.Add(observer);
        }
        else
        {
            _waitingSubscribers.Add(observer);
        }
    }
    #endregion
}

}

Subscription

public class Subscription
{
    #region Members
    List<Observer> _observerList = new List<Observer>();
    #endregion

    public void Unsubscribe(string subscription)
    {
        var observers = _observerList.Where(o => o.Subscription == subscription);

        foreach (var observer in observers)
        {
            MessageBus.Instance.Unsubscribe(observer.Subscription, observer.Respond);
        }

        _observerList.Where(o => o.Subscription == subscription).ToList().ForEach(o => _observerList.Remove(o));
    }

    public void Subscribe(string subscription, Action<object> response)
    {
        MessageBus.Instance.Subscribe(subscription, response);
        _observerList.Add(new Observer() { Subscription = subscription, Respond = response });
    }

    public void SubscribeFirstPublication(string subscription, Action<object> response)
    {
        MessageBus.Instance.SubscribeFirstPublication(subscription, response);
    }
}
Scott Nimrod
  • 11,206
  • 11
  • 54
  • 118
-1

sorry for late reply, I have one simple resolution.

  • In Page.xaml create public string variable.
  • If you click to the button on the page, variable gets the some value.
  • Create new background theard on MainWindow and there runs an endless loop while (true) {..}
  • The cycle control of the value public string variable again and again... with Thread.Sleep(10);
  • If it finds a value that does something in MainWindow

It works too and simply for me :)