내용 보기

작성자

관리자 (IP : 172.17.0.1)

날짜

2020-07-10 04:30

제목

[WPF] Tip: Cannot animate ‘…’ on an immutable object instance


데이터 트리거를 이용해서 애니메이션을 적용할때 '변경할 수 없는 개체 인스턴스에서 '...'에 애니메이션 효과를 줄 수 없습니다.'

이런 에러가 발생될 경우 아래 글을 참고해서 컨버터를 이용해 처리 한다.

요약하자면, 이미 바인딩 처리 되어 있는 속성을 트리거를 통해 애니메이션 처리를 할 경우 기존 바인딩 처리를 방해하기에 새로운 인스턴스를 생성해서 사용하는 방법이다.

For the most part, you can animate any property in a WPF application.  For example, the following is a rectangle that animates it’s fill color on mouse enter and leave:

<Window x:Class="Scratch.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Scratch"
    Foreground="Black"
    Name="MyWindow">
    <Rectangle Width="100" Height="100" Fill="Green" >
        <Rectangle.Triggers>
            <EventTrigger RoutedEvent="Rectangle.MouseEnter">
                <BeginStoryboard>
                    <Storyboard TargetProperty="Fill.Color">
                        <ColorAnimation To="Red" Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
            <EventTrigger RoutedEvent="Rectangle.MouseLeave">
                <BeginStoryboard>
                    <Storyboard TargetProperty="Fill.Color">
                        <ColorAnimation Duration="0:0:1" />
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Rectangle.Triggers>
    </Rectangle>
</Window>
cs

If you animate a property that’s databound, however, you might get the following exception: “Cannot animate 'Fill.Color' on an immutable object instance.” For example, you’ll get this if you change the rectangle’s fill above to:

Fill="{Binding ElementName=MyWindow, Path=Foreground}" >

The reason for this is a known issue where the animation is trying to make a copy of the Window’s “black” foreground brush, but is unable to because of the interaction with the binding.

As a workaround, you can update the binding to make a copy of the brush for the rectangle. That doesn’t interfere with the binding – any change to the window’s foreground will still be propagated to the rectangle – but the rectangle will make its own copy for a local animation. So the Fill ends up looking like this:

Fill="{Binding ElementName=MyWindow, Path=Foreground, Converter={x:Static local:MyCloneConverter.Instance}}"

… which is referencing an IValueConverter for the binding that looks like this:

internal class MyCloneConverter : IValueConverter
{
    public static MyCloneConverter Instance = new MyCloneConverter();
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is Freezable)
        {
            value = (value as Freezable).Clone();
        }
        return value;
    }
 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
cs



출처1

https://docs.microsoft.com/ko-kr/archive/blogs/mikehillberg/tip-cannot-animate-on-an-immutable-object-instance

출처2