locked
How to pass String^ from usercontrol to mainpage?

    Question

  • How do I pass a String^ variable from a usercontrol to mainpage.xaml.cpp?
    Saturday, August 17, 2013 9:35 AM

Answers

  • One way is to make the variable a property of the user control.  Then some method in the mainpage can just read it.

    MyUserControl.xaml.h

    #pragma once
    
    #include "MyUserControl.g.h"
    
    namespace TestUserControl
    {
    	[Windows::Foundation::Metadata::WebHostHidden]
    	public ref class MyUserControl sealed
    	{
    	public:
    		MyUserControl();
    		property Platform::String^ myString; //Here is the new property
    	private:
    		void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    	};
    }

    MyUserControl.xaml.cpp

    #include "pch.h"
    #include "MyUserControl.xaml.h"
    
    using namespace TestUserControl;
    
    using namespace Platform;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Controls::Primitives;
    using namespace Windows::UI::Xaml::Data;
    using namespace Windows::UI::Xaml::Input;
    using namespace Windows::UI::Xaml::Media;
    using namespace Windows::UI::Xaml::Navigation;
    
    MyUserControl::MyUserControl()
    {
    	InitializeComponent();
    	myString = "I am initialized";
    }
    
    void TestUserControl::MyUserControl::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	Result->Text = "Hello World";
    	myString = "Here I am";
    }

    MyUserControl.xaml

    <UserControl
        x:Class="TestUserControl.MyUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TestUserControl"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
        
        <Grid>
            <StackPanel>
                <Button Click="Button_Click">Go</Button>
                <TextBlock x:Name="Result">Output</TextBlock>
            </StackPanel>
        </Grid>
    </UserControl>

    MainPage.xaml

    <Page
        x:Class="TestUserControl.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TestUserControl"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <StackPanel>
                <local:MyUserControl x:Name="OneControl"/>
                <Button Click="Button_Click">Get String</Button>
                <TextBlock x:Name="ControlResult">String from Control</TextBlock>
            </StackPanel>      
        </Grid>
    </Page>

    MainPage.xaml.h

    #pragma once
    
    #include "MainPage.g.h"
    #include "MyUserControl.xaml.h"
    
    namespace TestUserControl
    {
    	
    	public ref class MainPage sealed
    	{
    	public:
    		MainPage();
    
    	protected:
    		virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
    	private:
    		void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    	};
    }

    MainPage.xaml.cpp

    #include "pch.h" #include "MainPage.xaml.h" using namespace TestUserControl; using namespace Platform; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Navigation; MainPage::MainPage() { InitializeComponent(); } void MainPage::OnNavigatedTo(NavigationEventArgs^ e) { (void) e; // Unused parameter } void TestUserControl::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) {

    //Reading the String^ property of the control ControlResult->Text = OneControl->myString; }



    Saturday, August 17, 2013 1:06 PM
  • Here is one way to do it.

    Create a class that will be used to hold all global variables.  I call it "CommonViewModel".

    CommonViewModel.h

    #pragma once
    #include "pch.h"
    
    namespace TestUserControl
    {
    	//This class will hold global variables
    	public ref class CommonViewModel sealed
    	{
    	public:
    		CommonViewModel();		
    
    		//Here is a global string
    		property Platform::String^ aGlobalString;
    	};
    }

    CommonViewModel.cpp

    #include "pch.h"
    #include "CommonViewModel.h"
    
    using namespace TestUserControl;
    
    CommonViewModel::CommonViewModel()
    {
    }

    An instance of this class is instantiated by putting it in App.xaml Resources.

    First, add a #include "CommmonViewModel.h" to the App.xaml.h file.  Then in App.xaml:

    <Application
        x:Class="TestUserControl.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TestUserControl">
    
        <Application.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Common/StandardStyles.xaml"/>               
                </ResourceDictionary.MergedDictionaries>
                
                <!--This Resource will be used for global variables-->
                <local:CommonViewModel x:Key="MyCVM" />
                
            </ResourceDictionary>
        </Application.Resources>
    </Application>

    (A side note: The xaml designer seems to have a problem with the previous step if the class that you are referencing has never been built.  So I recommend building the solution then adding the line in XAML, taking advantage of Intellisense when possible.)

    Then you can access this instance anywhere by getting a handle to it from the App Resources like this.

    	//Get a handle on the common resource
    	auto cvm = safe_cast<CommonViewModel^>(
    		App::Current->Resources->Lookup("MyCVM"));

    (You could make cvm a local variable that is initialized this way in the constructor.)

    And accessing the properties like this

    	//Access it
    	cvm->aGlobalString = "goodby";
    Each Page or UserControl that uses this global resource will need a #include "pch.h".  This file has a reference to the App.xaml.h file which also knows about the CommonViewModel.

    An advantage to this approach is that the global variables in CommonViewModel can be bound to elements of your XAML.  You can make the class implement INotifyPropertyChange and any updates to the properties will automatically propagate to the View (display).



    Sunday, August 18, 2013 1:58 PM

