Databindings - Added conditional databindings

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

No files matched your search

@@ -4,17 +4,78 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
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"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16">
<materialDesign:PackIcon Kind="Crane" Width="60" Height="60" HorizontalAlignment="Center" />
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25">
Conditional data bindings not yet implemented
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center">
This is where you'd provide values and their conditions.. :>
</TextBlock>
</StackPanel>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DataModelConditions.xaml" />
<ResourceDictionary>
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</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>
</UserControl>
</UserControl>
@@ -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;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.ConditionalDataBinding
{
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;
ConditionViewModels = new BindableCollection<DataBindingConditionViewModel<TLayerProperty, TProperty>>();
Initialize();
}
public ConditionalDataBinding<TLayerProperty, TProperty> ConditionalDataBinding { get; }
public void Dispose()
{
}
public BindableCollection<DataBindingConditionViewModel<TLayerProperty, TProperty>> ConditionViewModels { get; }
public void Update()
{
UpdateConditionViewModels();
}
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
}
}
@@ -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>
@@ -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();
}
}
}