How do I "pass" variables/data into a child control/element with minimal/no code behind? Esp. for binding.
Posted: 19 Jun 2023, 13:00
A great example of this requirement is; I have the desire to display multiple single-coloured images (using rectangles) to represent different parts of a ship, e.g. one rectangle for the front, one for the left, the right, the rear, and the central hull. They should have some binding and logic to change colour based on the health of that part of the ship. The logic is the same; the only thing that should change is the binding for the values. Below, each "ArmourRectangle" should bind to a different source for armour value and max armour value. Imagine this 5+ times... kinda redundant!
This is how I use them
How can I pass the binding paths through to some re-usable ArmourRectangle control? I'd like to point each one at a different binding for the armour value, and the max armour value. This isn't correct XAML but you get the idea. It should use the same style (or control template if that's easier) but be able to take the binding path set from this parent.
Not sure how to pass a string through and then use it in a binding. I tried Attached Properties but it would take it as a string literal and not resolve into the [] operator.
Furthermore, if I wanted to pool these rectangles into a user control, it'd be great to have all of the above together, plus being able to pass a string for the base of the image path and do some string concat for the ImageSource, e.g.
Which would resolve in the control to something like this, using the (ideally) re-usable rectangles from earlier:
-----------------------------
I'm not asking for necessarily fixing all of these issues, just some ideas on how to get these values through. I've hit this frustration so many times; having to have many many duplicated styles or templates where the parent control should surely be able to pass in values and re-use the same one multiple times.
Thanks!
Code: Select all
<Style x:Key="ArmourRectangle_Front" TargetType="Rectangle">
<Setter Property="Fill" Value="{StaticResource DefaultArmourColour}"/>
<Style.Triggers>
<!-- Change colour if value < amount -->
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource IsLessThanPercentageConverter}" Mode="OneWay">
<Binding Path="[ArmourComponent].Front"/>
<Binding Path="[ArmourComponent].MaxFront"/>
<Binding Source="{StaticResource ArmourLowPercentage}"></Binding>
</MultiBinding>
</DataTrigger.Binding>
<DataTrigger.Setters>
<Setter Property="Fill" Value="{StaticResource LowArmourColour}"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="ArmourRectangle_Back" TargetType="Rectangle">
<Setter Property="Fill" Value="{StaticResource DefaultArmourColour}"/>
<Style.Triggers>
<!-- Change colour if value < amount -->
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource IsLessThanPercentageConverter}" Mode="OneWay">
<Binding Path="[ArmourComponent].Back"/>
<Binding Path="[ArmourComponent].MaxBack"/>
<Binding Source="{StaticResource ArmourLowPercentage}"></Binding>
</MultiBinding>
</DataTrigger.Binding>
<DataTrigger.Setters>
<Setter Property="Fill" Value="{StaticResource LowArmourColour}"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
Code: Select all
<Rectangle Style="{StaticResource ArmourRectangle_Front}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Galactica_FrontPiece.png"/>
</Rectangle.OpacityMask>
</Rectangle>
<Rectangle Style="{StaticResource ArmourRectangle_Back}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Galactica_BackPiece.png"/>
</Rectangle.OpacityMask>
</Rectangle>
Code: Select all
<Rectangle Style="{StaticResource ArmourRectangle}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}" ArmourPath="[ArmourComponent].Front" MaxArmourPath="[ArmourComponent].MaxFront">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Galactica_FrontPiece.png"/>
</Rectangle.OpacityMask>
</Rectangle>
<Rectangle Style="{StaticResource ArmourRectangle}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}" ArmourPath="[ArmourComponent].Back" MaxArmourPath="[ArmourComponent].MaxBack">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Galactica_BackPiece.png"/>
</Rectangle.OpacityMask>
</Rectangle>
Furthermore, if I wanted to pool these rectangles into a user control, it'd be great to have all of the above together, plus being able to pass a string for the base of the image path and do some string concat for the ImageSource, e.g.
Code: Select all
<Control ControlTemplate="{StaticResource ArmourPiecesControl}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}" ArmourImagesBase="/NameOfShipGoesHere"/>
Code: Select all
<Rectangle Style="{StaticResource ArmourRectangle}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}" ArmourPath="[ArmourComponent].Front" MaxArmourPath="[ArmourComponent].MaxFront">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="{ArmourImagesBase}_FrontPiece.png"/>
</Rectangle.OpacityMask>
</Rectangle>
<Rectangle Style="{StaticResource ArmourRectangle}" Width="{StaticResource ControlWidth}" Height="{StaticResource ControlHeight}" ArmourPath="[ArmourComponent].Back" MaxArmourPath="[ArmourComponent].MaxBack">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="{ArmourImagesBase}_BackPiece.png"/>
</Rectangle.OpacityMask>
</Rectangle>
I'm not asking for necessarily fixing all of these issues, just some ideas on how to get these values through. I've hit this frustration so many times; having to have many many duplicated styles or templates where the parent control should surely be able to pass in values and re-use the same one multiple times.
Thanks!