Avalonia.Xaml.Behaviors icon indicating copy to clipboard operation
Avalonia.Xaml.Behaviors copied to clipboard

Setting BorderBrush and BorderThickness for a button doesn't seem to work?

Open derekantrican opened this issue 3 years ago • 3 comments

I'm on version 0.9.12 of everything. I'm trying to do the following:

<Button Name="GetCalendarsButton" Grid.Column="1" Height="25" Content="Get Calendars" Command="{Binding GetCalendars}" Margin="5">
  <i:Interaction.Behaviors>
    <ia:DataTriggerBehavior Binding="{Binding FlashGetCalendarsButton}" ComparisonCondition="Equal" Value="true">
        <ia:ChangePropertyAction TargetObject="{Binding #GetCalendarsButton}" PropertyName="BorderBrush" Value="Blue"/>
        <ia:ChangePropertyAction TargetObject="{Binding #GetCalendarsButton}" PropertyName="BorderThickness" Value="2"/>
    </ia:DataTriggerBehavior>
    <ia:DataTriggerBehavior Binding="{Binding FlashGetCalendarsButton}" ComparisonCondition="Equal" Value="false">
        <ia:ChangePropertyAction TargetObject="{Binding #GetCalendarsButton}" PropertyName="BorderBrush" Value="Transparent"/>
        <ia:ChangePropertyAction TargetObject="{Binding #GetCalendarsButton}" PropertyName="BorderThickness" Value="0"/>
    </ia:DataTriggerBehavior>
  </i:Interaction.Behaviors>
</Button>

That doesn't seem to work, but - as an alternate test, this does work:

<Button Name="GetCalendarsButton" Grid.Column="1" Height="25" Content="Get Calendars" Command="{Binding GetCalendars}" Margin="5">
  <i:Interaction.Behaviors>
    <ia:DataTriggerBehavior Binding="{Binding FlashGetCalendarsButton}" ComparisonCondition="Equal" Value="true">
        <ia:ChangePropertyAction TargetObject="{Binding #GetCalendarsButton}" PropertyName="Content" Value="Get"/>
    </ia:DataTriggerBehavior>
    <ia:DataTriggerBehavior Binding="{Binding FlashGetCalendarsButton}" ComparisonCondition="Equal" Value="false">
        <ia:ChangePropertyAction TargetObject="{Binding #GetCalendarsButton}" PropertyName="Content" Value="Get Calendars"/>
    </ia:DataTriggerBehavior>
  </i:Interaction.Behaviors>
</Button>

derekantrican avatar Dec 11 '20 00:12 derekantrican

As workaround, try add this code before use triggers somewhere in applications initialization:

if (!TypeDescriptor.GetAttributes(typeof(Avalonia.Thickness)).Cast<Attribute>().Any(x => x is TypeConverterAttribute))
{
    TypeDescriptor.AddAttributes(typeof(Avalonia.Thickness), new TypeConverterAttribute(typeof(ThicknessTypeConverter)));
}

/*...*/

    public class ThicknessTypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
        {
            return sourceType == typeof(string) || sourceType == typeof(double) || sourceType == typeof(int);
        }

        public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
        {
            return value switch
            {
                string stringValue => new Avalonia.Thickness(double.Parse(stringValue, culture)),
                double doubleValue => new Avalonia.Thickness(doubleValue),
                int intValue => new Avalonia.Thickness(intValue),
                _ => base.ConvertFrom(context, culture, value)
            };
        }
    }

ChangePropertyAction internally uses a heuristic way of converting types (e.g. string->Avalonia.Thickness and string->Avalonia.Brush in your case) and it falldown to call TypeDescriptor.GetConverter. Using reflection it tries to find custom TypeConverter for destynation type. There is no default converter today, but you can do it yourself.

dif-sam avatar Jun 02 '22 13:06 dif-sam

Same problem but with padding:

<i:Interaction.Behaviors>
	<ia:DataTriggerBehavior Binding="{Binding IsExpanded}" ComparisonCondition="Equal" Value="true">
		<ia:ChangePropertyAction TargetObject="{Binding #btn}" PropertyName="Content" Value="&#xE936;"/>
		<ia:ChangePropertyAction TargetObject="{Binding #btn}" PropertyName="Padding" Value="5,7,5,3"/>
		
	</ia:DataTriggerBehavior>
	<ia:DataTriggerBehavior Binding="{Binding IsExpanded}" ComparisonCondition="Equal" Value="false">
		<ia:ChangePropertyAction TargetObject="{Binding #btn}" PropertyName="Padding" Value="9,4,1,6"/>
		<ia:ChangePropertyAction TargetObject="{Binding #btn}" PropertyName="Content" Value="&#xE937;"/>
	</ia:DataTriggerBehavior>
</i:Interaction.Behaviors>

When trying to implement the suggested workaround I can cannot find class Avalonia.Padding. Seems like it would be a pretty low leve object and included in the Avalonia library(?):

public class PaddingTypeConverter : TypeConverter
{
	public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
	{
		return sourceType == typeof(string) || sourceType == typeof(double) || sourceType == typeof(int);
	}

	public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
	{
		return value switch
		{
			string stringValue => new Avalonia.Padding(double.Parse(stringValue, culture)), // error:  .Padding(...) not found
		};
	}
}

sam-wheat avatar Jun 20 '22 18:06 sam-wheat

Instead, it should be parsed compile time. But for that some attributes-hints should be created.

maxkatz6 avatar Jun 21 '22 00:06 maxkatz6