AvaloniaUI / Avalonia.Markup.Declarative

Provides helpers for declarative ui in C#
349 stars 20 forks source link

bindings in styles for templated controls #27

Closed jmkinzer closed 1 year ago

jmkinzer commented 1 year ago

I am trying to replicate the tabcontrol xaml as follows (omitting the item/content templates as those are not an issue):

            <TabControl
                Items="{Binding Tabs}"
                <TabControl.Styles>
                    <Style Selector="TabItem" x:DataType="viewModels:TabControlPageViewModelItem">
                        <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
                    </Style>
                </TabControl.Styles>
            </TabControl>

But I can't see how to provide bindings for the IsEnabled property. The first issue is that there do not appear to be extension methods to create a binding in a style (and I'm not sure how one would bind in the control template). The second is I'm not actually sure what the binding path would actually look like in any case. It would also be really nice to have an approach that detects binding errors in such cases at compile time (perhaps using compiledbindingextension?)

            new TabControl()
            .Items(Bind(Tabs))
            .Styles(
                new Style<TabItem>(sel => sel.Is(typeof(TabItem)))
                    .IsEnabled(Bind(??))
                ,
                new Style<TabItem>(sel => sel.Is(typeof(TabItem)).PropertyEquals(TabItem.IsSelectedProperty, true))
                    .IsEnabled(true)
                )

Could an example be created here? Thank you!

gritsenko commented 1 year ago

Looks like I need to add binding support for styles

jmkinzer commented 1 year ago

That would really helpful - thanks!

gritsenko commented 1 year ago

@jmkinzer I pushed update with binding support in styles. Usage sample:

public class StylesSampleView : ViewBase
{
    protected override object Build() =>
        new StackPanel()
            .Children(new Control[]
            {
                new TabControl()
                    .ItemTemplate<TabVm>(tab => new TextBlock().Text(tab.Title))
                    .ContentTemplate(new FuncDataTemplate<TabVm>((item, ns) => new TextBlock().Text(item?.Content)))
                    .Items(Tabs)
                    .Styles(
                        new Style<TabItem>()
                            .IsEnabled(new Binding(nameof(TabVm.Enabled)))
                            .Foreground(Brushes.YellowGreen)
                    )
            });

    public List<TabVm> Tabs { get; set; } = new()
    {
        new TabVm("Tab1"),
        new TabVm("Tab2"),
        new TabVm("Disabled tab",false)
    };
}

public class TabVm
{
    public TabVm(string title, bool enabled = true)
    {
        Title = title;
        Enabled = enabled;
    }

    public string Title { get; }
    public bool Enabled { get; }

    public string Content => Title + " Content";
}
jmkinzer commented 1 year ago

Fantastic, exactly what I needed. Thanks!