locked
Is there a way to control multiple textblocks with one cpp statement?

    Question

  • In the xaml document, I know I can't give the same name to multiple text blocks.  I have to give each a unique x:Name. 

    Is there an identifier that allows me to do this?  In the cpp portion, instead of writing out the same command statement 20 times, each pointing to a different text block, is there an identifier I can give to these specific text blocks and so I can control them en masse with the cpp?

    Saturday, June 29, 2013 2:42 PM

Answers

  • As Rob said, data binding is the way to go.  As the documentation for data binding in C++ is sparse, here is an example I cooked up:

    The Xaml

    <Page
        x:Class="DataBinding.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:DataBinding"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
            <local:ViewModel x:Name="myViewModel"/>
        </Page.Resources>
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <StackPanel DataContext="{StaticResource myViewModel}">
                <TextBox x:Name="inputText"/>
                <Button Click="Button_Click">Change</Button>
                <TextBlock Text="{Binding myText}"/>
                <TextBlock Text="{Binding myText}"/>
                <TextBlock Text="{Binding myText}"/>
            </StackPanel>
        </Grid>
    </Page>

    We have 3 TextBlocks bound to a myText property.  The StackPanel container's DataContext is an instance of a ViewModel (shown later).

    In the code behind...

    void DataBinding::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	myViewModel->myText = inputText->Text;
    }

    we have a button click event that sets the property of the ViewModel from the contents of a TextBox.

    Now the magic is in the ViewModel which is a class that implements INotifiyPropertyChanged.

    ViewModel.h

    #pragma once
    #include "pch.h"
    
    namespace DataBinding
    {
    	[Windows::UI::Xaml::Data::Bindable]
    	public ref class ViewModel sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged
    	{
    	private:
    		Platform::String^ _myText;
    	public:
    		ViewModel();
    
    		virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
    
    		property Platform::String^ myText
    		{
    			Platform::String^ get();
    			void set(Platform::String^ value);
    		}
    
    	protected:
    		void OnPropertyChanged(Platform::String^ propertyName);
    	};
    }

    and ViewModel.cpp

    #include "pch.h"
    #include "ViewModel.h"
    
    using namespace DataBinding;
    
    using namespace Platform;
    using namespace Windows::UI;
    using namespace Windows::UI::Xaml::Data;
    
    ViewModel::ViewModel()
    {
    	this->_myText = "";
    }
    
    void ViewModel::myText::set(String^ value)
    {
        if (myText != value)
        {
            _myText = value;
            OnPropertyChanged("myText");
        }
    }
    
    String^ ViewModel::myText::get()
    {
        return _myText;
    }
    
    void ViewModel::OnPropertyChanged(String^ propertyName)
    {
        PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName));
    }

    I can put the example on SkyDrive if you need further clarification.

    When a property in the ViewModel is changed in the MainPage, a property changed event is raised for the data binding mechanism that updates the UI for you.

    Depending on your scenario, you can also bind the TextBlock controls to a single 'master' TextBlock.  Change the master, and the others will follow.  Like this:

                <TextBlock x:Name="Master"/>
                <TextBlock Text="{Binding Text, ElementName=Master}"/>
                <TextBlock Text="{Binding Text, ElementName=Master}"/>

    and

    void DataBinding::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	Master->Text = inputText->Text;
    }

    • Edited by jrboddie Saturday, June 29, 2013 8:44 PM Another way
    • Marked as answer by RandyPete Sunday, June 30, 2013 6:28 PM
    Saturday, June 29, 2013 5:24 PM
  • Thank you for your kind reply.

    What I'm trying to do is change the visibility of stackpanels at various places in my xaml file.  Does databinding work for changing such property as well?

    Added by edit.

    Success!

    <StackPanel x:Name="master"> </StackPanel>

    <StackPanel Visibility="{Blinding Visibility, ElementNAme=master}"></StackPanel>


    • Edited by RandyPete Saturday, June 29, 2013 10:45 PM spelling
    • Marked as answer by RandyPete Sunday, June 30, 2013 6:28 PM
    Saturday, June 29, 2013 10:21 PM
  • Yes that works.

    ...or you could use the ViewModel approach:

    1. Add a bool property to the ViewModel class that will control visibility.

    2. Add a ValueConverter class that converts bool to Visibility

    3. In the XAML, bind the Visibility attributes of each UI element that you want to control to PanelIsVisible and use the ValueConverter.

    4. In the code behind set the ViewModel bool property true or false to control the visibility of the bound UI elements.


    • Marked as answer by RandyPete Sunday, June 30, 2013 6:28 PM
    Sunday, June 30, 2013 12:25 AM

