Rocko Bonaparte
Topic Author
Posts: 30
Joined: 13 Oct 2020, 08:32

Basic style definition

29 Dec 2020, 20:25

Previously I found out about having to define my own style. This is pretty alien to me and I'm bumbling along. I tried to define a style for one of my buttons inside its data template:
    <DataTemplate x:Key="SaveGameButton" DataType="local:SaveData">
        <Button Name="SaveButton" HorizontalContentAlignment="Stretch" Command="{Binding RunCommonButtonCommand}" CommandParameter="{Binding ElementName=TopmostWindow}">
        ...
            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="BorderBrush" Value="Yellow"/>
                    <Setter Property="Background" Value="Chartreuse"/>
                </Style>
            </Button.Style>
        </Button>
    </DataTemplate>
When I launch my standalone WPF application window using a regular WPF build, I do get yellow borders with a chartreuse body. When I then load this up into Unity, nothing has changed there. I'm still batched in purple buttons and purple borders. I've been double checking that the assets are getting rebuilt and brought over to the resources folder. The time stamps at least look okay, so I wanted to confirm I'm approaching this in the Noesis way or if there's some alternate approach I have to follow.

Tags:
 
User avatar
sfernandez
Site Admin
Posts: 2254
Joined: 22 Dec 2011, 19:20

Re: Basic style definition

30 Dec 2020, 13:16

Setting a style without a setter for the Template property will make your control to fallback to our internal pink templates. In WPF it fallbacks to operating system theme styles, but we don't want our core library to pay for a complete and complex theme always, when games usually define their own styles and templates. Instead we recommend users to set their styles in the Application Resources, so controls look the same in Blend and Unity.

In your case you can set the template locally in that style:
    <DataTemplate x:Key="SaveGameButton" DataType="local:SaveData">
        <Button Name="SaveButton" HorizontalContentAlignment="Stretch" Command="{Binding RunCommonButtonCommand}" CommandParameter="{Binding ElementName=TopmostWindow}">
        ...
            <Button.Style>
                <Style TargetType="Button">
                    <Setter Property="BorderBrush" Value="Yellow"/>
                    <Setter Property="Background" Value="Chartreuse"/>
                    <Setter Property="Template">
                      <Setter.Value>
                        <ControlTemplate TargetType="Button">
                          <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1">
                            <ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="Center VerticalAlignment="Center"/>
                          </Border>
                        </ControlTemplate>
                      </Setter.Value>
                    </Setter>
                </Style>
            </Button.Style>
        </Button>
    </DataTemplate>
Or if you already defined a template in your Application Resources Button style you can extend it by using BasedOn to get the rest of properties from that style:
    <DataTemplate x:Key="SaveGameButton" DataType="local:SaveData">
        <Button Name="SaveButton" HorizontalContentAlignment="Stretch" Command="{Binding RunCommonButtonCommand}" CommandParameter="{Binding ElementName=TopmostWindow}">
        ...
            <Button.Style>
                <Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
                    <Setter Property="BorderBrush" Value="Yellow"/>
                    <Setter Property="Background" Value="Chartreuse"/>
                </Style>
            </Button.Style>
        </Button>
    </DataTemplate>
You can read more about this topic in the Styles & Templates tutorial.
 
User avatar
jsantos
Site Admin
Posts: 3138
Joined: 20 Jan 2012, 17:18
Contact:

Re: Basic style definition

30 Dec 2020, 15:20

The Gallery is also a good example of application using our default theme in both Blend and Unity. For blend, you can see in App.xaml how the theme is merged.
<Application x:Class="Gallery.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:Gallery"
             StartupUri="/Gallery;component/Assets/NoesisGUI/Samples/Gallery/MainWindow.xaml">
  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="pack://application:,,,/Noesis.GUI.Extensions;component/Theme/NoesisTheme.DarkBlue.xaml" />
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>
 
Rocko Bonaparte
Topic Author
Posts: 30
Joined: 13 Oct 2020, 08:32

Re: Basic style definition

31 Dec 2020, 09:35

Hmm okay I was messing around with this and got the control template working for that button and then tried to see where this might be causing trouble elsewhere. I have a style defined for list view items that is a whole bunch of pink/purple and it isn't stretching the contents like I expected. It also didn't have a template property set. So I'm assuming the problem there is that Noesis completely blew off the style because a content template wasn't set.

