1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-31 09:43:46 +00:00

Databindings - Added conditional databindings

Conditions - Added easy method for null-handling in operators
This commit is contained in:
Robert 2020-09-23 19:26:44 +02:00
parent b19cc6ca54
commit b73ea53622
26 changed files with 491 additions and 134 deletions

View File

@ -23,7 +23,11 @@ namespace Artemis.Core.DefaultTypes
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide) public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{ {
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _contains, Expression.Call(rightSide, _toLower)), Expression.Constant(true)); var contains = Expression.Equal(
Expression.Call(Expression.Call(leftSide, _toLower), _contains, Expression.Call(rightSide, _toLower)),
Expression.Constant(true)
);
return AddNullChecks(leftSide, rightSide, contains);
} }
} }
} }

View File

@ -23,7 +23,11 @@ namespace Artemis.Core.DefaultTypes
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide) public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{ {
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _endsWith, Expression.Call(rightSide, _toLower)), Expression.Constant(true)); var endsWith = Expression.Equal(
Expression.Call(Expression.Call(leftSide, _toLower), _endsWith, Expression.Call(rightSide, _toLower)),
Expression.Constant(true)
);
return AddNullChecks(leftSide, rightSide, endsWith);
} }
} }
} }

View File

@ -23,7 +23,11 @@ namespace Artemis.Core.DefaultTypes
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide) public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{ {
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _contains, Expression.Call(rightSide, _toLower)), Expression.Constant(false)); var notContains = Expression.Equal(
Expression.Call(Expression.Call(leftSide, _toLower), _contains, Expression.Call(rightSide, _toLower)),
Expression.Constant(false)
);
return AddNullChecks(leftSide, rightSide, notContains);
} }
} }
} }

View File

@ -23,7 +23,11 @@ namespace Artemis.Core.DefaultTypes
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide) public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{ {
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _startsWith, Expression.Call(rightSide, _toLower)), Expression.Constant(true)); var startsWith = Expression.Equal(
Expression.Call(Expression.Call(leftSide, _toLower), _startsWith, Expression.Call(rightSide, _toLower)),
Expression.Constant(true)
);
return AddNullChecks(leftSide, rightSide, startsWith);
} }
} }
} }

View File

@ -53,5 +53,34 @@ namespace Artemis.Core
/// <param name="rightSide">The parameter on the right side of the expression</param> /// <param name="rightSide">The parameter on the right side of the expression</param>
/// <returns></returns> /// <returns></returns>
public abstract BinaryExpression CreateExpression(Expression leftSide, Expression rightSide); public abstract BinaryExpression CreateExpression(Expression leftSide, Expression rightSide);
/// <summary>
/// Wraps the provided expression in null-checks for the left and right side
/// <para>
/// The resulting expression body looks like:
/// <code>(a == null &amp;&amp; b == null) || ((a != null &amp;&amp; b != null) &amp;&amp; &lt;expression&gt;)</code>
/// </para>
/// </summary>
/// <param name="leftSide">The left side to check for nulls</param>
/// <param name="rightSide">The right side to check for nulls</param>
/// <param name="expression">The expression to wrap</param>
/// <returns>The wrapped expression</returns>
protected BinaryExpression AddNullChecks(Expression leftSide, Expression rightSide, BinaryExpression expression)
{
var nullConst = Expression.Constant(null);
return Expression.OrElse(
Expression.AndAlso(
Expression.Equal(leftSide, nullConst),
Expression.Equal(rightSide, nullConst)
),
Expression.AndAlso(
Expression.AndAlso(
Expression.NotEqual(leftSide, nullConst),
Expression.NotEqual(rightSide, nullConst)
),
expression
)
);
}
} }
} }

View File

