问题
I'm currently trying to style a ListView
so each of the items inside it can control their own background color, PointerOver, Pressed and Selected states.
I have figured out that I can set the Background of the ListViewItem
to Transparent
and let the DataTemplate
for my item control the Background. But what I'm struggling with is the VisualStates
of the ListViewItem
. They just won't seem to style correctly.
What I've tried so far is so far is putting my Binding
code for the colors inside the Style
for the ListViewItem
like so:
NOTE: Code has been cut down for brevity, ListViewItem
style taken from the Generic.xaml
<Style TargetType="ListViewItem">
<Setters.../>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Grid x:Name="ContentBorder">
<!-- ContentPresenter etc in here -->
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Pressed">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{Binding AccentColour}" />
</ObjectAnimationUsingKeyFrames>
</VisualState>
<!-- More Visual States-->
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
However this doesn't work and I assume it has something to do with the ListViewItem
not knowing the DataContext
for the Binding
.
My item is just a basic class to hold info like the text associated with the item and the colors the for Background and the States.
public class BasicItem {
// Constructor etc
public SolidColorBrush AccentColour { get; set; }
// More Colours
}
Another approach I had considered was creating AttachedProperties
for the Colors on the ListViewItem. Only issue is I'm not sure how I would bind to them.
Anyone have any idea if it's possible for the Item to control its States in this way, any help appreciated.
回答1:
Another approach I had considered was creating AttachedProperties for the Colors on the ListViewItem. Only issue is I'm not sure how I would bind to them.
You are right about using AttachedProperties and this is how it can be done.
Step 1. Define your attached properties
public static Brush GetPointerOverBackground(DependencyObject obj)
{
return (Brush)obj.GetValue(PointerOverBackgroundProperty);
}
public static void SetPointerOverBackground(DependencyObject obj, Brush value)
{
obj.SetValue(PointerOverBackgroundProperty, value);
}
public static readonly DependencyProperty PointerOverBackgroundProperty =
DependencyProperty.RegisterAttached("PointerOverBackground", typeof(Brush), typeof(YourStaticClass), new PropertyMetadata(null));
Step 2. Define default values for your attached properties
<Setter Property="local:YourStaticClass.PointerOverBackground" Value="LightBlue" />
Step 3. Use attached properties in your Visual States
<VisualState x:Name="PointerOver">
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Background">
<DiscreteObjectKeyFrame KeyTime="0" Value="{TemplateBinding local:YourStaticClass.PointerOverBackground}" />
</ObjectAnimationUsingKeyFrames>
</VisualState>
Step 4. Create an Interface that defines all the brushes
The reason of doing this is so we can later cast the object (i.e. BasicItem
) bound to each template to this Interface, without the need of knowing its concrete type. Of course your BasicItem
should implement this Interface.
public interface ISupportListViewItemBrushes
{
SolidColorBrush PointerOverBrush { get; set; }
Step 5. Create a Behavior
responsible for assigning Brush
es to ListViewItem
s
This is where everything comes together. First we will need to install the XAML Behavior Nuget Package. After that, create a Behavior
called SupportListViewItemBrushesBehavior
and make it only attachable to a ListView
.
public class SupportListViewItemBrushesBehavior : Behavior<ListView>
ListView
has an event called ContainerContentChanging
where we have access to each ListViewItem
and its underlying Item
(i.e. BasicItem
/ISupportListViewItemBrushes
) object. Finally, we just use the SetAttachedPropertyName
method to assign the corresponding Brush
to the ListViewItem
like below
private void OnContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
if (!args.InRecycleQueue &&
args.ItemContainer is ListViewItem container &&
args.Item is ISupportListViewItemBrushes brushes)
{
Helper.SetPointerOverBackground(container, brushes.PointerOverBrush);
}
}
That's all!
Note we had to create the Behavior
here because UWP doesn't support FindAncestor
binding yet. Alternatively, rather than using attached properties and a Behavior
, you can extend ListView
/ListViewItem
to achieve the same result.
I have included a small sample here for your reference. And here's the end result. Hope this helps!
回答2:
Implement a StyleSelector that chooses the ListViewItem style you want for a given item, and set it as the ItemContainerStyleSelector on your ListView.
来源:https://stackoverflow.com/questions/45599788/is-it-possible-for-individual-listviewitems-selected-pointerover-and-pressed-st