It's distressing to me because I'm struggling to define a custom control template for the list view item. All that trouble is happening in Visual Studio so it's all on me. However, I was puzzled that I didn't see something I thought was essential for doing this in the include Noesis XAMLs. There's one definition for a ListViewItem in NoesisTheme.Styles.xaml, and that template doesn't have a ContentPresenter with a Content field set, nor anything referencing a TemplateBinding to Content. I was lead to believe that was essential; it was basically the "insert the stuff that this list view item has to show here" of the whole thing.
 
User avatar
sfernandez
Site Admin
Posts: 2254
Joined: 22 Dec 2011, 19:20

Re: Basic style definition

31 Dec 2020, 11:37

A UI element can only have 1 style object set in its Style property, so when a style is set locally only the properties specified there will be applied unless you extend it with the BasedOn as I indicated earlier. The best way to work with styles is by defining a theme with styles and templates for all your controls (you can start by just using our Theme) and set it in the Application resources. Then whenever you need to tweak the style for a control locally, you just use BasedOn to extend the one in Application resources.

Regarding the ListViewItem, instead of a ContentPresenter this control needs to use a more advanced element, the GridViewRowPresenter, so it can generate the content for each Column specified in the GridView definition.

If you need a simpler list with just one content per row, then you should use a ListBox. You will see that in this case ListBoxItem is using a ContentPresenter to show the content of the item.
 
Rocko Bonaparte
Topic Author
Posts: 30
Joined: 13 Oct 2020, 08:32

Re: Basic style definition

31 Dec 2020, 21:24

My problem looks more fundamental because I'm not getting it to work even without Noesis involved. My next plan is to just make a new standalone project with a hard-set ListView and see how it reacts to different control templates. I have enough fiddly bits beyond my (hopefully I'm reaching an intermediate level here) understanding of all of this. At the least, I can shop around online with a standalone example and get clearer answers. I don't expect you to be my general WPF tech support at this point.



I see that GridViewRowPresenter and I also see that online too, although I see some examples using a ContentPresenter too. People are acting like either one works based on something that I haven't sorted out. As for me, If I use a ContentPresenter, I just get the class names of the elements I want to draw instead. If I use GridViewRowPresenter, I get nothing visible. I see in the tree that the requisite number of GridViewRowPresenters were created, but they're not drawing anything.

Regarding the BasedOn propery: I have a ListView style defined separate from there. I have the ItemContainerStyle property set to this problematic ListViewItem style. I'm assuming that since these two styles are targeting different elements (ListView and ListViewItem respectively) that they contain as one style object each instead of two. Regardless, I tried to set basedOn between them and it got mad about them targeting different things. So that reinforced my notions.

Regarding ListBox: I tried that original and the drawn behavior was not what I wanted. I can't recall exactly what the issue was any more though.

Regarding Application Resources: I thought I couldn't use that in Unity. I saw the documentation about Noesis properly using an App.xaml but I thought that was for standalone projects. I've been basically merging my resources into a separate, common file that I then merge/reference in the UIs I'm starting up.

If I get rid of the control template in the ListViewItem style, then everything draws as I expect it. If I don't use the container style at all, I get some really bizarre behavior too. The first button is super-huge and everything else is squished. I think the Noesis style grabbed wholesale has a similar behavior. So I suspect part of my problem is the other setters that set content alignment in both directions and the height. That's what I'll be playing with later and I'm mostly typing this out for my own reference. If you're curious, this was the template before I tried to add a control template:

(I kept the comments for your Noesis pleasure haha)
                    <!-- Stretches the save buttons to fill up the ListView... mostly. There seems to still be padding on either side? -->
                    <Style x:Key="ListViewButtonStyle" TargetType="ListViewItem">
                        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
                        <Setter Property="VerticalContentAlignment" Value="Stretch" />
                        <Setter Property="Height" Value="{Binding RelativeSource={RelativeSource AncestorType=ListView}, Path=ActualHeight, Converter={StaticResource ResourceKey=fitFiveButtonsConverter}, ConverterParameter=5}"/>
                        <!-- This suppressed event prevents clicking the bottommost button causing it to scroll into view instead of firing the command. 
                             I'm not entirely convinced this is over. My hunch is this might prevent scrolling with a gamepad too. -->
                        <!-- Also, Noesis doesn't recognize it! :( -->
                        <!-- TODO: Determine strategy for supporting this capability in Unity with Noesis -->
                        <!-- <EventSetter Event="RequestBringIntoView" Handler="MuteButtonBringIntoView"/> -->
                    </Style>
 
