StackOverflow与DataStateBehavior和MVVM绑定

时间:2014-10-11 01:50:11

标签: c# windows-phone-8 mvvm data-binding stack-overflow

在Windows Phone 8 Silverlight应用程序中,当我的ViewModel属性发生更改时,我使用DataStateBehavior以不同的样式显示数据绑定列表项。问题是在ViewModel的构造函数中设置了Question中的属性。现在加载ListBox时,它进入无限循环,导致堆栈溢出。

<ListBox ItemsSource="{Binding Trips}"
                         HorizontalContentAlignment="Stretch"
                         SelectionMode="Multiple">
                    <ListBox.ItemContainerStyle>
                        <Style TargetType="ListBoxItem">
                            <Setter Property="Background"
                                    Value="Transparent" />
                            <Setter Property="BorderThickness"
                                    Value="0" />
                            <Setter Property="BorderBrush"
                                    Value="Transparent" />
                            <Setter Property="Padding"
                                    Value="0" />
                            <Setter Property="HorizontalContentAlignment"
                                    Value="Stretch" />
                            <Setter Property="VerticalContentAlignment"
                                    Value="Top" />
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="ListBoxItem">
                                        <Border x:Name="LayoutRoot"
                                                BorderBrush="{TemplateBinding BorderBrush}"
                                                BorderThickness="{TemplateBinding BorderThickness}"
                                                Background="{TemplateBinding Background}"
                                                HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
                                                VerticalAlignment="{TemplateBinding VerticalAlignment}">
                                            <VisualStateManager.VisualStateGroups>
                                                <VisualStateGroup x:Name="CommonStates">
                                                    <VisualState x:Name="Normal" />
                                                    <VisualState x:Name="MouseOver" />
                                                    <VisualState x:Name="Disabled">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background"
                                                                                           Storyboard.TargetName="LayoutRoot">
                                                                <DiscreteObjectKeyFrame KeyTime="0"
                                                                                        Value="{StaticResource TransparentBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                            <DoubleAnimation Duration="0"
                                                                             To=".5"
                                                                             Storyboard.TargetProperty="Opacity"
                                                                             Storyboard.TargetName="ContentContainer" />
                                                        </Storyboard>
                                                    </VisualState>
                                                </VisualStateGroup>
                                                <VisualStateGroup x:Name="SelectionStates">
                                                    <VisualState x:Name="Unselected" />
                                                    <VisualState x:Name="Selected" />
                                                </VisualStateGroup>
                                                <VisualStateGroup x:Name="BackEndStates">
                                                    <VisualState x:Name="IsNormal" />
                                                    <VisualState x:Name="IsSelected">
                                                        <Storyboard>
                                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground"
                                                                                           Storyboard.TargetName="ContentContainer">
                                                                <DiscreteObjectKeyFrame KeyTime="0"
                                                                                        Value="{StaticResource PhoneAccentBrush}" />
                                                            </ObjectAnimationUsingKeyFrames>
                                                        </Storyboard>
                                                    </VisualState>
                                                </VisualStateGroup>
                                            </VisualStateManager.VisualStateGroups>
                                            <ContentControl x:Name="ContentContainer"
                                                            ContentTemplate="{TemplateBinding ContentTemplate}"
                                                            Content="{TemplateBinding Content}"
                                                            Foreground="{TemplateBinding Foreground}"
                                                            HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                            Margin="{TemplateBinding Padding}"
                                                            VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
                                            <i:Interaction.Behaviors>
                                                <ec:DataStateBehavior Binding="{Binding IsSelected}"
                                                                      Value="True"
                                                                      TrueState="IsSelected"
                                                                      FalseState="IsNormal" />
                                            </i:Interaction.Behaviors>

                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </ListBox.ItemContainerStyle>

                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <Grid>
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Tap">
                                        <ec:CallMethodAction TargetObject="{Binding}"
                                                             MethodName="ToggleIsSelected" />
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>

                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>
                                <TextBlock Text="{Binding TripName, Mode=OneWay}" />
                                <TextBlock Text="{Binding StartTime, Mode=OneWay}"
                                           Grid.Row="1" />
                                <Line Height="1"
                                      Grid.Row="2"
                                      Stroke="{StaticResource PhoneAccentBrush}"
                                      Fill="{StaticResource PhoneAccentBrush}" />
                            </Grid>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

