wpf3d游戏引擎TransformView实现

1.TransformView.xaml

<UserControl x:Class="PrimalEditor.Editors.TransformView"

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"

xmlns:local="clr-namespace:PrimalEditor.Editors"

xmlns:vm="clr-namespace:PrimalEditor.Components"

xmlns:utl="clr-namespace:PrimalEditor.Utilities.Controls"

d:DataContext="{d:DesignInstance Type=vm:MSTransform, IsDesignTimeCreatable=True}"

mc:Ignorable="d"

d:DesignHeight="450" d:DesignWidth="800">

<UserControl.Resources>

<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource LightTextBlockStyle}"/>

</UserControl.Resources>

<local:ComponentView Header="Transform">

<Grid>

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition Height="Auto"/>

<RowDefinition Height="Auto"/>

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="78"/>

<ColumnDefinition />

<ColumnDefinition Width="Auto"/>

</Grid.ColumnDefinitions>

<TextBlock Text="Position" Grid.Column="0" Grid.Row="0"/>

<utl:VectorBox X="{Binding PosX}" Y="{Binding PosY}" Z="{Binding PosZ}" Grid.Column="1" Grid.Row="0"

PreviewMouseLeftButtonDown="OnPosition_VectorBox_PreviewMouse_LBD"

PreviewMouseLeftButtonUp="OnPosition_VectorBox_PreviewMouse_LBU"

LostKeyboardFocus="OnPosition_VectorBox_LostKeyboardFocus"

/>

<TextBlock Text="Rotation" Grid.Column="0" Grid.Row="0"/>

<utl:VectorBox X="{Binding RotX}" Y="{Binding RotY}" Z="{Binding RotZ}" Grid.Column="1" Grid.Row="0"

PreviewMouseLeftButtonDown="OnRotation_VectorBox_PreviewMouse_LBD"

PreviewMouseLeftButtonUp="OnRotation_VectorBox_PreviewMouse_LBU"

LostKeyboardFocus="OnRotation_VectorBox_LostKeyboardFocus"

/>

<TextBlock Text="Scale" Grid.Column="0" Grid.Row="0"/>

<utl:VectorBox X="{Binding ScaleX}" Y="{Binding ScaleY}" Z="{Binding ScaleZ}" Grid.Column="1" Grid.Row="0"

PreviewMouseLeftButtonDown="OnScale_VectorBox_PreviewMouse_LBD"

PreviewMouseLeftButtonUp="OnScale_VectorBox_PreviewMouse_LBU"

LostKeyboardFocus="OnScale_VectorBox_LostKeyboardFocus"

/>

</Grid>

</local:ComponentView>

</UserControl>

2.TransformView.xaml.cs

using PrimalEditor.Components;

using PrimalEditor.GameProject;

using PrimalEditor.Utilities;

using System.Diagnostics;

using System.Numerics;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Input;

namespace PrimalEditor.Editors

{

/// <summary>

/// TransformView.xaml 的交互逻辑

/// </summary>

public partial class TransformView : UserControl

{

private Action _undoAction = null;

private bool _propertyChanged = false;

public TransformView()

{

InitializeComponent();

Loaded += OnTransformViewLoaded;

}

private void OnTransformViewLoaded(object sender, RoutedEventArgs e)

{

Loaded -= OnTransformViewLoaded;

(DataContext as MSTransform).PropertyChanged += (s, e) => _propertyChanged = true;

}

private Action GetAction(Func<Transform, (Transform transform, Vector3)> selector,

Action<(Transform transform, Vector3)> forEachAction)

{

if (!(DataContext is MSTransform vm))

{

_undoAction = null;

_propertyChanged = false;

return null;

}

var selection = vm.SelectedComponents.Select(x => selector(x)).ToList();

return new Action(() =>

{

selection.ForEach(x => forEachAction(x));

(GameEntityView.Instance.DataContext as MSEntity)?.GetMSComponent<MSTransform>().Refresh();

});

}

private Action GetPositionAction() => GetAction((x) => (x, x.Position), (x) => x.transform.Position = x.Item2);

private Action GetRotationAction() => GetAction((x) => (x, x.Rotation), (x) => x.transform.Rotation = x.Item2);

private Action GetScaleAction() => GetAction((x) => (x, x.Scale), (x) => x.transform.Scale = x.Item2);

private void RecordActions(Action redoAction, string name)

{

if (_propertyChanged)

{

Debug.Assert(_undoAction != null);

_propertyChanged = false;

Project.UndoRedo.Add(new UndoRedoAction(_undoAction, redoAction, name));

}

}

private void OnPosition_VectorBox_PreviewMouse_LBD(object sender, MouseButtonEventArgs e)

{

_propertyChanged = false;

_undoAction = GetPositionAction();

}

private void OnPosition_VectorBox_PreviewMouse_LBU(object sender, MouseButtonEventArgs e)

{

RecordActions(GetPositionAction(), "Postion Changed");

}

private void OnRotation_VectorBox_PreviewMouse_LBD(object sender, MouseButtonEventArgs e)

{

_propertyChanged = false;

_undoAction = GetRotationAction();

}

private void OnRotation_VectorBox_PreviewMouse_LBU(object sender, MouseButtonEventArgs e)

{

RecordActions(GetPositionAction(), "Rotation Changed");

}

private void OnScale_VectorBox_PreviewMouse_LBD(object sender, MouseButtonEventArgs e)

{

_propertyChanged = false;

_undoAction = GetScaleAction();

}

private void OnScale_VectorBox_PreviewMouse_LBU(object sender, MouseButtonEventArgs e)

{

RecordActions(GetPositionAction(), "Scale Changed");

}

private void OnPosition_VectorBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)

{

if (_propertyChanged && _undoAction != null)

{

OnPosition_VectorBox_PreviewMouse_LBU(sender, null);

}

}

private void OnRotation_VectorBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)

{

if (_propertyChanged && _undoAction != null)

{

OnPosition_VectorBox_PreviewMouse_LBU(sender, null);

}

}

private void OnScale_VectorBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)

{

if (_propertyChanged && _undoAction != null)

{

OnPosition_VectorBox_PreviewMouse_LBU(sender, null);

}

}

}

}