HateDread
Topic Author
Posts: 71
Joined: 06 Feb 2020, 10:27

Re: Working with components / ECS?

26 Nov 2021, 17:14

This is where I've gotten up to and am trying out in C++, with hand-written "*ComponentName*Model" classes rather than the original components as struct properties or anything like that. An example of one of the optional health bars:
    <ControlTemplate x:Key="EmptyTemplate"></ControlTemplate>
    
    <sys:Single x:Key="IntegrityLowPercent">0.25</sys:Single>
    <Style x:Key="IntegrityBarAnimStyle" TargetType="ProgressBar" BasedOn="{StaticResource {x:Type ProgressBar}}">
        <Style.Triggers>

            <DataTrigger Binding="{Binding [HealthComponent], Converter={StaticResource IsNullConverter}}" Value="True">
                <Setter Property="Template" Value="{StaticResource EmptyTemplate}"></Setter>
            </DataTrigger>

            <DataTrigger Value="True">
                <DataTrigger.Binding>
                    <MultiBinding Converter="{StaticResource IsLessThanPercentageConverter}" Mode="OneWay">
                        <Binding Path="[HealthComponent].Integrity"/>
                        <Binding Path="[HealthComponent].MaxIntegrity"/>
                        <Binding Source="{StaticResource IntegrityLowPercent}"></Binding>
                    </MultiBinding>
                </DataTrigger.Binding>
                <DataTrigger.EnterActions>
                    <BeginStoryboard Name="LowIntegrityFlash">
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetProperty="Foreground.Color" To="{StaticResource IntegrityLowColor}" AutoReverse="True" Duration="0:0:0.1" RepeatBehavior="Forever"/>
                        </Storyboard>
                    </BeginStoryboard>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <StopStoryboard BeginStoryboardName="LowIntegrityFlash"></StopStoryboard>
                </DataTrigger.ExitActions>
            </DataTrigger>
        </Style.Triggers>
    </Style>
I've tried a few combinations; like setting template to x:Null or setting IsEnabled to False and Visibility to Hidden. The end result is always the same - that the 'IsLessThanPercentageConverter' used here is still being called, and with 'UnsetValue' types since the component doesn't exist. I was hoping the entire style and its bindings would cease to be processed. The above in use in my control xaml:
                <ProgressBar x:Name="IntegrityBar" Style="{StaticResource IntegrityBarAnimStyle}" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Center" Panel.ZIndex="2" Margin="29,0,-29,0" Background="#FF575757" Height="5" Foreground="#FFD4D4D4" Value="{Binding [HealthComponent].Integrity, Mode=OneWay}" BorderBrush="#FFD4D4D4" Maximum="{Binding [HealthComponent].MaxIntegrity, Mode=OneWay}">
                    <ProgressBar.RenderTransform>
                        <TransformGroup>
                            <ScaleTransform/>
                            <SkewTransform/>
                            <RotateTransform Angle="270"/>
                            <TranslateTransform/>
                        </TransformGroup>
                    </ProgressBar.RenderTransform>
                </ProgressBar>
I've started messing with it in C++, and getting errors like
[ 11/27/21 03:05:54 ] [warn] [RTG] Index 4294967295 out of bounds accessing EntityComponentsViewModel
[ 11/27/21 03:05:54 ] [error] [RTG] Binding failed: Path=[ShieldComponent].MaxShield, Source=EntityComponentsViewModel(''), Target=ProgressBar('ShieldBar'), TargetProperty=RangeBase.Maximum
[ 11/27/21 03:05:54 ] [warn] [RTG] Index 4294967295 out of bounds accessing EntityComponentsViewModel
[ 11/27/21 03:05:54 ] [error] [RTG] Binding failed: Path=[ShieldComponent].Shield, Source=EntityComponentsViewModel(''), Target=ProgressBar('ShieldBar'), TargetProperty=RangeBase.Value
Which don't surprise me - I guess it's the aforementioned issues of still trying to access components that don't exist?
 
User avatar
sfernandez
Site Admin
Posts: 2984
Joined: 22 Dec 2011, 19:20

Re: Working with components / ECS?

26 Nov 2021, 19:26

the 'IsLessThanPercentageConverter' used here is still being called, and with 'UnsetValue' types since the component doesn't exist.
Yes, that is correct, the DataTrigger needs to evaluate the binding to determine if it has to apply the setters or execute the specified actions. And even if part of the binding is null it calls the converter because some converters may accept a null as a valid value.

On a side note, you can simplify the first DataTrigger by comparing directly to {x:Null}
<DataTrigger Binding="{Binding [HealthComponent]}" Value="{x:Null}">
  <Setter Property="Template" Value="{StaticResource EmptyTemplate}"/>
</DataTrigger>
I've started messing with it in C++, and getting errors like
Those bindings shouldn't report an error message, this was a deviation from WPF, we've fixed that for the next release: #2200

Anyway, if you want to avoid evaluating those bindings at all you can have an indirection. Instead of directly including the ProgressBar, you can have a Control that only sets its template when the component is available:
<ControlTemplate x:Key="EmptyTemplate"/>
<ControlTemplate x:Key="ProgressBarTemplate">
  <ProgressBar Style="{StaticResource IntegrityBarAnimStyle}" .../>
</ControlTemplate>
<Style x:Key="HealthControl" TargetType="Control">
  <Setter Property="Template" Value="{StaticResource ProgressBarTemplate}"/>
  <Style.Triggers>
    <DataTrigger Binding="{Binding [HealthComponent]}" Value="{x:Null}">
      <Setter Property="Template" Value="{StaticResource EmptyTemplate}"/>
    </DataTrigger>
  </Style.Triggers>
</Style>
<Control Style="{StaticResource HealthControl}"/>

Who is online

Users browsing this forum: No registered users and 90 guests