@ -152,9 +152,10 @@ namespace Artemis.Core
private void ApplyRegistration(DataBindingRegistration<TLayerProperty, TProperty> dataBindingRegistration) private void ApplyRegistration(DataBindingRegistration<TLayerProperty, TProperty> dataBindingRegistration)
{ {
if (dataBindingRegistration != null) if (dataBindingRegistration == null)
dataBindingRegistration.DataBinding = this; throw new ArgumentNullException(nameof(dataBindingRegistration));
dataBindingRegistration.DataBinding = this;
Converter = dataBindingRegistration?.Converter; Converter = dataBindingRegistration?.Converter;
Registration = dataBindingRegistration; Registration = dataBindingRegistration;
@ -226,8 +227,10 @@ namespace Artemis.Core
{ {
if (_disposed) if (_disposed)
throw new ObjectDisposedException("DataBinding"); throw new ObjectDisposedException("DataBinding");
// General // General
var registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression); var registration = LayerProperty.GetDataBindingRegistration<TProperty>(Entity.TargetExpression);
if (registration != null)
ApplyRegistration(registration); ApplyRegistration(registration);
EasingTime = Entity.EasingTime; EasingTime = Entity.EasingTime;

View File

@ -17,6 +17,7 @@ namespace Artemis.Core
{ {
DataBinding = dataBinding; DataBinding = dataBinding;
Entity = entity; Entity = entity;
Load();
} }
internal ConditionalDataBindingEntity Entity { get; } internal ConditionalDataBindingEntity Entity { get; }
@ -90,8 +91,14 @@ namespace Artemis.Core
OnConditionsUpdated(); OnConditionsUpdated();
} }
internal void ApplyOrder() /// <summary>
/// Applies the current order of conditions to the <see cref="Conditions" /> collection
/// </summary>
public void ApplyOrder()
{ {
if (_disposed)
throw new ObjectDisposedException("ConditionalDataBinding");
_conditions.Sort((a, b) => a.Order.CompareTo(b.Order)); _conditions.Sort((a, b) => a.Order.CompareTo(b.Order));
for (var index = 0; index < _conditions.Count; index++) for (var index = 0; index < _conditions.Count; index++)
{ {

View File

@ -13,10 +13,11 @@ namespace Artemis.Core
/// Creates a new instance of the <see cref="DataBindingCondition{TLayerProperty,TProperty}" /> class /// Creates a new instance of the <see cref="DataBindingCondition{TLayerProperty,TProperty}" /> class
/// </summary> /// </summary>
/// <param name="conditionalDataBinding">The conditional data binding this condition is applied too</param> /// <param name="conditionalDataBinding">The conditional data binding this condition is applied too</param>
public DataBindingCondition(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding) internal DataBindingCondition(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding)
{ {
ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding)); ConditionalDataBinding = conditionalDataBinding ?? throw new ArgumentNullException(nameof(conditionalDataBinding));
Order = conditionalDataBinding.Conditions.Count + 1; Order = conditionalDataBinding.Conditions.Count + 1;
Condition = new DataModelConditionGroup(null);
Entity = new DataBindingConditionEntity(); Entity = new DataBindingConditionEntity();
Save(); Save();
} }
@ -34,9 +35,9 @@ namespace Artemis.Core
public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; } public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; }
/// <summary> /// <summary>
/// Gets the position at which the modifier appears on the data binding /// Gets or sets the position at which the modifier appears on the data binding
/// </summary> /// </summary>
public int Order { get; internal set; } public int Order { get; set; }
/// <summary> /// <summary>
/// Gets or sets the value to be applied when the condition is met /// Gets or sets the value to be applied when the condition is met
@ -82,7 +83,7 @@ namespace Artemis.Core
? new DataModelConditionGroup(null, Entity.Condition) ? new DataModelConditionGroup(null, Entity.Condition)
: new DataModelConditionGroup(null); : new DataModelConditionGroup(null);
Value = JsonConvert.DeserializeObject<TProperty>(Entity.Value); Value = Entity.Value == null ? default : JsonConvert.DeserializeObject<TProperty>(Entity.Value);
Order = Entity.Order; Order = Entity.Order;
} }
@ -93,15 +94,5 @@ namespace Artemis.Core
Condition.Dispose(); Condition.Dispose();
} }
/// <summary>
/// Updates the order and resorts the Conditions list in the <see cref="ConditionalDataBinding" />
/// </summary>
/// <param name="order"></param>
public void UpdateOrder(int order)
{
Order = order;
ConditionalDataBinding.ApplyOrder();
}
} }
} }

View File