All replies

  • What are you trying to do with them?

    You can databind them all to the same property.

    --Rob

    Saturday, June 29, 2013 4:42 PM
    Owner
  • As Rob said, data binding is the way to go.  As the documentation for data binding in C++ is sparse, here is an example I cooked up:

    The Xaml

    <Page
        x:Class="DataBinding.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:DataBinding"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
        <Page.Resources>
            <local:ViewModel x:Name="myViewModel"/>
        </Page.Resources>
    
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
            <StackPanel DataContext="{StaticResource myViewModel}">
                <TextBox x:Name="inputText"/>
                <Button Click="Button_Click">Change</Button>
                <TextBlock Text="{Binding myText}"/>
                <TextBlock Text="{Binding myText}"/>
                <TextBlock Text="{Binding myText}"/>
            </StackPanel>
        </Grid>
    </Page>

    We have 3 TextBlocks bound to a myText property.  The StackPanel container's DataContext is an instance of a ViewModel (shown later).

    In the code behind...

    void DataBinding::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	myViewModel->myText = inputText->Text;
    }

    we have a button click event that sets the property of the ViewModel from the contents of a TextBox.

    Now the magic is in the ViewModel which is a class that implements INotifiyPropertyChanged.

    ViewModel.h

    #pragma once
    #include "pch.h"
    
    namespace DataBinding
    {
    	[Windows::UI::Xaml::Data::Bindable]
    	public ref class ViewModel sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged
    	{
    	private:
    		Platform::String^ _myText;
    	public:
    		ViewModel();
    
    		virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
    
    		property Platform::String^ myText
    		{
    			Platform::String^ get();
    			void set(Platform::String^ value);
    		}
    
    	protected:
    		void OnPropertyChanged(Platform::String^ propertyName);
    	};
    }

    and ViewModel.cpp

    #include "pch.h"
    #include "ViewModel.h"
    
    using namespace DataBinding;
    
    using namespace Platform;
    using namespace Windows::UI;
    using namespace Windows::UI::Xaml::Data;
    
    ViewModel::ViewModel()
    {
    	this->_myText = "";
    }
    
    void ViewModel::myText::set(String^ value)
    {
        if (myText != value)
        {
            _myText = value;
            OnPropertyChanged("myText");
        }
    }
    
    String^ ViewModel::myText::get()
    {
        return _myText;
    }
    
    void ViewModel::OnPropertyChanged(String^ propertyName)
    {
        PropertyChanged(this, ref new PropertyChangedEventArgs(propertyName));
    }

    I can put the example on SkyDrive if you need further clarification.

    When a property in the ViewModel is changed in the MainPage, a property changed event is raised for the data binding mechanism that updates the UI for you.

    Depending on your scenario, you can also bind the TextBlock controls to a single 'master' TextBlock.  Change the master, and the others will follow.  Like this:

                <TextBlock x:Name="Master"/>
                <TextBlock Text="{Binding Text, ElementName=Master}"/>
                <TextBlock Text="{Binding Text, ElementName=Master}"/>

    and

    void DataBinding::MainPage::Button_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
    	Master->Text = inputText->Text;
    }

    • Edited by jrboddie Saturday, June 29, 2013 8:44 PM Another way
    • Marked as answer by RandyPete Sunday, June 30, 2013 6:28 PM
    Saturday, June 29, 2013 5:24 PM
  • Thank you for your kind reply.

    What I'm trying to do is change the visibility of stackpanels at various places in my xaml file.  Does databinding work for changing such property as well?

    Added by edit.

    Success!

    <StackPanel x:Name="master"> </StackPanel>

    <StackPanel Visibility="{Blinding Visibility, ElementNAme=master}"></StackPanel>


    • Edited by RandyPete Saturday, June 29, 2013 10:45 PM spelling
    • Marked as answer by RandyPete Sunday, June 30, 2013 6:28 PM
    Saturday, June 29, 2013 10:21 PM
  • Yes that works.

    ...or you could use the ViewModel approach:

    1. Add a bool property to the ViewModel class that will control visibility.

    2. Add a ValueConverter class that converts bool to Visibility

    3. In the XAML, bind the Visibility attributes of each UI element that you want to control to PanelIsVisible and use the ValueConverter.

    4. In the code behind set the ViewModel bool property true or false to control the visibility of the bound UI elements.


    • Marked as answer by RandyPete Sunday, June 30, 2013 6:28 PM
    Sunday, June 30, 2013 12:25 AM