问题
I am trying to set a custom property on a custom control using the Visual State Manager but I'm not having any luck so far. My custom control is just a label with an additional bindable property on it.
public class SelectableLabel : Label
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableLabel), false);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
SetValue(IsSelectedProperty, value);
}
}
I use this control inside a CollectionView to toggle the IsSelected
property when the control enters the Selected
visual state.
<CollectionView
x:Name="cv"
ItemsSource="{Binding Names}"
SelectionMode="Multiple"
SelectedItems="{Binding SelectedNames, Mode=TwoWay}"
VerticalOptions="Fill">
<CollectionView.ItemTemplate>
<DataTemplate>
<local:SelectableLabel
x:Name="lblName"
Text="{Binding First}">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Selected">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableLabel>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
When I run this on an iOS simulator, I'm not seeing the setter being fired when the visual state changes to Selected
. If I change the property in the setter to BackgroundColor
or Text
, I'm seeing the expected behavior. The problem seems specific to the custom property. I looked at the documentation for the Setter.Property
and it states that the Setter can be applied to a BindableProperty
which IsSelected
is. Am I doing something wrong or does the VSM not support this functionality?
Edit: The CollectionView
part of this example is irrelevant. The same issue happens with this code.
public class SelectableEntry : Entry
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
var color = value ? Color.LightBlue : Color.LightPink;
SetValue(IsSelectedProperty, value);
SetValue(BackgroundColorProperty, color);
}
}
}
Here is the corresponding XAML. The background color changes when the first custom Entry control receives focus while the second does not. I also don't see my WriteLine
statement in the console.
<local:SelectableEntry Text="First">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="BackgroundColor"
Value="LightBlue" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="BackgroundColor"
Value="LightPink" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<local:SelectableEntry Text="Second">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup
x:Name="CommonStates">
<VisualState
x:Name="Normal">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState
x:Name="Focused">
<VisualState.Setters>
<Setter
Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
回答1:
I have tried with Bindable Property to check whether property be invoked in VisualStateManager
. That's regrettable, it can not be invoked even in propertyChanged
method . I think maybe bindable property can not work in VisualStateManager
.
Custom Entry
Code as follow :
public class SelectableEntry : Entry
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create("IsSelected", typeof(bool), typeof(SelectableEntry), false ,propertyChanged:changedMethod);
private static void changedMethod(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine($"MDO: {oldValue}.IsSelected_set={newValue}");
}
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set
{
Console.WriteLine($"MDO: {Text}.IsSelected_set={value}");
var color = value ? Color.LightBlue : Color.LightPink;
SetValue(IsSelectedProperty, value);
SetValue(BackgroundColorProperty, color);
}
}
}
Solution:
However , there is a Attached Properties that can be used in Style.Setters
. Then you can also have a try with it in VisualState.Setters
.It also will work .
Attached property class Code as follow :
public class SelectableEntryStyle
{
public static readonly BindableProperty IsSelectedProperty = BindableProperty.CreateAttached("IsSelected", typeof(bool), typeof(SelectableEntryStyle), false,propertyChanged:onChangedMethod);
private static void onChangedMethod(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine($"MDO:IsSelected_set={newValue}");
var color = (bool)newValue ? Color.LightBlue : Color.LightPink;
var entry = bindable as Entry;
entry.SetValue(Entry.BackgroundColorProperty, color);
}
public static bool GetIsSelected(BindableObject view)
{
return (bool)view.GetValue(IsSelectedProperty);
}
public static void SetIsSelected(BindableObject view, bool value)
{
view.SetValue(IsSelectedProperty, value);
}
}
The code of Xaml as follow :
<local:SelectableEntry FontSize="18" Placeholder="Bindable Property">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Disabled">
<VisualState.Setters>
<Setter Property="IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</local:SelectableEntry>
<Entry Placeholder="Attached Property">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="local:SelectableEntryStyle.IsSelected"
Value="False" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Focused">
<VisualState.Setters>
<Setter Property="local:SelectableEntryStyle.IsSelected"
Value="True" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Entry>
Then console can print log when Entry
is Normal
or Focused
.
02-18 14:26:27.360 I/mono-stdout(26014): MDO:IsSelected_set=True
02-18 14:26:28.675 I/mono-stdout(26014): MDO:IsSelected_set=False
The effects :
来源:https://stackoverflow.com/questions/60234901/xamarin-visual-state-manager-and-custom-properties