Rocko Bonaparte
Topic Author
Posts: 30
Joined: 13 Oct 2020, 08:32

Re: Basic style definition

07 Jan 2021, 01:28

So I spent a few days kind of just grinding through control templates. An important thing for anybody else reading this far that is struggling with defining their own control templates: Visual Studio can actually dump the default control template for your control under the miscellaneous properties. You then get the default look and feel that you can then peck at free from pink/purple rendering in Noesis.

I didn't see a GridViewRowPresenter come up from these templates and my templates to use them wouldn't render if I tried to use them instead. I can look up stuff through work on WPF now and I'm trying to get something that really spells out that presenter's role and how it differs from a regular ContentPresenter in this kind of context.

The reason ContentPresenter was messing up was because I was defining extra properties that were then overridding proper behavior even though I thought I was just passing through template bindings. One was ContentStringFormat but in itself wasn't all of it. For whatever reason, using {Template Binding} to map Content and ContentTemplate messed up rendering. I don't fully understand why yet either.

BTW that would happen outside of using Noesis. So it's a more general problem.
 
peterh
Posts: 34
Joined: 13 Mar 2015, 13:50

Re: Basic style definition

07 Jan 2021, 10:40

Visual Studio can actually dump the default control template for your control under the miscellaneous properties.
That sounds awesome! I could really use that myself, but can't figure out how. Is there a more comprehensive how-to that you know of?
 
User avatar
sfernandez
Site Admin
Posts: 2254
Joined: 22 Dec 2011, 19:20

Re: Basic style definition

07 Jan 2021, 17:04

Is there a more comprehensive how-to that you know of?
If you create a simple Button in Blend without any style/template applied you can go to the Properties tab, expand de Miscellaneous section, click the small square right to the Template property and select "Convert to Local Value". This will create a copy of the default template used by Windows theme.
People are acting like either one works based on something that I haven't sorted out. As for me, If I use a ContentPresenter, I just get the class names of the elements I want to draw instead
If you use a simple ContentPresenter to show the information of ListViewItem Content it can only show the default ToString() of the item content. If you want to show different columns and the data templates specified by the GridView then you have to use a GridViewRowPresenter. Using the trick described before to dump the default template used by Windows for a ListViewItem it shows that they are also using a GridViewRowPresenter.
If I use GridViewRowPresenter, I get nothing visible. I see in the tree that the requisite number of GridViewRowPresenters were created, but they're not drawing anything.
Are you defining a GridView for the ListBox? Something like:
<ListView Width="120" Height="120">
  <ListView.View>
    <GridView>
      <GridViewColumn Header="Op1"/>
      <GridViewColumn Header="Op2"/>
    </GridView>
  </ListView.View>
  ...
</ListView>
Regarding the BasedOn propery: I have a ListView style defined separate from there. I have the ItemContainerStyle property set to this problematic ListViewItem style. I'm assuming that since these two styles are targeting different elements (ListView and ListViewItem respectively) that they contain as one style object each instead of two. Regardless, I tried to set basedOn between them and it got mad about them targeting different things. So that reinforced my notions.
The BasedOn should be used to reference a previous Style definition for the same type. You shouldn't use BasedOn to mix ListViewItem and ListView styles, instead you should probably have this:
<Style x:Key="LocalListViewItemStyle" TargetType="ListViewItem" BasedOn="{StaticResource {x:Type ListViewItem}}">
This assumes that previously you have an implicit Style resource defined (for example in Application Resources) for the ListViewItem type:
<ControlTemplate x:Key="DefaultListViewItemTemplate" TargetType="ListViewItem">
...
</ControlTemplate>
<Style TargetType="ListViewItem">
  <Setter Property="Template" Value="{StaticResource DefaultListViewItemTemplate}"/>
  ...
</Style>
Regarding Application Resources: I thought I couldn't use that in Unity. I saw the documentation about Noesis properly using an App.xaml but I thought that was for standalone projects.
In Unity you cannot use the App.xaml, but you can have all the application resources defined in a ResourceDictionary that is merged into App.xaml, and then use that same resource dictionary in NoesisSettings to set the Application Resources property. That way you share the same look between Blend and Unity.

Who is online

Users browsing this forum: No registered users and 1 guest