Как определить, изменено ли вложенное свойство

#c# #wpf #storyboard #inotifypropertychanged #helix-3d-toolkit

#c# #wpf #раскадровка #inotifypropertychanged #helix-3d-toolkit

Вопрос:

Я хочу анимировать ModelVisual3D, но я не могу определить, когда изменилась система отсчета родительского объекта.

У меня есть класс FrameOfReference, который представляет собой трехмерную систему координат, использующую углы Эйлера ZYX для описания ориентации. У этого класса есть свойство TransformGroup, которое отражает положение фрейма, которое обновляется при каждом изменении X, Y, Z, A, B или C. Для меня очень важно, чтобы я взаимодействовал с углами Эйлера ZYX для создания преобразований, а не TransformGroup.

У меня также есть класс EOAT («end of arm tool»), который имеет свойства FrameOfReference и ModelVisual3D. Я пытаюсь заставить ModelVisual3D обновляться, если изменилось свойство FrameOfReference.

 public class FrameOfReference
{
    private double _x, _y, _z, _a, _b, _c, _legLength;
    private ModelVisual3D _model;
    private Transform3DGroup _transformGroup;

    public FrameOfReference()
    {
        _x = 0;
        _y = 0;
        _z = 0;
        _a = 0;
        _b = 0;
        _c = 0;
    }

    public double X
    {
        get { return _x; }
        set { _x = value; UpdateTransformGroup();}
    }

    public double Y
    {
        get { return _y; }
        set {
            _y = value; UpdateTransformGroup();}
    }

    public double Z
    {
        get { return _z; }
        set { _z = value; UpdateTransformGroup();}
    }

    public double A
    {
        get { return _a; }
        set{ _a = value; UpdateTransformGroup();}
    }

    public double B
    {
        get { return _b; }
        set { _b = value; UpdateTransformGroup();}
    }

    public double C
    {
        get { return _c; }
        set { _c = value; UpdateTransformGroup();}
    }
    public void Transform3DGroup UpdateTransformGroup()
    {
            //convert ZYX Euler angles into a transformgroup
            Transform3DGroup group = new Transform3DGroup();
            Vector3D e = new Vector3D(C, B, A);
            Quaternion q = new Quaternion(new Vector3D(0.0, 0.0, 1.0), e.Z)
                * new Quaternion(new Vector3D(0.0, 1.0, 0.0), e.Y)
                * new Quaternion(new Vector3D(1.0, 0.0, 0.0), e.X);
            AxisAngleRotation3D r = new AxisAngleRotation3D(q.Axis, q.Angle);
            group.Children.Add(new RotateTransform3D(r));
            group.Children.Add(new TranslateTransform3D(X, Y, Z));
            _transformGroup = group;
    }
    public Transform3DGroup TransformGroup
    {
        get
        { return _transformGroup;}
        set { _transformGroup = value;}

    }
}
  

и мой класс, который является EOAT и содержит ModelVisual3D и FrameOfReference

 class EOATModel
{

    private FrameOfReference _frame;
    private ModelVisual3D _model;

    public EOATModel()
    {
        Frame = new FrameOfReference();
    }

    public EOATModel(FrameOfReference Frame)
    {
        this.Frame = Frame;
    }

    public FrameOfReference Frame
    {
        get
        {
            return _frame;
        }
        set
        {
            _frame = value;
            CreateModel();
        }
    }

    public ModelVisual3D Model
    {
        get
        {
            return _model;
        }
        set
        {
            _model = value;
        }
    }

    public void CreateModel()
    {
        if (_model != null)
        {
            //--a bunch of code that makes the EOAT since its irrelevant--

            _model.Children.Add(EOATCube);
            _model.Transform = Frame.TransformGroup;
        }
    }

}
  

Несколько примеров кода, показывающих, как я создаю _eoat.

 public class Main
{
    EOAT _eoat = new EOAT()
    _eoat.Frame.X = 100;
    _eoat.Frame.Y = 100;
    _eoat.Frame.Z = 100;
    _eoat.Frame.A = 100;
    _eoat.Frame.B = 100;
    _eoat.Frame.C = 100;
    _eoat.Model = new ModelVisual3D();
    viewPort3d.Children.Add(_eoat.Model);
    _eoat.Frame.C = 45;
}
  

Если я введу «_eoat.Frame.C = 45», FrameOfReference внутри _eoat не обнаруживает, что фрейм был изменен, и, следовательно, не обновляет модель с помощью CreateModel(). Я знаю, что мог бы просто вручную вызвать CreateModel() после изменения фрейма, но это не сработает, когда придет время создавать анимационную раскадровку, поскольку анимация просто меняет значение с течением времени и не может вызвать CreateModel() во время анимации.

Короче говоря, как мне заставить EOAT автоматически вызывать CreateModel() всякий раз, когда что-либо внутри фрейма изменяется. Я пробовал код INotifyPropertyChange, но ничего из этого не сработало.

Извините за все содержимое. Я надеюсь, что этот вопрос имеет смысл. Спасибо.

Ответ №1:

Вы можете просто добавить обработчик событий к NotifyPropertyChanged событию FrameOfReference и вызвать CreateModel из обработчика событий.

 public EOATModel()
{
    Frame = new FrameOfReference();
    Frame.PropertyChanged  = (o,e) => CreateModel());
}
  

Комментарии:

1. Этого не хватало! Спасибо, Георг. Теперь все, что мне нужно сделать, это выяснить, как создать эти свойства зависимостей, чтобы я мог ссылаться на них в материале раскадровки целевого свойства.