当初始时间不满足设计师的XAML模式时,对RenderTransform.Changed的订阅将会丢失 [英] Subscription to RenderTransform.Changed will be lost when it does not fulfill the XAML pattern of the designer on initial time

查看:124
本文介绍了当初始时间不满足设计师的XAML模式时,对RenderTransform.Changed的订阅将会丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的用户控制中,我想知道旋转和合。在WPF设计器中制作。所以在我的用户控件中我做了:

  private void Test_Loaded(object sender,RoutedEventArgs e)
{
this.RenderTransform.Changed + = this.RenderTransform_Changed;
}

private void RenderTransform_Changed(object sender,EventArgs e)
{
// do anything
}

似乎 this.RenderTransform 永远不会 null 。但是,除非我的用户控件具有正确的XAML结构,就像设计师在旋转我的控件时所做的那样,它将失败。



示例:
当我打开一个包含以下内容的XAML文件时:

 < my:Test> 
< my:Test.RenderTransform>
< TransformGroup>
< ScaleTransform />
< SkewTransform />
< RotateTransform />
< TranslateTransform />
< / TransformGroup>
< / my:Test.RenderTransform>
< / my:Test>

当我旋转时,将调用 RenderTransform_Changed 我的控制。



但是当XAML是:

 我:试验> 
< my:Test.RenderTransform>
< TransformGroup>
< ScaleTransform />
< SkewTransform />
< TranslateTransform />
< / TransformGroup>
< / my:Test.RenderTransform>
< / my:Test>

 <我的:试验> 
< my:Test.RenderTransform>
< RotateTransform />
< / my:Test.RenderTransform>
< / my:Test>

 <我的:测试/> 

旋转时不会调用 RenderTransform_Changed 我的控制。



我假设,发生这种情况,因为设计师在不遵循 this.RotateTransform 与设计师想要的完全相同的结构。因此,订阅将完全丢失。



为了解决这个问题,我试图向提供相同的结构this.RenderTransform 加载事件之前订阅更改事件:

  private void Test_Loaded(object sender,RoutedEventArgs e)
{
ScaleTransform scale = this.RenderTransform是ScaleTransform
? (ScaleTransform)this.RenderTransform
:new ScaleTransform();
SkewTransform skew = this.RenderTransform是SkewTransform
? (SkewTransform)this.RenderTransform
:new SkewTransform();
RotateTransform rotate = this.RenderTransform是RotateTransform
? (RotateTransform)this.RenderTransform
:new RotateTransform();
TranslateTransform translate = this.RenderTransform是TranslateTransform
? (TranslateTransform)this.RenderTransform
:new TranslateTransform();

if(this.RenderTransform是TransformGroup)
{
TransformCollection tc =((TransformGroup)this.RenderTransform).Children;

foreach(tc中的变换t)
{
if(t为ScaleTransform)scale =(ScaleTransform)t;
if(t为SkewTransform)skew =(SkewTransform)t;
if(t为RotateTransform)rotate =(RotateTransform)t;
if(t是TranslateTransform)translate =(TranslateTransform)t;
}

if(!tc.Any(x => x是ScaleTransform))tc.Add(scale);
if(!tc.Any(x => x是SkewTransform))tc.Add(skew);
if(!tc.Any(x => x是RotateTransform))tc.Add(rotate);
if(!tc.Any(x => x是TranslateTransform))tc.Add(translate);
}
else
{
this.RenderTransform = new TransformGroup()
{
儿童=
{
比例,
skew,
rotate,
translate,
},
};
}

foreach(在Transform(TransformGroup)中转换this.RenderTransform).Children)
{
t.Changed + = this.RenderTransform_Changed;
}
this.RenderTransform.Changed + = this.RenderTransform_Changed;
}

private void RenderTransform_Changed(object sender,EventArgs e)
{
// do anything
}

因此,我试图为初始时间的任何给定的 RenderTransform 结构做好准备。但是,似乎设计师不在乎实际上在 RenderTransform 对象中的内容,它只是重写它,因为XAML仍然不能满足所需的结构。



我可以如何解决这个问题?

解决方案

除非我我的诊断错误,这里有一个答案:



问题



每当您使用 this.RenderTransform.Changed + = ... 注册一个处理程序时,您订阅一个对象,该对象的值为 this.RenderTransform 。当属性然后被更改时,它不再保存您订阅的对象(并且该对象不再有效),但是您仍然订阅该确切的对象,而不是属性的新值。 p>

解决方案



为了跟踪 RenderTransform proprety你需要订阅它的所有者(通常是一个窗口控件)为ValueChanged事件,并在每次发生该事件时注册 RenderTransform.Changed 处理程序。由于 RenderTransform DependencyProperty 的一个快捷属性,称为 RenderTransformProperty ,你需要这样做:

  //在构造函数内
{
DependencyPropertyDescriptor
.FromProperty(RenderTransformProperty)
.AddValueChanged(this,new EventHandler(RenderTransformPropertyChanged));
}

private void RenderTransformPropertyChanged(object sender,EventArgs e)
{
//this.RenderTransform.Changed + = ...
}

