2.GameEntityView.xaml
<UserControl x:Class="PrimalEditor.Editors.GameEntityView"
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"
mc:Ignorable="d" Background="{StaticResource Editor.Window.GrayBrush3}"
d:DesignHeight="450" d:DesignWidth="800">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ScrollViewer.Style>
<Style TargetType="ScrollViewer">
<Style.Triggers>
<Trigger Property="DataContext" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
</Style>
</ScrollViewer.Style>
<StackPanel>
<Border Height="32">
<ToggleButton x:Name="addComponent" VerticalAlignment="Center"
HorizontalAlignment="Left" Margin="5,0,0,0">
<ToggleButton.Content>
<DockPanel>
<TextBlock Text="Add Component" Margin="5,0"/>
<Path Margin="3,0,2,0"
Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z"
HorizontalAlignment="Center" Fill="Black"
VerticalAlignment="Center"
/>
</DockPanel>
</ToggleButton.Content>
</ToggleButton>
</Border>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="78"/>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name" Grid.Column="0" Margin="5,0,0,0"/>
<TextBox Text="{Binding Name}" Grid.Column="1" Tag="{Binding RenameCommand}"/>
<StackPanel Orientation="Horizontal" Grid.Column="2">
<TextBlock Text="Enabled" Margin="5,0,0,0"/>
<CheckBox IsChecked="{Binding IsEnabled}" Command="{Binding IsEnabledCommand}"
CommandParameter="{Binding IsChecked,RelativeSource={RelativeSource Self}}"
Margin="5,0" VerticalAlignment="Center"/>
</StackPanel>
</Grid>
<ItemsControl ItemsSource="{Binding Components}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</UserControl>
2.GameEntityView.xaml.cs
using PrimalEditor.Components;
using PrimalEditor.GameProject;
using PrimalEditor.Utilities;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
namespace PrimalEditor.Editors
{
public class NullableBoolToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is bool b && b == true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is bool b && b == true;
}
}
/// <summary>
/// GameEntityView.xaml 的交互逻辑
/// </summary>
public partial class GameEntityView : UserControl
{
private Action _undoAction;
private string _propertyName;
public static GameEntityView Instance { get; private set; }
public GameEntityView()
{
InitializeComponent();
DataContext = null;
Instance = this;
DataContextChanged += (_, __) =>
{
if (DataContext != null)
{
(DataContext as MSEntity).PropertyChanged += (s, e) => _propertyName = e.PropertyName;
}
};
}
private Action GetRenameAction()
{
var vm = DataContext as MSEntity;
var selection = vm.SelectedEntities.Select(entity => (entity, entity.Name)).ToList();
return new Action(() =>
{
selection.ForEach(item => item.entity.Name = item.Name);
(DataContext as MSEntity).Refresh();
});
}
private Action GetIsEnabledAction()
{
var vm = DataContext as MSEntity;
var selection = vm.SelectedEntities.Select(entity => (entity, entity.IsEnabled)).ToList();
return new Action(() =>
{
selection.ForEach(item => item.entity.IsEnabled = item.IsEnabled);
(DataContext as MSEntity).Refresh();
});
}
private void OnName_TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
_propertyName = string.Empty;
_undoAction = GetRenameAction();
}
private void OnName_TextBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
if (_propertyName == nameof(MSEntity.Name) && _undoAction != null)
{
var vm = DataContext as MSEntity;
var selection = vm.SelectedEntities.Select(entity => (entity, entity.Name)).ToList();
var redoAction = new Action(() =>
{
selection.ForEach(item => item.entity.Name = item.Name);
});
Project.UndoRedo.Add(new UndoRedoAction(_undoAction, redoAction, "Rename game entity"));
_propertyName = null;
};
_undoAction = null;
}
private void OnIsEnabled_CheckBox_Click(object sender, RoutedEventArgs e)
{
var undoAction = GetIsEnabledAction();
var vm = DataContext as MSEntity;
vm.IsEnabled = (sender as CheckBox).IsChecked == true;
var redoAction = GetIsEnabledAction();
Project.UndoRedo.Add(new UndoRedoAction(undoAction, redoAction,
vm.IsEnabled == true ? "Enable game entity" : "Disable game entity"
));
}
private void OnAddComponent_Button_PreviewMouse_LBD(object sender, MouseButtonEventArgs e)
{
var menu = FindResource("addComponentMenu") as ContextMenu;
var btn = sender as ToggleButton;
btn.IsChecked = true;
menu.Placement = PlacementMode.Bottom;
menu.PlacementTarget = btn;
menu.MinWidth = btn.ActualWidth;
menu.IsOpen = true;
}
private void AddComponent(ComponentType componentType, object data)
{
var creationFunction = ComponentFactory.GetCreationFunction(componentType);
var changedEntities = new List<(GameEntity entity, Component component)>();
var vm = DataContext as MSEntity;
foreach (var entity in vm.SelectedEntities)
{
var component = creationFunction(entity, data);
if (entity.AddComponent(component))
{
changedEntities.Add((entity, component));
}
}
if (changedEntities.Any())
{
vm.Refresh();
Project.UndoRedo.Add(new UndoRedoAction(
() =>
{
changedEntities.ForEach(x => x.entity.RemoveComponent(x.component));
(DataContext as MSEntity).Refresh();
},
() =>
{
changedEntities.ForEach(x => x.entity.AddComponent(x.component));
(DataContext as MSEntity).Refresh();
},
$"Add {componentType} component"
));
}
}
private void AddScriptComponent(object sender, RoutedEventArgs e)
{
AddComponent(ComponentType.Script, (sender as MenuItem).Header.ToString());
}
}
}