Page 1 of 1

NineSlice control does not immediately work correctly.

Posted: 26 Oct 2020, 22:18
by asusralis
I created a nine slice control, but it has odd behavior. When you first start the application, either through Unity's editor or a standalone, the control will not have any brushes applied. However, if you exit out of Unity's play mode and go back in (or load another nine slice control) it will then start to work. In the editor's case, it will work until after the domain (?) is reloaded (usually from compiling).

It is similar to what is shown in the Images documentation, but this only takes an image source and not individual brushes.
<Grid x:Name="Root">
    <Grid.Resources>
        <Style TargetType="Rectangle">
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="IsHitTestVisible" Value="True" />
            <Setter Property="RenderOptions.BitmapScalingMode" Value="NearestNeighbor" />
        </Style>
        <ImageBrush
            x:Key="TLeft"
            ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ImageSource}"
            ViewboxUnits="Absolute" />
        <ImageBrush
            x:Key="T"
            ImageSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ImageSource}"
            ViewboxUnits="Absolute" />
        ... Repeat
    </Grid.Resources>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="{Binding BorderThickness.Left, RelativeSource={RelativeSource TemplatedParent}}" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="{Binding BorderThickness.Right, RelativeSource={RelativeSource TemplatedParent}}" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="{Binding BorderThickness.Top, RelativeSource={RelativeSource TemplatedParent}}" />
        <RowDefinition Height="*" />
        <RowDefinition Height="{Binding BorderThickness.Bottom, RelativeSource={RelativeSource TemplatedParent}}" />
    </Grid.RowDefinitions>
    <Rectangle
        x:Name="TopLeft"
        Grid.Row="0"
        Grid.Column="0"
        Fill="{StaticResource TLeft}" />
    <Rectangle
        x:Name="TopCenter"
        Grid.Row="0"
        Grid.Column="1"
        Fill="{StaticResource T}" />
        ... Repeat
    <Grid
        x:Name="Middle"
        Grid.Row="1"
        Grid.Column="1"
        IsHitTestVisible="True">
        <Rectangle Fill="{StaticResource C}" IsHitTestVisible="True" />
        <ContentPresenter x:Name="MiddleContent" Margin="{TemplateBinding Padding}" />
    </Grid>
</Grid>
It seems that the image source is not applying when the application is started. Only after I recreate a nine slice control (or exit out of play mode and go back in) does it work correctly.

Here is a WPF example that uses the control I made. Not sure why it throws an exception in the designer, but running the control shows it works:

Re: NineSlice control does not immediately work correctly.

Posted: 27 Oct 2020, 12:13
by sfernandez
Hi, I've been investigating this issue and it is related to the way we have implemented control templates in Noesis. The problem I'm seeing is that the resources returned by FindResource are not the ones being applied to the Rectangles when template gets instantiated. I created ticket #1822 to follow this issue.

The workaround is to directly access the ImageBrush from each Rectangle.Fill:
_tLeft = (ImageBrush)((Rectangle)Template.FindName("TopLeft", this)).Fill;
 _t = (ImageBrush)((Rectangle)Template.FindName("TopCenter", this)).Fill;
_tRight = (ImageBrush)((Rectangle)Template.FindName("TopRight", this)).Fill;
_cLeft = (ImageBrush)((Rectangle)Template.FindName("CenterLeft", this)).Fill;
_c = (ImageBrush)((Rectangle)Template.FindName("Center", this)).Fill;
_cRight = (ImageBrush)((Rectangle)Template.FindName("CenterRight", this)).Fill;
_bLeft = (ImageBrush)((Rectangle)Template.FindName("BottomLeft", this)).Fill;
_b = (ImageBrush)((Rectangle)Template.FindName("BottomCenter", this)).Fill;
_bRight = (ImageBrush)((Rectangle)Template.FindName("BottomRight", this)).Fill;
Not sure why it throws an exception in the designer, but running the control shows it works
To avoid the designer exception just add a Template != null check in Loaded delegate:
Loaded += (s, e) =>
{
  ApplyTemplate();

  if (Template != null)
  {
    ...
  }
};

Re: NineSlice control does not immediately work correctly.

Posted: 28 Oct 2020, 04:43
by asusralis
That seems to work! Thanks for the help. Do you know why the control doesn't work in the editor? Is there anything I can change to fix this? I swear a previous version of this control was working in the editor when testing it in WPF, but I haven't been able to get it to work since then.

Re: NineSlice control does not immediately work correctly.

Posted: 28 Oct 2020, 17:32
by sfernandez
Do you know why the control doesn't work in the editor? Is there anything I can change to fix this?
As I mentioned in my previous post Blend designer was raising a NullReferenceException when executing your code in NineSliceControl.cs (line 83). The Template can be null there, so you need to check if (Template != null) before doing the FindName.

I also noticed that you have Control Display Options set to platform controls only, so your user control can't be rendered.

Re: NineSlice control does not immediately work correctly.

Posted: 30 Oct 2020, 09:19
by asusralis
No sorry, I understand that. I meant: why is my template null to begin with? Why can't the nine slice show in the editor?

> Control display options

Interesting, I haven't seen this before. I will try this.

Re: NineSlice control does not immediately work correctly.

Posted: 30 Oct 2020, 09:24
by asusralis
Nevermind, I found it! It displays correctly now, thanks.

Re: NineSlice control does not immediately work correctly.

Posted: 03 Nov 2020, 12:59
by sfernandez
Glad it works now.
Just curious, what did you change to fix it?

Re: NineSlice control does not immediately work correctly.

Posted: 09 Nov 2020, 10:32
by sfernandez
Hi, following this topic we developed our own version of nine slice control and shared it in our GitHub:

https://github.com/Noesis/Tutorials/tre ... /NineSlice

Hope this would help others in the future :)