0

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.

FuzzUK
  • 23
  • 6
  • "that seemed convoluted" - it is not. "there must be a way to do this purely with XAML" - there are such ways. they have more downsides and limitations than simply creating a usercontrol with dependency properties – ASh Dec 12 '22 at 18:52
  • @ASh - OK, I will concede to doing it that way and see how I find it, I take it with your experience that this is a common way to do it whilst conforming to MVVM? Do you have any documentation to provide on this? This is what I followed before, does this apply? https://stackoverflow.com/questions/37197906/wpf-passing-variables-from-parent-xaml-to-usercontrol. Thanks! – FuzzUK Dec 12 '22 at 19:40
  • "this is a common way to do it" - yes. "whilst conforming to MVVM" - UserControls don't care about MVVM - they never see model or view model. They work with their own DPs. "Do you have any documentation to provide on this?" I don't. Microsoft has plenty of that. the linked post is not the best example, I would even say "poor example" – ASh Dec 12 '22 at 19:53
  • @ASh - OK.. I wasn't asking if *you* specifically had documentation, but perhaps a link to documentation from Microsoft (or the like) on this subject. It may be useful to remember that people post on Stack Overflow as a last resort, in fact most of my Google searches come back to the question I posted in my last comment, of which you've said is a poor example. I guess I'll go trawl the web again.. Thank you at least for pointing me in the right (or at least not in the wrong) direction! – FuzzUK Dec 12 '22 at 20:06
  • "It may be useful to remember that people post on Stack Overflow as a last resort" - it may be useful to remember that the first question on stackoverflow was asked in 2008 and the last resort of a software-developer is "I will implement it myself from scratch". – ASh Dec 12 '22 at 20:13

1 Answers1

1

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.

FuzzUK
  • 23
  • 6