@ -46,9 +46,9 @@ namespace Artemis.Core
public ProfileRightSideType ParameterType { get; private set; } public ProfileRightSideType ParameterType { get; private set; }
/// <summary> /// <summary>
/// Gets the position at which the modifier appears on the data binding /// Gets or sets the position at which the modifier appears on the data binding
/// </summary> /// </summary>
public int Order { get; internal set; } public int Order { get; set; }
/// <summary> /// <summary>
/// Gets the currently used instance of the parameter data model /// Gets the currently used instance of the parameter data model

View File

@ -224,7 +224,10 @@ namespace Artemis.Core
OnModifiersUpdated(); OnModifiersUpdated();
} }
internal void ApplyOrder() /// <summary>
/// Applies the current order of conditions to the <see cref="Modifiers" /> collection
/// </summary>
public void ApplyOrder()
{ {
_modifiers.Sort((a, b) => a.Order.CompareTo(b.Order)); _modifiers.Sort((a, b) => a.Order.CompareTo(b.Order));
for (var index = 0; index < _modifiers.Count; index++) for (var index = 0; index < _modifiers.Count; index++)

View File

@ -70,6 +70,9 @@ namespace Artemis.Core.Services
public async Task UpdateModuleActivation() public async Task UpdateModuleActivation()
{ {
if (ActiveModuleSemaphore.CurrentCount == 0)
return;
try try
{ {
await ActiveModuleSemaphore.WaitAsync(); await ActiveModuleSemaphore.WaitAsync();

View File

@ -36,8 +36,7 @@
ToolTip="{Binding SelectedPropertyViewModel.DisplayPropertyPath}" ToolTip="{Binding SelectedPropertyViewModel.DisplayPropertyPath}"
IsEnabled="{Binding IsEnabled}" IsEnabled="{Binding IsEnabled}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
Click="PropertyButton_OnClick" Click="PropertyButton_OnClick">
Visibility="{Binding ShowFreeInput, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
<Button.ContextMenu> <Button.ContextMenu>
<ContextMenu ItemsSource="{Binding DataModelViewModel.Children}" IsOpen="{Binding IsDataModelViewModelOpen, Mode=OneWayToSource}"> <ContextMenu ItemsSource="{Binding DataModelViewModel.Children}" IsOpen="{Binding IsDataModelViewModelOpen, Mode=OneWayToSource}">
<ContextMenu.ItemContainerStyle> <ContextMenu.ItemContainerStyle>

View File

@ -32,12 +32,12 @@
<Grid> <Grid>
<StackPanel Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal"> <StackPanel Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
<TextBlock FontWeight="Light" <TextBlock FontWeight="Light"
Text="{Binding TargetPropertyViewModel.PropertyDescription.Prefix}" Text="{Binding TargetDescription.Prefix}"
Visibility="{Binding TargetPropertyViewModel.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}" /> Visibility="{Binding TargetDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}" />
<ContentControl s:View.Model="{Binding DisplayViewModel}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" /> <ContentControl s:View.Model="{Binding DisplayViewModel}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
<TextBlock FontWeight="Light" <TextBlock FontWeight="Light"
Text="{Binding TargetPropertyViewModel.PropertyDescription.Affix}" Text="{Binding TargetDescription.Affix}"
Visibility="{Binding TargetPropertyViewModel.PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" /> Visibility="{Binding TargetDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" />
</StackPanel> </StackPanel>
<TextBlock FontStyle="Italic" Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}"> <TextBlock FontStyle="Italic" Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">

View File

@ -0,0 +1,20 @@
using System;
using System.Linq;
using Stylet;
namespace Artemis.UI.Extensions
{
public static class BindableCollectionExtensions
{
public static void Sort<T>(this BindableCollection<T> collection, Func<T, object> order)
{
var ordered = collection.OrderBy(order).ToList();
for (var index = 0; index < ordered.Count; index++)
{
var dataBindingConditionViewModel = ordered[index];
if (collection.IndexOf(dataBindingConditionViewModel) != index)
collection.Move(collection.IndexOf(dataBindingConditionViewModel), index);
}
}
}
}

View File

@ -88,9 +88,10 @@ namespace Artemis.UI.Ninject.Factories
public interface IDataBindingsVmFactory public interface IDataBindingsVmFactory
{ {
IDataBindingViewModel DataBindingViewModel(IDataBindingRegistration registration); IDataBindingViewModel DataBindingViewModel(IDataBindingRegistration registration);
DataBindingModifierViewModel<TLayerProperty, TProperty> DataBindingModifierViewModel<TLayerProperty, TProperty>(DataBindingModifier<TLayerProperty, TProperty> modifier);
DirectDataBindingModeViewModel<TLayerProperty, TProperty> DirectDataBindingModeViewModel<TLayerProperty, TProperty>(DirectDataBinding<TLayerProperty, TProperty> directDataBinding); DirectDataBindingModeViewModel<TLayerProperty, TProperty> DirectDataBindingModeViewModel<TLayerProperty, TProperty>(DirectDataBinding<TLayerProperty, TProperty> directDataBinding);
DataBindingModifierViewModel<TLayerProperty, TProperty> DataBindingModifierViewModel<TLayerProperty, TProperty>(DataBindingModifier<TLayerProperty, TProperty> modifier);
ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> ConditionalDataBindingModeViewModel<TLayerProperty, TProperty>(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding); ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> ConditionalDataBindingModeViewModel<TLayerProperty, TProperty>(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding);
DataBindingConditionViewModel<TLayerProperty, TProperty> DataBindingConditionViewModel<TLayerProperty, TProperty>(DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition);
} }
public interface IPropertyVmFactory public interface IPropertyVmFactory

View File

@ -142,6 +142,15 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
if (IsRootGroup && Parent is DisplayConditionsViewModel displayConditionsViewModel) if (IsRootGroup && Parent is DisplayConditionsViewModel displayConditionsViewModel)
displayConditionsViewModel.DisplayStartHint = !Items.Any(); displayConditionsViewModel.DisplayStartHint = !Items.Any();
OnUpdated();
}
public event EventHandler Updated;
protected virtual void OnUpdated()
{
Updated?.Invoke(this, EventArgs.Empty);
} }
} }
} }

