【问题标题】:Cannot set a property on object because it is in a read-only state无法在对象上设置属性,因为它处于只读状态
【发布时间】:2015-01-02 01:55:16
【问题描述】:

在我的XAML 我有以下内容:

<DataTemplate x:Key="ItemTemplate">
        <DockPanel Width="Auto">
            <Button Click="SelectMovie_Click" DockPanel.Dock="Top">
                <Button.Template>
                    <ControlTemplate >
                        <Image Source="{Binding image}"/>
                    </ControlTemplate>
                </Button.Template>                   
                <Button.Triggers>
                    <EventTrigger RoutedEvent="Button.Click">
                        <BeginStoryboard>
                            <Storyboard>
                                <local:GridLengthAnimation
                                    Storyboard.Target="{Binding ElementName=col2}"
                                    Storyboard.TargetProperty="Width"
                                    Duration="0:0:2"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Button.Triggers>
            </Button>
            <TextBlock Text="{Binding title}" HorizontalAlignment="Center" DockPanel.Dock="Bottom"/>
        </DockPanel>
    </DataTemplate>

<Grid Grid.Row="2" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Name="col1"  Width="{Binding ElementName=root, Path=DataContext.gla.LeftGridWidth}"/>
            <ColumnDefinition Name="col2" Width="{Binding ElementName=root, Path=DataContext.gla.RightGridWidth}"/>
        </Grid.ColumnDefinitions>
         ...
         ...
</Grid>

glaGridLengthAnimationObject

当我尝试设置 Dependency Property 时出现上述错误

public class GridLengthAnimation : AnimationTimeline
{
    public override Type TargetPropertyType
    {
        get
        {
            return typeof(GridLength);
        }
    }

    protected override System.Windows.Freezable CreateInstanceCore()
    {
        return new GridLengthAnimation();
    }

    public GridLengthAnimation()
    {
        LeftGridWidth = new GridLength(7, GridUnitType.Star);
        RightGridWidth = new GridLength(0, GridUnitType.Star);
    }

    public static readonly DependencyProperty LeftGridWidthProperty = DependencyProperty.Register("LeftGridWidth", typeof(GridLength), typeof(GridLengthAnimation));
    public GridLength LeftGridWidth
    {
        get { return (GridLength)this.GetValue(LeftGridWidthProperty); }
        set { this.SetValue(LeftGridWidthProperty, value); }
    }

    public static readonly DependencyProperty RightGridWidthProperty = DependencyProperty.Register("RightGridWidth", typeof(GridLength), typeof(GridLengthAnimation));
    public GridLength RightGridWidth
    {

        get { return (GridLength)this.GetValue(RightGridWidthProperty); }
        set { this.SetValue(RightGridWidthProperty, value); }
    }

    public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
    {
        double rightGridVal = ((GridLength)GetValue(GridLengthAnimation.RightGridWidthProperty)).Value;
        double leftGridVal = ((GridLength)GetValue(GridLengthAnimation.LeftGridWidthProperty)).Value;

        RightGridWidth = rightGridVal == 0 ? new GridLength(3, GridUnitType.Star) : new GridLength(0, GridUnitType.Star);

        return RightGridWidth;
    }        
}

此处发生错误:

 RightGridWidth = rightGridVal == 0 ? new GridLength(3, GridUnitType.Star) : new GridLength(0, GridUnitType.Star);

Stack Trace

System.InvalidOperationException: Cannot set a property on object   'VideoManager.GridLengthAnimation' because it is in a read-only state.
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value,   PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue,   OperationType operationType, Boolean isInternal)
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at VideoManager.GridLengthAnimation.set_RightGridWidth(GridLength value) in    c:\Users\Giri\Documents\Visual Studio   2013\Projects\VideoManager\VideoManager\GridLengthAnimation.cs:line 47
at VideoManager.GridLengthAnimation.GetCurrentValue(Object defaultOriginValue, Object    defaultDestinationValue, AnimationClock animationClock) in c:\Users\Giri\Documents\Visual Studio   2013\Projects\VideoManager\VideoManager\GridLengthAnimation.cs:line 56
A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll     

在我的LeftGrid 中有多个ButtonsLeftGrid 的默认宽度为7*,而RightGrid 最初设置为0*(不可见)。在LeftGrid 中单击Button 时,RightGrid 应扩展为3* 的宽度。 RightGrid 的扩展应该是动画的。最后,如果RightGrid 被展开并且LeftGrid 中的一个按钮被连续点击两次,RightGrid 应该缩回到0*

【问题讨论】:

  • 不管怎样,您的Register 调用最后缺少元数据。我怀疑这会导致错误,但可能值得一试。
  • 能否请您添加带有完整堆栈跟踪的异常详细信息?这将大大有助于解决问题。
  • @DrewMarsh 我添加了一些额外的信息。
  • 你为什么要在动画运行时设置RightGridWidth属性的值?
  • @Giri 异常的类型和消息呢?如果您在调试器中出现故障,只需转到即时窗口并执行 $exception.ToString() 并将其输出粘贴到此处。

标签: c# wpf dependency-properties freezable


【解决方案1】:

GridLengthAnimation 的最简单实现如下所示。它只添加了一个 To 属性(例如 DoubleAnimation 具有),但没有添加 FromBy 属性。因此,它只能将属性从其当前值设置为指定的目标值。

public class GridLengthAnimation : AnimationTimeline
{
    public static readonly DependencyProperty ToProperty =
        DependencyProperty.Register(
            "To", typeof(GridLength), typeof(GridLengthAnimation));

    public GridLength To
    {
        get { return (GridLength)GetValue(ToProperty); }
        set { SetValue(ToProperty, value); }
    }

    public override Type TargetPropertyType
    {
        get { return typeof(GridLength); }
    }

    protected override Freezable CreateInstanceCore()
    {
        return new GridLengthAnimation();
    }

    public override object GetCurrentValue(
        object defaultOriginValue, object defaultDestinationValue,
        AnimationClock animationClock)
    {
        var from = (GridLength)defaultOriginValue;

        if (from.GridUnitType != To.GridUnitType ||
            !animationClock.CurrentProgress.HasValue)
        {
            return from;
        }

        var p = animationClock.CurrentProgress.Value;

        return new GridLength(
            (1d - p) * from.Value + p * To.Value,
            from.GridUnitType);
    }
}

你会这样使用它:

<local:GridLengthAnimation
    Storyboard.Target="{Binding ElementName=col2}"
    Storyboard.TargetProperty="Width"
    Duration="0:0:2" To="3*"/>

【讨论】:

  • 谢谢克莱门斯。在进行RightGrid 的扩展和收缩之前,我需要满足If 条件。你能告诉我我可以在代码中的什么地方插入这个吗?
  • 只要您可以设置To 值,您就不需要它。它应该有什么好处?
  • RightGrid 应该仅在右网格展开并且连续单击两次相同按钮时收缩,而不仅仅是在单击任何按钮并且右网格已经展开时。
  • 一个动画不应该知道它正在动画的哪个属性,以及在什么条件下的哪个方向。它应该只提供一个与时间相关的值,仅此而已。您的状况检查属于其他地方。例如,您可以添加一个 Click 事件处理程序,根据当前条件设置动画的 To 值,而不是 XAML 中的 Click 事件触发器。
猜你喜欢
  • 2018-12-07
  • 1970-01-01
  • 2016-02-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-24
  • 2019-02-11
  • 1970-01-01
相关资源
最近更新 更多