In WP7 + Silverlight how can I change the Visual State of an ListBox Item?
I need to change the visual state of my listbox item. Here is the DataTemplate which has the visual states. I'm using WP7 as my environment.
<DataTemplate x:Key="MessageItemTemplate">
<Grid MinWidth="200" MinHeight="90" Width="460" Margin="0,2">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Modes">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0" To="Normal">
<Storyboard>
<DoubleAnimation Duration="0:0:0.4" To="0" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border" d:IsOptimized="True"/>
</Storyboard>
</VisualTransition>
<VisualTransition GeneratedDuration="0"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Normal"/>
<VisualState x:Name="Edit">
<Storyboard>
<DoubleAnimation Duration="0:0:0.7" To="1" Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="border" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<VisualStateManager.CustomVisualStateManager>
<ic:ExtendedVisualStateManager/>
</VisualStateManager.CustomVisualStateManager>
<StackPanel Orientation="Vertical" d:LayoutOverrides="Width, Height" Canvas.ZIndex="10" Margin="7">
<TextBlock x:Name="tbTitle" Text="{Binding Path=Title, Mode=OneWay}" FontSize="24" VerticalAlignment="Top" Foreground="{StaticResource PhoneContrastBackgroundBrush}" FontWeight="Bold" Height="30" FontFamily="Microsoft New Tai Lue"/>
<TextBlock x:Name="tbMessage" Text="{Binding Path=Message, Mode=OneWay}" FontSize="29.333" Foreground="{StaticResource PhoneContrastBackgroundBrush}" Margin="0" FontFamily="Candara" TextWrapping="Wrap" HorizontalAlignment="Left"/>
开发者_如何学Python </StackPanel>
<Border BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Background="{StaticResource PhoneBackgroundBrush}" CornerRadius="10" />
<Border x:Name="border" BorderThickness="4" CornerRadius="4" BorderBrush="#FFED1212" Opacity="0" >
<Grid>
<Path Data="M149,0.16666667 L192,36.166332 L189.60141,-2.7298894 z" Fill="#FFED1212" HorizontalAlignment="Right" Margin="0,-3.031,-2.784,38.328" Stretch="Fill" UseLayoutRounding="False" Width="51.629" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<CompositeTransform Rotation="2.523" TranslateX="-0.076551587038494961" TranslateY="-0.0016857129841283403"/>
</Path.RenderTransform>
</Path>
<Image Margin="0" Source="images/pensil.png" Stretch="Fill" Height="26" Width="26" HorizontalAlignment="Right" VerticalAlignment="Top"/>
</Grid>
</Border>
</Grid>
</DataTemplate>
Heres my ListBox:
<ListBox x:Name="SmsMessagesList" Grid.Row="1"
ItemsSource="{Binding Path=Model.Messages}"
SelectionChanged="SmsMessagesList_SelectionChanged"
ItemTemplate="{StaticResource MessageItemTemplate}">
</ListBox>
The ObservableCollection which I bind to this ListBox's ItemsSource is:
public ObservableCollection<SmsMessage> Messages;
public class SmsMessage : EntityBase
{
private string _CurrentState;
public string CurrentState
{
get
{
return _CurrentState;
}
set
{
_CurrentState = value;
PropertyChangedHandler("CurrentState");
}
}
private string _Title;
public string Title
{
get
{
return _Title;
}
set
{
_Title = value;
PropertyChangedHandler("Title");
}
}
private string _Message;
public string Message
{
get
{
return _Message;
}
set
{
_Message = value;
PropertyChangedHandler("Message");
}
}
}
How can I change the visual state of my ListBox to 'Edit' and 'Normal' based on the property 'CurrentState' changing?
Thanks
If you want to stick to a binding approach, your only real choice is a Blend Behavior. However, since Silverlight 3 (and thus WP7) doesn't support data bound behavior properties, your path is a lot more complicated. Yes, it's a PITA and yes, I hope they'll be announcing SL4 features at MIX next week.
Below is a WPF behavior that does the same thing, to give you an idea of what is required by the behavior but it won't work in Silverlight 3 / WP7 due to the above problem. You'll need to change the State
property to be of type Binding
and go through the convoluted process of getting access to that binding value. You can see examples of how to do this in TailSpin.PhoneClient.Infrastructure.ButtonCommand
of the Patterns & Practices WP7 Dev Guide source or from MVVM Light's EventToCommand.
public class StateManagementBehavior : Behavior<FrameworkElement>
{
public static readonly DependencyProperty StateProperty =
DependencyProperty.Register("State", typeof(string),
typeof(StateManagementBehavior),
new UIPropertyMetadata(null, PropertyChangedCallback));
public static readonly DependencyProperty UseTransitionsProperty =
DependencyProperty.Register("UseTransitions", typeof(bool),
typeof(StateManagementBehavior),
new UIPropertyMetadata(true));
public static void PropertyChangedCallback(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var stateManagementBehavior = (StateManagementBehavior)d;
stateManagementBehavior.GoToState();
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Loaded += (s, e) => GoToState();
}
private void GoToState()
{
if (AssociatedObject == null || State == null) return;
VisualStateManager.GoToState(AssociatedObject, State, UseTransitions);
}
public string State
{
get { return (string)GetValue(StateProperty); }
set { SetValue(StateProperty, value); }
}
public bool UseTransitions
{
get { return (bool)GetValue(UseTransitionsProperty); }
set { SetValue(UseTransitionsProperty, value); }
}
}
Assuming you get it all working, you'll use the behavior like this:
<DataTemplate x:Key="MessageItemTemplate">
<Grid MinWidth="200" MinHeight="90" Width="460" Margin="0,2">
<i:Interactivity.Behaviors>
<infrastructure:StateManagementBehavior State="{Binding CurrentState}"
UseTransitions="True" />
</i:Interactivity.Behaviors>
<VisualStateManager.VisualStateGroups>
...
</VisualStateManager.VisualStateGroups>
...
</Grid>
</DataTemplate>
If you provide a control to act as the container for your listbox items. You can then add the logic for changing state to the code for that control using VisualStateManage.GoToState(this, "Your State", true);
Just managed to get this happening on the SL4 project I'm working (so not sure if it's going to work on WP7, but the original library was made for SL3 so it should), the solution was to use DataStateBehavior
from the Expression Blend Samples on CodePlex inside the DataTemplate:
<i:Interaction.Behaviors>
<ei:DataStateBehavior Binding="{Binding IsEditMode}" Value="True" TrueState="Edit" FalseState="Normal"/>
</i:Interaction.Behaviors>
If you need more than 2 states, you can also use DataStateSwitchBehavior
.
精彩评论