View File

@ -157,6 +157,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered; RightSideInputViewModel.ValueUpdated += RightSideOnValueEntered;
} }
RightSideInputViewModel.Value = DataModelConditionPredicate.RightStaticValue;
if (RightSideInputViewModel.TargetType != targetType) if (RightSideInputViewModel.TargetType != targetType)
RightSideInputViewModel.UpdateTargetType(targetType); RightSideInputViewModel.UpdateTargetType(targetType);
} }

View File

@ -4,17 +4,78 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:dd="urn:gong-wpf-dragdrop" xmlns:Converters="clr-namespace:Artemis.UI.Converters"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
<Grid> <UserControl.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16"> <ResourceDictionary>
<materialDesign:PackIcon Kind="Crane" Width="60" Height="60" HorizontalAlignment="Center" /> <ResourceDictionary.MergedDictionaries>
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25"> <ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DataModelConditions.xaml" />
Conditional data bindings not yet implemented <ResourceDictionary>
</TextBlock> <Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center"> <utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
This is where you'd provide values and their conditions.. :> </ResourceDictionary>
</TextBlock> </ResourceDictionary.MergedDictionaries>
</StackPanel> </ResourceDictionary>
</UserControl.Resources>
<Grid Margin="5 10 0 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button Grid.Row="0"
Style="{StaticResource DataModelConditionButtonLeftClickMenu}"
Background="{StaticResource PrimaryHueMidBrush}"
BorderBrush="{StaticResource PrimaryHueMidBrush}"
HorizontalAlignment="Right">
ADD CONDITION
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Add static condition"
ToolTip="A condition that compares with a static input"
Command="{s:Action AddCondition}"
CommandParameter="Static">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FormTextarea" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add dynamic condition"
ToolTip="A condition that compares with a data model property"
Command="{s:Action AddCondition}"
CommandParameter="Dynamic">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Link" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Add list condition"
ToolTip="A condition that evaluates on items in a list"
Command="{s:Action AddCondition}"
CommandParameter="List">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="FormatListBulleted" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Button.ContextMenu>
</Button>
<ListBox Grid.Row="1"
ItemsSource="{Binding ConditionViewModels}"
materialDesign:RippleAssist.IsDisabled="True"
dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultDragAdorner="True"
HorizontalContentAlignment="Stretch"
ScrollViewer.CanContentScroll="False"
Margin="0 5 0 0">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,28 +1,120 @@
using Artemis.Core; using System;
using System.Collections.Specialized;
using System.Linq;
using Artemis.Core;
using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared.Services;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding
{ {
public class ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> : Screen, IDataBindingModeViewModel public class ConditionalDataBindingModeViewModel<TLayerProperty, TProperty> : Screen, IDataBindingModeViewModel
{ {
public ConditionalDataBindingModeViewModel(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding) private readonly IProfileEditorService _profileEditorService;
private readonly IDataBindingsVmFactory _dataBindingsVmFactory;
private bool _updating;
public ConditionalDataBindingModeViewModel(ConditionalDataBinding<TLayerProperty, TProperty> conditionalDataBinding,
IProfileEditorService profileEditorService,
IDataBindingsVmFactory dataBindingsVmFactory)
{ {
_profileEditorService = profileEditorService;
_dataBindingsVmFactory = dataBindingsVmFactory;
ConditionalDataBinding = conditionalDataBinding; ConditionalDataBinding = conditionalDataBinding;
ConditionViewModels = new BindableCollection<DataBindingConditionViewModel<TLayerProperty, TProperty>>();
Initialize();
} }
public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; } public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; }
public BindableCollection<DataBindingConditionViewModel<TLayerProperty, TProperty>> ConditionViewModels { get; }
public void Dispose()
{
}
public void Update() public void Update()
{ {
UpdateConditionViewModels();
} }
public object GetTestValue() public object GetTestValue()
{ {
return null; return ConditionalDataBinding.DataBinding.Converter.GetValue();
} }
public void AddCondition(string type)
{
var condition = ConditionalDataBinding.AddCondition();
// Find the VM of the new condition
var viewModel = ConditionViewModels.First(c => c.DataBindingCondition == condition);
viewModel.ActiveItem.AddCondition(type);
_profileEditorService.UpdateSelectedProfileElement();
}
private void UpdateConditionViewModels()
{
_updating = true;
// Remove old VMs
var toRemove = ConditionViewModels.Where(c => !ConditionalDataBinding.Conditions.Contains(c.DataBindingCondition)).ToList();
foreach (var dataBindingConditionViewModel in toRemove) {
ConditionViewModels.Remove(dataBindingConditionViewModel);
dataBindingConditionViewModel.Dispose();
}
// Add missing VMs
foreach (var condition in ConditionalDataBinding.Conditions)
{
if (ConditionViewModels.All(c => c.DataBindingCondition != condition))
ConditionViewModels.Add(_dataBindingsVmFactory.DataBindingConditionViewModel(condition));
}
// Fix order
ConditionViewModels.Sort(c => c.DataBindingCondition.Order);
_updating = false;
}
private void Initialize()
{
ConditionalDataBinding.ConditionsUpdated += ConditionalDataBindingOnConditionsUpdated;
ConditionViewModels.CollectionChanged += ConditionViewModelsOnCollectionChanged;
UpdateConditionViewModels();
}
private void ConditionViewModelsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_updating || e.Action != NotifyCollectionChangedAction.Add)
return;
for (var index = 0; index < ConditionViewModels.Count; index++)
{
var conditionViewModel = ConditionViewModels[index];
conditionViewModel.DataBindingCondition.Order = index + 1;
}
ConditionalDataBinding.ApplyOrder();
_profileEditorService.UpdateSelectedProfileElement();
}
private void ConditionalDataBindingOnConditionsUpdated(object sender, EventArgs e)
{
UpdateConditionViewModels();
}
#region IDisposable
public void Dispose()
{
ConditionalDataBinding.ConditionsUpdated -= ConditionalDataBindingOnConditionsUpdated;
foreach (var conditionViewModel in ConditionViewModels)
conditionViewModel.Dispose();
ConditionViewModels.Clear();
}
#endregion
} }
} }