其中 DependencyPropertyDescriptor System.ComponendModel 命名空间。


In my user control I want to get aware of rotations & co. made in the WPF designer. So in my user control I did:

    private void Test_Loaded(object sender, RoutedEventArgs e)
    {
        this.RenderTransform.Changed += this.RenderTransform_Changed;
    }

    private void RenderTransform_Changed(object sender, EventArgs e)
    {
        // do anything
    }

It seems this.RenderTransform is never null. However unless my user control has the exact XAML structure like the designer makes when i.e. rotating my control, it will fail.

Example: When I open a XAML file with the following content:

<my:Test>
    <my:Test.RenderTransform>
        <TransformGroup>
            <ScaleTransform/>
            <SkewTransform/>
            <RotateTransform/>
            <TranslateTransform/>
        </TransformGroup>
    </my:Test.RenderTransform>
</my:Test>

the RenderTransform_Changed will be called when I rotate my control.

But when the XAML is:

<my:Test>
    <my:Test.RenderTransform>
        <TransformGroup>
            <ScaleTransform/>
            <SkewTransform/>
            <TranslateTransform/>
        </TransformGroup>
    </my:Test.RenderTransform>
</my:Test>

or

<my:Test>
    <my:Test.RenderTransform>
        <RotateTransform/>
    </my:Test.RenderTransform>
</my:Test>

or

<my:Test/>

it won't call RenderTransform_Changed when rotating my control.

I assume, this happens, because the designer is recreating this.RotateTransform when it does not follow the exact same structure as the designer wants. Thus, the subscription will be lost, entirely.

To solve the problem I tried to provide the same structure to this.RenderTransform in the Loaded event before subscribing to the Changed event:

    private void Test_Loaded(object sender, RoutedEventArgs e)
    {
        ScaleTransform scale = this.RenderTransform is ScaleTransform 
            ? (ScaleTransform)this.RenderTransform 
            : new ScaleTransform();
        SkewTransform skew = this.RenderTransform is SkewTransform 
            ? (SkewTransform)this.RenderTransform 
            : new SkewTransform();
        RotateTransform rotate = this.RenderTransform is RotateTransform 
            ? (RotateTransform)this.RenderTransform 
            : new RotateTransform();
        TranslateTransform translate = this.RenderTransform is TranslateTransform 
            ? (TranslateTransform)this.RenderTransform 
            : new TranslateTransform();

        if (this.RenderTransform is TransformGroup)
        {
            TransformCollection tc = ((TransformGroup)this.RenderTransform).Children;

            foreach (Transform t in tc)
            {
                if (t is ScaleTransform) scale = (ScaleTransform)t;
                if (t is SkewTransform) skew = (SkewTransform)t;
                if (t is RotateTransform) rotate = (RotateTransform)t;
                if (t is TranslateTransform) translate = (TranslateTransform)t;
            }

            if (!tc.Any(x => x is ScaleTransform)) tc.Add(scale);
            if (!tc.Any(x => x is SkewTransform)) tc.Add(skew);
            if (!tc.Any(x => x is RotateTransform)) tc.Add(rotate);
            if (!tc.Any(x => x is TranslateTransform)) tc.Add(translate);
        }
        else
        {
            this.RenderTransform = new TransformGroup()
            {
                Children = 
                {
                    scale,
                    skew,
                    rotate,
                    translate,
                },
            };
        }

        foreach (Transform t in ((TransformGroup)this.RenderTransform).Children)
        {
            t.Changed += this.RenderTransform_Changed;
        }
        this.RenderTransform.Changed += this.RenderTransform_Changed;
    }

    private void RenderTransform_Changed(object sender, EventArgs e)
    {
        // do anything
    }

With that I tried to be ready for any given structure of RenderTransform on initial time. But it seems the designer does not care what's actually in the RenderTransform object, it simply rewrites it, because the XAML still does not fulfill the structure it wants.

What can I do to get rid of this problem?

解决方案

Unless I'm wrong in my diagnosis of the problem, here's an answer:

The problem

Whenever you register a handler with this.RenderTransform.Changed += ... you subscribe to an object which is the value of this.RenderTransform. When the property is then changed, it no longer holds the object to which you subscribed (and that object is no longer in effect), yet you're still subscribed to that exact object, and not the new value of the property.

The solution

In order to keep track of the actual value of the RenderTransform proprety you need to subscribe to it's owner (usually a Window or a Control) for a "ValueChanged" event, and register RenderTransform.Changed handler upon each occurrence of that event. Since RenderTransform is a "shortcut property" for a DependencyProperty called RenderTransformProperty, you need to do it like this:

//inside the constructor
{
    DependencyPropertyDescriptor
        .FromProperty(RenderTransformProperty)
        .AddValueChanged(this, new EventHandler(RenderTransformPropertyChanged));
}

private void RenderTransformPropertyChanged(object sender, EventArgs e)
{
    //this.RenderTransform.Changed += ...
}

where DependencyPropertyDescriptor is in System.ComponendModel namespace.

这篇关于当初始时间不满足设计师的XAML模式时,对RenderTransform.Changed的订阅将会丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