如您所见,我删除了原始Selected状态的StoryBoard。我有一组新的视觉状态,由DataStateBehavior触发。

现在当我尝试运行它时,我在尝试渲染列表框时得到了一个stackoverflow。堆栈帧充满了这种模式。看起来当DataStateBehavior设置状态时,它会触发应用模板,并重复整个评估周期。

[Managed to Native Transition]  
System.Windows.ni.dll!MS.Internal.XcpImports.FrameworkElement_ApplyTemplate(System.Windows.FrameworkElement frameworkElement)   Unknown
System.Windows.ni.dll!System.Windows.Controls.Control.ApplyTemplate()   Unknown
microsoft.expression.interactions.DLL!Microsoft.Expression.Interactivity.VisualStateUtilities.GoToState(System.Windows.FrameworkElement element, string stateName, bool useTransitions) Unknown
microsoft.expression.interactions.DLL!Microsoft.Expression.Interactivity.Core.DataStateBehavior.Evaluate()  Unknown
microsoft.expression.interactions.DLL!Microsoft.Expression.Interactivity.Core.DataStateBehavior.OnBindingChanged(System.Windows.DependencyObject obj, System.Windows.DependencyPropertyChangedEventArgs args)   Unknown
System.Windows.ni.dll!System.Windows.DependencyObject.RaisePropertyChangeNotifications(System.Windows.DependencyProperty dp, object oldValue, object newValue)  Unknown
System.Windows.ni.dll!System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.DependencyProperty property, System.Windows.EffectiveValueEntry oldEntry, ref System.Windows.EffectiveValueEntry newEntry, System.Windows.DependencyObject.ValueOperation operation)  Unknown
System.Windows.ni.dll!System.Windows.DependencyObject.RefreshExpression(System.Windows.DependencyProperty dp)   Unknown
System.Windows.ni.dll!System.Windows.Data.BindingExpression.SendDataToTarget()  Unknown
System.Windows.ni.dll!System.Windows.Data.BindingExpression.SourceAcquired()    Unknown
System.Windows.ni.dll!System.Windows.Data.BindingExpression.System.Windows.IDataContextChangedListener.OnDataContextChanged(object sender, System.Windows.DataContextChangedEventArgs e)    Unknown
System.Windows.ni.dll!System.Windows.WeakDataContextChangedListener.MentorDataContextChanged(object sender, System.Windows.DataContextChangedEventArgs e)   Unknown
System.Windows.ni.dll!System.Windows.FrameworkElement.OnDataContextChanged(System.Windows.DataContextChangedEventArgs e)    Unknown
System.Windows.ni.dll!System.Windows.FrameworkElement.OnTreeParentUpdated(System.Windows.DependencyObject newParent, bool bIsNewParentAlive)    Unknown
System.Windows.ni.dll!System.Windows.DependencyObject.UpdateTreeParent(MS.Internal.IManagedPeer oldParent, MS.Internal.IManagedPeer newParent, bool bIsNewParentAlive, bool keepReferenceToParent)  Unknown
System.Windows.ni.dll!MS.Internal.FrameworkCallbacks.ManagedPeerTreeUpdate(System.IntPtr oldParentElement, System.IntPtr parentElement, System.IntPtr childElement, byte bIsParentAlive, byte bKeepReferenceToParent, byte bCanCreateParent)    Unknown
[Native to Managed Transition]  

有人能想出一种防止这种无限循环的方法吗?

1 个答案:

答案 0 :(得分:0)

好的,事实证明这是.Net现在的另一个特质,documentation还不够清楚,并留下了很多“弄明白”。经过大量的试验,我发现如果绑定值在加载时为null,则行为有效。所以我最终将我的属性更改为bool?(Nullable bool)而不是简单bool,在构造函数中将其设置为Null,并实现延迟加载逻辑以设置为true / false。现在它不会导致StackOverFLow。

如果有人想尝试一下,请使用http://1drv.ms/1D8l6yS中的示例项目,它既有问题版本也有固定版本。