View File

@ -0,0 +1,27 @@
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding.DataBindingConditionView"
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:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0"
s:View.Model="{Binding ActiveItem}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsTabStop="False" />
<ContentControl Grid.Row="1"
Margin="26 5 0 0"
s:View.Model="{Binding ValueViewModel}"
VerticalContentAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsTabStop="False" />
</Grid>
</UserControl>

View File

@ -0,0 +1,56 @@
using System;
using System.Linq;
using Artemis.Core;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.Conditions;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Input;
using Artemis.UI.Shared.Services;
using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding
{
public class DataBindingConditionViewModel<TLayerProperty, TProperty> : Conductor<DataModelConditionGroupViewModel>, IDisposable
{
private readonly IProfileEditorService _profileEditorService;
public DataBindingConditionViewModel(DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition,
IProfileEditorService profileEditorService,
IDataModelConditionsVmFactory dataModelConditionsVmFactory,
IDataModelUIService dataModelUIService)
{
_profileEditorService = profileEditorService;
DataBindingCondition = dataBindingCondition;
ActiveItem = dataModelConditionsVmFactory.DataModelConditionGroupViewModel(DataBindingCondition.Condition, false);
ActiveItem.IsRootGroup = true;
ActiveItem.Update();
ActiveItem.Updated += ActiveItemOnUpdated;
ValueViewModel = dataModelUIService.GetStaticInputViewModel(typeof(TProperty));
ValueViewModel.ValueUpdated += ValueViewModelOnValueUpdated;
ValueViewModel.Value = DataBindingCondition.Value;
}
private void ActiveItemOnUpdated(object sender, EventArgs e)
{
if (!ActiveItem.GetChildren().Any())
DataBindingCondition.ConditionalDataBinding.RemoveCondition(DataBindingCondition);
}
private void ValueViewModelOnValueUpdated(object sender, DataModelInputStaticEventArgs e)
{
DataBindingCondition.Value = (TProperty) Convert.ChangeType(e.Value, typeof(TProperty));
_profileEditorService.UpdateSelectedProfileElement();
}
public DataBindingCondition<TLayerProperty, TProperty> DataBindingCondition { get; }
public DataModelStaticViewModel ValueViewModel { get; set; }
public void Dispose()
{
ValueViewModel.Dispose();
}
}
}

