Пользовательский элемент управления WPF ViewPort3D с привязкой свойства ModelVisual3D?
Я создаю пользовательский элемент управления, который имеет 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 обработчик событий имеет значение null, поэтому я полагаю, что есть какой-то механизм привязки, который мне не хватает. Я пробовал кучу разных подходов. Я пытался прочитать о связывании данных в WPF и о DataContext, но не могу понять, как это работает или как его использовать. Я также читал о свойствах зависимостей, но не уверен, что это то, что мне нужно.
(Также приветствуются любые рекомендации по созданию этой передовой практики. Должен ли я попробовать MVVM: если пользовательский элемент управления, и в таком случае как? Или вы считаете это ненужной сложностью?)
Ничто из этого не помогло мне заставить его работать:
WPF - Связывание в простом пользовательском элементе управления WPF Простое связывание со свойством объектов Custom UserControl Свойство, используемое дочерним элементом Как я могу связать свойство пользовательского элемента управления со свойствами этого же элемента управления в WPF? Проблема привязки пользовательского элемента управления WPF
Спасибо / Ульф - в настоящее время новичок WPF...:-)