Home > Blockchain >  Passing in variables for different instances of UserControl
Passing in variables for different instances of UserControl

Time:01-03

Can I create a UserControl which has different elements in it such as 'Rectangle' and 'TextBlock' and then call an instance of that UserControl in 'MainWindow.xaml' with a variable/value set to the 'Text' element for the TextBlock, and a 'Fill' for the Rectangles?

Therefore, I can just call an instance of the UserControl in the MainWindow, setting the values of each element, to save myself from replicating the UserControl XAML.

Say I have a MainWindow which is a Grid (3 x 3 say) of many Grids, all with the same structure. Instead of creating this 9 times:

  <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>
        <Rectangle Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Fill="{StaticResource colour1}"  RadiusX="20" RadiusY="20" Margin="5"/>
        <TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="TITLE" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource textColour1}" FontSize="16" FontWeight="Medium"/>
        <Rectangle Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="1" Grid.RowSpan="2" Fill="{StaticResource colour1}" RadiusX="25" RadiusY="25" Margin="5,0, 5, 0"/>
        <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="1" Text="TARGET" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource textColour1}" />
        <Rectangle Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="2" Fill="{StaticResource colour1}" RadiusX="25" RadiusY="25" Margin="5,0, 5, 0"/>
        <TextBlock Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="1" Text="ACTUAL" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource textColour1}" />
        <TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="1" Text="0" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource textColour1}" />
        <TextBlock Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="1" Text="0" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="{StaticResource textColour1}" />

    </Grid>

Is there a way to create a UserControl called 'AreaTile', with a Binding back to the MainWindow XAML, and then call those elements in the MainWindow, such as:


        <Grid Grid.Row="0" Grid.Column="0">
            <local:AreaTile Title="FirstTitle" Colour="{StaticResource textColour1}"/>
        </Grid>

        <Grid Grid.Row="0" Grid.Column="1">
            <local:AreaTile Title="SecondTitle" Colour="{StaticResource textColour2}"/>
        </Grid>

        <Grid Grid.Row="0" Grid.Column="2">
            <local:AreaTile Title="ThirdTitle" Colour="{StaticResource textColour3}"/>
        </Grid>

I have tried creating a TextBlock style and using a 'Setter' on 'Text' with a '{Binding Path=Tag}' but that didn't work.

I have also tried using C# with:

    public static readonly DependencyProperty myAreaNameProperty =
    DependencyProperty.Register("myAreaName", typeof(string), typeof(UserControl), new FrameworkPropertyMetadata(null));

But that seemed convoluted, and I thought there must be a way to do this purely with XAML.

Any help would be greatly appreciated.

CodePudding user response:

Initially, following this example: WPF: Passing variables from parent xaml to usercontrol it seemed to me that the MainWindow.xaml.cs (code-behind) also required declaration of the variable I wanted to pass in to the instance of the UserControl, which is incorrect.

In the MainWindow.xaml, we can create instances by using <local:AreaTile../>, where local is the namespace of where the UserControl exists. If this is not in the same folder as the 'MainWindow.xaml' in the Solution Explorer, you can create a xmlns reference in the header, such as:

<Window x:Class="MasterOverview.Views.MainViewWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MasterOverview.Views"
        xmlns:vms="clr-namespace:MasterOverview.ViewModels"
        mc:Ignorable="d"
        Title="MainWindow" Height="1000" Width="1800">

In MainWindow.xaml we can then refer to the instances, like below. With 'myAreaTile' being a 'Custom Dependancy Property' which is the variable we are passing in to the instance of the UserControl. Useful link: https://www.tutorialspoint.com/wpf/wpf_dependency_properties.htm

    <Grid Grid.Row="0" Grid.Column="0">
        <local:AreaTile myAreaTitle="FirstTitle"/>
    </Grid>

    <Grid Grid.Row="0" Grid.Column="1">
        <local:AreaTile myAreaTitle="SecondTitle"/>
    </Grid>

    <Grid Grid.Row="0" Grid.Column="2">
        <local:AreaTile myAreaTitle="ThirdTitle"/>
    </Grid>

Then in AreaTile.xaml.cs we can write the C#:

public partial class AreaTile : UserControl
{
    public static readonly DependencyProperty myAreaNameProperty =
    DependencyProperty.Register("myAreaName", typeof(string), typeof(UserControl), new FrameworkPropertyMetadata(null));

    public string myAreaName
    {
        get { return (string)GetValue(myAreaNameProperty); }
        set { SetValue(myAreaNameProperty, value); }
    }

    public AreaTile()
    {
        InitializeComponent();

        Loaded  = AreaTileC_Loaded;
    }

    
    private void AreaTileC_Loaded(object sender, RoutedEventArgs e)
    {
        AreaTileC.Text = myAreaName;
    }
}

This is creating the DependancyProperty, named 'myAreaTile' to the XAML, and 'myAreaNameProperty' to the AreaTile.xaml.cs (code-behind). We then create a string called 'myAreaTile' and make this equal to the DependancyProperty, which is the value we are getting for each instance of UserControl, from the MainWindow.xaml. We then set AreaTileC.Text equal to the local string 'myAreaTile'.

Now finally in the AreaTile.xaml, we can use the x:Name property on a TextBlock, such as:

    <TextBlock x:Name="AreaTileC"/>

Hope this helps someone out, and please feel free to comment if anything I have said above is incorrect.

  • Related