View File

@ -4,7 +4,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:dd="urn:gong-wpf-dragdrop"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"> d:DesignHeight="450" d:DesignWidth="800">
@ -16,7 +15,6 @@
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid> <Grid>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="0.75*" /> <ColumnDefinition Width="0.75*" />
@ -136,5 +134,4 @@
</Grid> </Grid>
</materialDesign:Card> </materialDesign:Card>
</Grid> </Grid>
</ScrollViewer>
</UserControl> </UserControl>

View File

@ -3,11 +3,11 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:converters="clr-namespace:Artemis.UI.Converters" xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities" xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBinding"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:DataBindingModifierViewModel}"> d:DataContext="{d:DesignInstance local:DataBindingModifierViewModel}">

View File

@ -64,6 +64,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
public void Delete() public void Delete()
{ {
Modifier.DirectDataBinding.RemoveModifier(Modifier); Modifier.DirectDataBinding.RemoveModifier(Modifier);
_profileEditorService.UpdateSelectedProfileElement();
} }
public void SwapType() public void SwapType()
@ -74,6 +75,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
Modifier.UpdateParameter(null, null); Modifier.UpdateParameter(null, null);
Update(); Update();
_profileEditorService.UpdateSelectedProfileElement();
} }
private void ParameterSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) private void ParameterSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)

View File

@ -33,9 +33,8 @@
Height="22" Height="22"
Command="{s:Action AddModifier}"> Command="{s:Action AddModifier}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<materialDesign:PackIcon Margin="0 -1 4 0" Kind="Plus" />
<TextBlock> <TextBlock>
Add modifier ADD MODIFIER
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Button> </Button>
@ -48,7 +47,6 @@
dd:DragDrop.IsDragSource="True" dd:DragDrop.IsDragSource="True"
dd:DragDrop.IsDropTarget="True" dd:DragDrop.IsDropTarget="True"
dd:DragDrop.UseDefaultDragAdorner="True" dd:DragDrop.UseDefaultDragAdorner="True"
dd:DragDrop.DropHandler="{Binding}"
HorizontalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"
Margin="0 5 0 0"> Margin="0 5 0 0">
<ListBox.ItemTemplate> <ListBox.ItemTemplate>

View File