All replies

  • One way is to make the variable a property of the user control.  Then some method in the mainpage can just read it.

    MyUserControl.xaml.h

    #pragma once
    
    #include "MyUserControl.g.h"
    
    namespace TestUserControl
    {
    	[Windows::Foundation::Metadata::WebHostHidden]
    	public ref class MyUserControl sealed
    	{
    	public:
    		MyUserControl();
    		property Platform::String^ myString; //Here is the new property
    	private:
    		void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    	};
    }

    MyUserControl.xaml.cpp

    #include "pch.h"
    #include "MyUserControl.xaml.h"
    
    using namespace TestUserControl;
    
    using namespace Platform;
    using namespace Windows::Foundation;
    using namespace Windows::Foundation::Collections;
    using namespace Windows::UI::Xaml;
    using namespace Windows::UI::Xaml::Controls;
    using namespace Windows::UI::Xaml::Controls::Primitives;
    using namespace Windows::UI::Xaml::Data;
    using namespace Windows::UI::Xaml::Input;
    using namespace Windows::UI::Xaml::Media;
    using namespace Windows::UI::Xaml::Navigation;
    
    MyUserControl::MyUserControl()
    {
    	InitializeComponent();
    	myString = "I am initialized";
    }
    
    void TestUserControl::MyUserControl::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	Result->Text = "Hello World";
    	myString = "Here I am";
    }

    MyUserControl.xaml

    <UserControl
        x:Class="TestUserControl.MyUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TestUserControl"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400">
        
        <Grid>
            <StackPanel>
                <Button Click="Button_Click">Go</Button>
                <TextBlock x:Name="Result">Output</TextBlock>
            </StackPanel>
        </Grid>
    </UserControl>

    MainPage.xaml

    <Page
        x:Class="TestUserControl.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TestUserControl"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <StackPanel>
                <local:MyUserControl x:Name="OneControl"/>
                <Button Click="Button_Click">Get String</Button>
                <TextBlock x:Name="ControlResult">String from Control</TextBlock>
            </StackPanel>      
        </Grid>
    </Page>

    MainPage.xaml.h

    #pragma once
    
    #include "MainPage.g.h"
    #include "MyUserControl.xaml.h"
    
    namespace TestUserControl
    {
    	
    	public ref class MainPage sealed
    	{
    	public:
    		MainPage();
    
    	protected:
    		virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
    	private:
    		void Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
    	};
    }

    MainPage.xaml.cpp

    #include "pch.h" #include "MainPage.xaml.h" using namespace TestUserControl; using namespace Platform; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; using namespace Windows::UI::Xaml; using namespace Windows::UI::Xaml::Controls; using namespace Windows::UI::Xaml::Controls::Primitives; using namespace Windows::UI::Xaml::Data; using namespace Windows::UI::Xaml::Input; using namespace Windows::UI::Xaml::Media; using namespace Windows::UI::Xaml::Navigation; MainPage::MainPage() { InitializeComponent(); } void MainPage::OnNavigatedTo(NavigationEventArgs^ e) { (void) e; // Unused parameter } void TestUserControl::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e) {

    //Reading the String^ property of the control ControlResult->Text = OneControl->myString; }



    Saturday, August 17, 2013 1:06 PM
  • Thank you.  That works perfectly.

    Unfortunately, I have like 30 usercontrols.  It's a rather extensive app that I've been working on.  And another unfortunate thing is I started it with c++ and I really don't want to go back and edit everything to c#.

    Is there a way to make myString a global variable so that everything can access it and edit it?




    • Edited by RandyPete Saturday, August 17, 2013 8:15 PM
    Saturday, August 17, 2013 6:23 PM
  • I'm not sure why reverting back to C# would be a solution. You would still have the same architectural problem to solve.

    Do you want to share access to just one string or a string per control? If the former, the you could define a String^ property with static storage. Otherwise if it a string per control then the control property route is the way to go.

    Saturday, August 17, 2013 10:46 PM
  • I'm not sure why reverting back to C# would be a solution. You would still have the same architectural problem to solve.

    Do you want to share access to just one string or a string per control? If the former, the you could define a String^ property with static storage. Otherwise if it a string per control then the control property route is the way to go.

    Well, I'm a structure engineer who recently picked up programming for hobby.  Got 4 apps published in the winstore.  I was never formally trained in programming, so I had to learn everything by myself.  Never formally trained.  I asked around the professional programmers I knew and they all told me to go with C++.  Well, it turned out that C# is a much better way to go, but it's too late because my projects have already been written in C++.  I just published my first app written in C#, but the one I'm working on that has like 30 usercontrols is already in C++.  Jrboddie suggested that going to C# should be easier. That's why I commented on the C# thing.

    Can you please tell me how to declare a global variable where any .cpp page can call, define, and edit?  If I go the route of a string per control, the code would be too cumbersome.  Having a global variable where anything can simply call and define will be a much better solution.

    And please don't just tell me what to do.  Remember that I was never formally trained.  Telling me what to do isn't too much help.  You have to show me the code. 

    Please be patient with me.  This is fun but also very exhausting for me. 

    PS - One of my apps is actually selling 2-3/day.  :-D

    Saturday, August 17, 2013 11:09 PM
  • Your original question was how to pass a string from a usercontrol to a page, so I'm curious why you would want to go with one big static. It's better to keep each control with a reference to it. Go with the approach above, the declare a data class that you use for the DataContext of your Mainpage. Then in xaml you'll assign each control to bind to the string value on your datacontext object. This is the proper xaml way :-)

    <my:MyUserControl StringProperty="{Binding SomeDataProperty}" />
    <my:MyUserControl StringProperty="{Binding SomeDataProperty}" />
    <my:MyUserControl StringProperty="{Binding SomeDataProperty}" />
    ... and 27 more times


    /Morten
    twitter: http://www.twitter.com/dotMorten
    blog: http://www.sharpgis.net

    Sunday, August 18, 2013 4:44 AM
  • Trust me, in my case it is better to have a global variable that everything can access. Can you please tell how to have a global variable?
    Sunday, August 18, 2013 5:22 AM
  • Here is one way to do it.

    Create a class that will be used to hold all global variables.  I call it "CommonViewModel".

    CommonViewModel.h

    #pragma once
    #include "pch.h"
    
    namespace TestUserControl
    {
    	//This class will hold global variables
    	public ref class CommonViewModel sealed
    	{
    	public:
    		CommonViewModel();		
    
    		//Here is a global string
    		property Platform::String^ aGlobalString;
    	};
    }

    CommonViewModel.cpp

    #include "pch.h"
    #include "CommonViewModel.h"
    
    using namespace TestUserControl;
    
    CommonViewModel::CommonViewModel()
    {
    }

    An instance of this class is instantiated by putting it in App.xaml Resources.

    First, add a #include "CommmonViewModel.h" to the App.xaml.h file.  Then in App.xaml:

    <Application
        x:Class="TestUserControl.App"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:TestUserControl">
    
        <Application.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Common/StandardStyles.xaml"/>               
                </ResourceDictionary.MergedDictionaries>
                
                <!--This Resource will be used for global variables-->
                <local:CommonViewModel x:Key="MyCVM" />
                
            </ResourceDictionary>
        </Application.Resources>
    </Application>

    (A side note: The xaml designer seems to have a problem with the previous step if the class that you are referencing has never been built.  So I recommend building the solution then adding the line in XAML, taking advantage of Intellisense when possible.)

    Then you can access this instance anywhere by getting a handle to it from the App Resources like this.

    	//Get a handle on the common resource
    	auto cvm = safe_cast<CommonViewModel^>(
    		App::Current->Resources->Lookup("MyCVM"));

    (You could make cvm a local variable that is initialized this way in the constructor.)

    And accessing the properties like this

    	//Access it
    	cvm->aGlobalString = "goodby";
    Each Page or UserControl that uses this global resource will need a #include "pch.h".  This file has a reference to the App.xaml.h file which also knows about the CommonViewModel.

    An advantage to this approach is that the global variables in CommonViewModel can be bound to elements of your XAML.  You can make the class implement INotifyPropertyChange and any updates to the properties will automatically propagate to the View (display).



    Sunday, August 18, 2013 1:58 PM
  • Thank you very much.  That worked perfectly.  You just saved me about 600 lines of codes and probably 2 hours of work time.
    Sunday, August 18, 2013 4:09 PM