Пользовательский элемент управления WPF ViewPort3D с привязкой свойства ModelVisual3D? - PullRequest
2 голосов
/ 24 мая 2011

Я создаю пользовательский элемент управления с ViewPort3D.Я хочу иметь возможность обновить порт представления со связанным свойством ModelVisual3D (через открытый метод, принимающий данные, которые используются для создания визуальной модели).Чтобы попробовать пользовательский элемент управления, я также пытаюсь использовать его в окне.Мне кажется, что я что-то упускаю из-за привязки, и задаюсь вопросом, может ли кто-нибудь помочь мне, указав, что мне не хватает.

Это мой код:

Элемент управления

<UserControl x:Class="TheProject.TheUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             x:Name="ThisUserControl"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <Viewport3D Name="mainViewPort" ClipToBounds="True">
            <Viewport3D.Camera>
                <PerspectiveCamera
                      FarPlaneDistance="100"
                      LookDirection="-11,-10,-9"
                      UpDirection="0,1,0"
                      NearPlaneDistance="2" 
                      Position="11,10,9"
                      FieldOfView="70" />
            </Viewport3D.Camera>
            <Viewport3D.Children>
                <ModelVisual3D Content="{Binding Path=Model, ElementName=ThisUserControl}" />
                <ModelVisual3D>
                    <ModelVisual3D.Content>
                        <DirectionalLight 
                                Color="White" 
                                Direction="-2,-3,-1">
                        </DirectionalLight>
                    </ModelVisual3D.Content>
                </ModelVisual3D>
            </Viewport3D.Children>
        </Viewport3D>
    </Grid>
</UserControl>

Код позади

using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.ComponentModel;

namespace TheProject
{
  public partial class TheUserControl : INotifyPropertyChanged
  {
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
        handler(this, new PropertyChangedEventArgs(name));
    }

    private ModelVisual3D _model;

    protected ModelVisual3D Model
    {
      get { return this._model; }
      set
      {
        this._model = value;
        OnPropertyChanged("Model");
      }
    }

    public void SetTheData(ITheData theData)
    {
      if (theData != null)
      {
        this.Model = SimpleTriangleModel(theData);
      }
    }

    private static ModelVisual3D SimpleTriangleModel(ITheData theData)
    {
      var point0 = new Point3D(theData.X, 0, 0);
      var point1 = new Point3D(0, theData.Y, 0);
      var point2 = new Point3D(0, 0, theData.Z);

      return new ModelVisual3D
      {
        Content = CreateTriangleModel(point0, point1, point2, new SolidColorBrush(Colors.Tomato))
      };
    }

    public static Model3DGroup CreateTriangleModel(Point3D p0, Point3D p1, Point3D p2, Brush brush)
    {
      var mesh = new MeshGeometry3D();
      mesh.Positions.Add(p0);
      mesh.Positions.Add(p1);
      mesh.Positions.Add(p2);
      mesh.TriangleIndices.Add(0);
      mesh.TriangleIndices.Add(1);
      mesh.TriangleIndices.Add(2);
      Vector3D normal = CalculateNormal(p0, p1, p2);
      mesh.Normals.Add(normal);
      mesh.Normals.Add(normal);
      mesh.Normals.Add(normal);
      Material material = new DiffuseMaterial(brush);
      var model = new GeometryModel3D(mesh, material);
      var group = new Model3DGroup();
      group.Children.Add(model);
      return group;
    }

    public static Vector3D CalculateNormal(Point3D p0, Point3D p1, Point3D p2)
    {
      var v0 = new Vector3D(p1.X - p0.X, p1.Y - p0.Y, p1.Z - p0.Z);
      var v1 = new Vector3D(p2.X - p1.X, p2.Y - p1.Y, p2.Z - p1.Z);
      return Vector3D.CrossProduct(v0, v1);
    }
  }
}

Интерфейс данных

namespace TheProject
{
  public interface ITheData
  {
    double X { set; get; }
    double Y { set; get; }
    double Z { set; get; }
  }
}

Управление пользователем с помощью окна

<Window x:Class="TheProject.TheWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:TheProject"
        Title="The Window" Height="416" Width="649">
    <Grid>
        <local:TheUserControl x:Name="TheUserControl1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
    </Grid>
</Window>

Код позади

using System.Windows;

namespace TheProject
{
  public partial class TheWindow : Window
  {
    private class DataClass : ITheData
    {
      public double X { get; set; }
      public double Y { get; set; }
      public double Z { get; set; }
    }

    public TheWindow()
    {
      InitializeComponent();
      ITheData newData = new DataClass { X = 3, Y = 2, Z = 1 };
      this.TheUserControl1.SetTheData(newData);
      this.DataContext = this;
    }
  }
}

Обработчик события является нулевым в OnPropertyChanged, поэтому я предполагаю, что есть какой-то механизм привязки, который мне не хватаетЯ пробовал кучу разных подходов.Я пытался прочитать о связывании данных в WPF и о DataContext, но не могу понять, как это работает или как его использовать.Я также читал о свойствах зависимостей, но не уверен, что это то, что мне нужно.

(Также приветствуются любые рекомендации по созданию этого передового опыта. Должен ли я попробовать MVVM: если пользовательский элемент управления, и в этомслучай как? Или вы считаете это ненужной сложностью?)

Ничто из этого не помогло мне заставить его работать:

WPF - Связывание в простом пользовательском управлении Простая привязка WPF к свойству объектов Свойство пользовательского элемента управления UserControl, используемое дочерним элементом Как связать свойство пользовательского элемента управления со свойствами этого же элемента управления в WPF? WPF Проблема привязки пользовательского элемента управления

Спасибо / Ульф - в настоящее время новичок WPF ...: -)

...