@ -1,5 +1,8 @@
using System; using System;
using System.Collections.Specialized;
using System.Linq;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Input; using Artemis.UI.Shared.Input;
@ -14,6 +17,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
private readonly IDataModelUIService _dataModelUIService; private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private DataModelDynamicViewModel _targetSelectionViewModel; private DataModelDynamicViewModel _targetSelectionViewModel;
private bool _canAddModifier;
private bool _updating;
public DirectDataBindingModeViewModel(DirectDataBinding<TLayerProperty, TProperty> directDataBinding, public DirectDataBindingModeViewModel(DirectDataBinding<TLayerProperty, TProperty> directDataBinding,
IProfileEditorService profileEditorService, IProfileEditorService profileEditorService,
@ -34,6 +39,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; } public DirectDataBinding<TLayerProperty, TProperty> DirectDataBinding { get; }
public BindableCollection<DataBindingModifierViewModel<TLayerProperty, TProperty>> ModifierViewModels { get; } public BindableCollection<DataBindingModifierViewModel<TLayerProperty, TProperty>> ModifierViewModels { get; }
public bool CanAddModifier
{
get => _canAddModifier;
set => SetAndNotify(ref _canAddModifier, value);
}
public DataModelDynamicViewModel TargetSelectionViewModel public DataModelDynamicViewModel TargetSelectionViewModel
{ {
get => _targetSelectionViewModel; get => _targetSelectionViewModel;
@ -45,6 +56,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DirectDataBinding.SourceDataModel, DirectDataBinding.SourcePropertyPath); TargetSelectionViewModel.PopulateSelectedPropertyViewModel(DirectDataBinding.SourceDataModel, DirectDataBinding.SourcePropertyPath);
TargetSelectionViewModel.FilterTypes = new[] {DirectDataBinding.DataBinding.GetTargetType()}; TargetSelectionViewModel.FilterTypes = new[] {DirectDataBinding.DataBinding.GetTargetType()};
CanAddModifier = DirectDataBinding.SourceDataModel != null;
UpdateModifierViewModels(); UpdateModifierViewModels();
} }
@ -58,10 +70,26 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
DirectDataBinding.ModifiersUpdated += DirectDataBindingOnModifiersUpdated; DirectDataBinding.ModifiersUpdated += DirectDataBindingOnModifiersUpdated;
TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule()); TargetSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected; TargetSelectionViewModel.PropertySelected += TargetSelectionViewModelOnPropertySelected;
ModifierViewModels.CollectionChanged += ModifierViewModelsOnCollectionChanged;
Update(); Update();
} }
private void ModifierViewModelsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (_updating || e.Action != NotifyCollectionChangedAction.Add)
return;
for (var index = 0; index < ModifierViewModels.Count; index++)
{
var dataBindingModifierViewModel = ModifierViewModels[index];
dataBindingModifierViewModel.Modifier.Order = index + 1;
}
DirectDataBinding.ApplyOrder();
_profileEditorService.UpdateSelectedProfileElement();
}
#region Target #region Target
private void TargetSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e) private void TargetSelectionViewModelOnPropertySelected(object sender, DataModelInputDynamicEventArgs e)
@ -82,15 +110,29 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDa
_profileEditorService.UpdateSelectedProfileElement(); _profileEditorService.UpdateSelectedProfileElement();
} }
private void UpdateModifierViewModels() private void UpdateModifierViewModels()
{ {
foreach (var dataBindingModifierViewModel in ModifierViewModels) _updating = true;
dataBindingModifierViewModel.Dispose();
ModifierViewModels.Clear();
foreach (var dataBindingModifier in DirectDataBinding.Modifiers) // Remove old VMs
ModifierViewModels.Add(_dataBindingsVmFactory.DataBindingModifierViewModel(dataBindingModifier)); var toRemove = ModifierViewModels.Where(m => !DirectDataBinding.Modifiers.Contains(m.Modifier)).ToList();
foreach (var modifierViewModel in toRemove)
{
ModifierViewModels.Remove(modifierViewModel);
modifierViewModel.Dispose();
}
// Add missing VMs
foreach (var modifier in DirectDataBinding.Modifiers)
{
if (ModifierViewModels.All(m => m.Modifier != modifier))
ModifierViewModels.Add(_dataBindingsVmFactory.DataBindingModifierViewModel(modifier));
}
// Fix order
ModifierViewModels.Sort(m => m.Modifier.Order);
_updating = false;
} }
private void DirectDataBindingOnModifiersUpdated(object sender, EventArgs e) private void DirectDataBindingOnModifiersUpdated(object sender, EventArgs e)