Data bindings - WIP commit

This commit is contained in:
SpoinkyNL committed 2020-09-06 21:24:35 +02:00
1 parent 7bcac904fc
commit 1dc58fd09a
42 files changed
+902 -356

No files matched your search

@@ -14,9 +14,9 @@ namespace Artemis.UI.Shared
private bool _closed;
private T _inputValue;
protected DataModelInputViewModel(DataModelPropertyAttribute description, T initialValue)
protected DataModelInputViewModel(DataModelPropertyAttribute targetDescription, T initialValue)
{
Description = description;
TargetDescription = targetDescription;
InputValue = initialValue;
}
@@ -26,7 +26,7 @@ namespace Artemis.UI.Shared
set => SetAndNotify(ref _inputValue, value);
}
public DataModelPropertyAttribute Description { get; }
public DataModelPropertyAttribute TargetDescription { get; }
internal override object InternalGuard { get; } = null;
/// <inheritdoc />
@@ -1,60 +0,0 @@
<UserControl x:Class="Artemis.UI.Shared.DataModelSelectionView"
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:shared="clr-namespace:Artemis.UI.Shared"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance shared:DataModelSelectionViewModel}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI.Shared;component/ResourceDictionaries/DisplayConditions.xaml" />
<ResourceDictionary>
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<shared:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
<DataTemplate x:Key="DataModelDataTemplate">
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource DataModelSelectionTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Data.ShowDataModelValues.Value, Source={StaticResource DataContextProxy}}" Value="True">
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource DataModelSelectionTemplateWithValues}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Button Background="{Binding ButtonBrush}"
BorderBrush="{Binding ButtonBrush}"
Style="{StaticResource DisplayConditionButton}"
ToolTip="{Binding SelectedPropertyViewModel.DisplayPropertyPath}"
IsEnabled="{Binding IsEnabled}"
HorizontalAlignment="Left"
Click="PropertyButton_OnClick">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding DataModelViewModel.Children}" IsOpen="{Binding IsDataModelViewModelOpen, Mode=OneWayToSource}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Command" Value="{Binding Data.SelectPropertyCommand, Source={StaticResource DataContextProxy}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
<Grid>
<TextBlock Text="{Binding SelectedPropertyViewModel.PropertyDescription.Name}"
Visibility="{Binding SelectedPropertyViewModel, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock FontStyle="Italic"
Visibility="{Binding SelectedPropertyViewModel, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<Run Text="« "/><Run Text="{Binding Placeholder}"/><Run Text=" »"/>
</TextBlock>
</Grid>
</Button>
</UserControl>
@@ -0,0 +1,69 @@
<UserControl x:Class="Artemis.UI.Shared.Input.DataModelDynamicView"
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:shared="clr-namespace:Artemis.UI.Shared"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:input="clr-namespace:Artemis.UI.Shared.Input"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance input:DataModelDynamicViewModel}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI.Shared;component/ResourceDictionaries/DisplayConditions.xaml" />
<ResourceDictionary>
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
<shared:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
<DataTemplate x:Key="DataModelDataTemplate">
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource DataModelSelectionTemplate}" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Data.ShowDataModelValues.Value, Source={StaticResource DataContextProxy}}" Value="True">
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource DataModelSelectionTemplateWithValues}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Button Background="{Binding ButtonBrush}"
BorderBrush="{Binding ButtonBrush}"
Style="{StaticResource DisplayConditionButton}"
ToolTip="{Binding SelectedPropertyViewModel.DisplayPropertyPath}"
IsEnabled="{Binding IsEnabled}"
HorizontalAlignment="Left"
Click="PropertyButton_OnClick"
Visibility="{Binding ShowFreeInput, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding DataModelViewModel.Children}" IsOpen="{Binding IsDataModelViewModelOpen, Mode=OneWayToSource}">
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Command" Value="{Binding Data.SelectPropertyCommand, Source={StaticResource DataContextProxy}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
<Setter Property="CommandTarget" Value="{Binding}" />
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="HeaderTemplate" Value="{StaticResource DataModelDataTemplate}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Button.ContextMenu>
<Grid>
<TextBlock Text="{Binding SelectedPropertyViewModel.PropertyDescription.Name}"
Visibility="{Binding SelectedPropertyViewModel, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock FontStyle="Italic"
Visibility="{Binding SelectedPropertyViewModel, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<Run Text="« " /><Run Text="{Binding Placeholder}" /><Run Text=" »" />
</TextBlock>
</Grid>
</Button>
</UserControl>
@@ -1,14 +1,14 @@
using System.Windows;
using System.Windows.Controls;
namespace Artemis.UI.Shared
namespace Artemis.UI.Shared.Input
{
/// <summary>
/// Interaction logic for DataModelSelectionView.xaml
/// Interaction logic for DataModelDynamicView.xaml
/// </summary>
public partial class DataModelSelectionView : UserControl
public partial class DataModelDynamicView : UserControl
{
public DataModelSelectionView()
public DataModelDynamicView()
{
InitializeComponent();
}
@@ -11,22 +11,21 @@ using Stylet;
// Remove, annoying while working on it
#pragma warning disable 1591
namespace Artemis.UI.Shared
namespace Artemis.UI.Shared.Input
{
public class DataModelSelectionViewModel : PropertyChangedBase
public class DataModelDynamicViewModel : PropertyChangedBase
{
private readonly IDataModelUIService _dataModelUIService;
private readonly Module _module;
private readonly Timer _updateTimer;
private Brush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188));
private DataModelPropertiesViewModel _dataModelViewModel;
private bool _isDataModelViewModelOpen;
private bool _isEnabled;
private bool _isEnabled = true;
private string _placeholder = "Select a property";
private DataModelVisualizationViewModel _selectedPropertyViewModel;
public DataModelSelectionViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService)
internal DataModelDynamicViewModel(Module module, ISettingsService settingsService, IDataModelUIService dataModelUIService)
{
_module = module;
_dataModelUIService = dataModelUIService;
@@ -38,22 +37,18 @@ namespace Artemis.UI.Shared
Initialize();
}
public string Placeholder
{
get => _placeholder;
set => SetAndNotify(ref _placeholder, value);
}
public Brush ButtonBrush
{
get => _buttonBrush;
set => SetAndNotify(ref _buttonBrush, value);
}
public DelegateCommand SelectPropertyCommand { get; }
public Type[] FilterTypes { get; set; }
public PluginSetting<bool> ShowDataModelValues { get; }
public string Placeholder
{
get => _placeholder;
set => SetAndNotify(ref _placeholder, value);
}
public bool IsEnabled
{
@@ -61,6 +56,10 @@ namespace Artemis.UI.Shared
set => SetAndNotify(ref _isEnabled, value);
}
public Type[] FilterTypes { get; set; }
public DelegateCommand SelectPropertyCommand { get; }
public PluginSetting<bool> ShowDataModelValues { get; }
public DataModelPropertiesViewModel DataModelViewModel
{
get => _dataModelViewModel;
@@ -117,14 +116,15 @@ namespace Artemis.UI.Shared
return;
SelectedPropertyViewModel = selected;
OnPropertySelected(new DataModelPropertySelectedEventArgs(selected));
OnPropertySelected(new DataModelInputDynamicEventArgs(selected));
}
#region Events
public event EventHandler<DataModelPropertySelectedEventArgs> PropertySelected;
public event EventHandler<DataModelInputDynamicEventArgs> PropertySelected;
protected virtual void OnPropertySelected(DataModelPropertySelectedEventArgs e)
protected virtual void OnPropertySelected(DataModelInputDynamicEventArgs e)
{
PropertySelected?.Invoke(this, e);
}
@@ -0,0 +1,56 @@
<UserControl x:Class="Artemis.UI.Shared.Input.DataModelStaticView"
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:input="clr-namespace:Artemis.UI.Shared.Input"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:shared="clr-namespace:Artemis.UI.Shared"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance input:DataModelStaticViewModel}">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI.Shared;component/ResourceDictionaries/DisplayConditions.xaml" />
<ResourceDictionary>
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<materialDesign:Transitioner SelectedIndex="{Binding TransitionIndex}" DefaultTransitionOrigin="0.5, 0.5" Margin="3 -4">
<Button Style="{StaticResource DisplayConditionButton}"
Background="{Binding ButtonBrush}"
BorderBrush="{Binding ButtonBrush}"
Margin="0 4"
Command="{s:Action ActivateInputViewModel}"
HorizontalAlignment="Left">
<Grid>
<StackPanel Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}}" Orientation="Horizontal">
<TextBlock FontWeight="Light"
Text="{Binding TargetPropertyViewModel.PropertyDescription.Prefix}"
Visibility="{Binding TargetPropertyViewModel.PropertyDescription.Prefix, Converter={StaticResource NullToVisibilityConverter}}" />
<TextBlock Text="{Binding Value}" />
<TextBlock FontWeight="Light"
Text="{Binding TargetPropertyViewModel.PropertyDescription.Affix}"
Visibility="{Binding TargetPropertyViewModel.PropertyDescription.Affix, Converter={StaticResource NullToVisibilityConverter}}" />
</StackPanel>
<TextBlock FontStyle="Italic" Visibility="{Binding Value, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
<Run Text="« " /><Run Text="{Binding Placeholder}" /><Run Text=" »" />
</TextBlock>
</Grid>
</Button>
<Border BorderBrush="{Binding ButtonBrush}"
Background="{DynamicResource MaterialDesignPaper}"
CornerRadius="3"
Padding="3"
HorizontalAlignment="Left"
MinWidth="140">
<ContentControl s:View.Model="{Binding InputViewModel}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</Border>
</materialDesign:Transitioner>
</UserControl>
@@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace Artemis.UI.Shared.Input
{
/// <summary>
/// Interaction logic for DataModelStaticView.xaml
/// </summary>
public partial class DataModelStaticView : UserControl
{
public DataModelStaticView()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,116 @@
using System;
using System.Windows.Media;
using Artemis.Core;
using Artemis.Core.DataModelExpansions;
using Artemis.UI.Shared.Services;
using Stylet;
// Remove, annoying while working on it
#pragma warning disable 1591
namespace Artemis.UI.Shared.Input
{
public class DataModelStaticViewModel : PropertyChangedBase
{
private readonly IDataModelUIService _dataModelUIService;
private Brush _buttonBrush = new SolidColorBrush(Color.FromRgb(171, 71, 188));
private DataModelInputViewModel _inputViewModel;
private string _placeholder = "Enter a value";
private DataModelPropertyAttribute _targetDescription;
private Type _targetType;
private int _transitionIndex;
private object _value;
internal DataModelStaticViewModel(Type targetType, IDataModelUIService dataModelUIService)
{
TargetType = targetType;
_dataModelUIService = dataModelUIService;
}
public Brush ButtonBrush
{
get => _buttonBrush;
set => SetAndNotify(ref _buttonBrush, value);
}
public int TransitionIndex
{
get => _transitionIndex;
set => SetAndNotify(ref _transitionIndex, value);
}
public DataModelInputViewModel InputViewModel
{
get => _inputViewModel;
private set => SetAndNotify(ref _inputViewModel, value);
}
public Type TargetType
{
get => _targetType;
set => SetAndNotify(ref _targetType, value);
}
public DataModelPropertyAttribute TargetDescription
{
get => _targetDescription;
set => SetAndNotify(ref _targetDescription, value);
}
public object Value
{
get => _value;
set => SetAndNotify(ref _value, value);
}
public string Placeholder
{
get => _placeholder;
set => SetAndNotify(ref _placeholder, value);
}
public void ActivateInputViewModel()
{
TransitionIndex = 1;
InputViewModel = _dataModelUIService.GetDataModelInputViewModel(
TargetType,
TargetDescription,
Value,
ApplyFreeInput
);
}
public void UpdateTargetType(Type target)
{
TargetType = target ?? throw new ArgumentNullException(nameof(target));
// If the type changed, reset to the default type
if (!target.IsCastableFrom(Value.GetType()))
{
// Force the VM to close if it was open and apply the new value
ApplyFreeInput(target.GetDefault(), true);
}
}
private void ApplyFreeInput(object value, bool submitted)
{
if (submitted)
OnValueUpdated(new DataModelInputStaticEventArgs(value));
TransitionIndex = 0;
InputViewModel = null;
Value = value;
}
#region Events
public event EventHandler<DataModelInputStaticEventArgs> ValueUpdated;
protected virtual void OnValueUpdated(DataModelInputStaticEventArgs e)
{
ValueUpdated?.Invoke(this, e);
}
#endregion
}
}
@@ -2,11 +2,11 @@
namespace Artemis.UI.Shared
{
public class DataModelPropertySelectedEventArgs : EventArgs
public class DataModelInputDynamicEventArgs : EventArgs
{
public DataModelVisualizationViewModel DataModelVisualizationViewModel { get; }
public DataModelPropertySelectedEventArgs(DataModelVisualizationViewModel dataModelVisualizationViewModel)
public DataModelInputDynamicEventArgs(DataModelVisualizationViewModel dataModelVisualizationViewModel)
{
DataModelVisualizationViewModel = dataModelVisualizationViewModel;
}
@@ -0,0 +1,14 @@
using System;
namespace Artemis.UI.Shared
{
public class DataModelInputStaticEventArgs : EventArgs
{
public object Value { get; }
public DataModelInputStaticEventArgs(object value)
{
Value = value;
}
}
}
@@ -5,6 +5,7 @@ using Artemis.Core;
using Artemis.Core.DataModelExpansions;
using Artemis.Core.Modules;
using Artemis.Core.Services;
using Artemis.UI.Shared.Input;
using Ninject;
using Ninject.Parameters;
@@ -179,9 +180,15 @@ namespace Artemis.UI.Shared.Services
}
}
public DataModelSelectionViewModel GetDataModelSelectionViewModel(Module module)
public DataModelDynamicViewModel GetDynamicSelectionViewModel(Module module)
{
return _kernel.Get<DataModelSelectionViewModel>(new ConstructorArgument("module", module));
return _kernel.Get<DataModelDynamicViewModel>(new ConstructorArgument("module", module));
}
public DataModelStaticViewModel GetStaticInputViewModel(Type targetType)
{
if (targetType == null) throw new ArgumentNullException(nameof(targetType));
return _kernel.Get<DataModelStaticViewModel>(new ConstructorArgument("targetType", targetType));
}
private DataModelInputViewModel InstantiateDataModelInputViewModel(DataModelVisualizationRegistration registration, DataModelPropertyAttribute description, object initialValue)
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Artemis.Core;
using Artemis.Core.DataModelExpansions;
using Artemis.Core.Modules;
using Artemis.UI.Shared.Input;
namespace Artemis.UI.Shared.Services
{
@@ -28,6 +29,7 @@ namespace Artemis.UI.Shared.Services
DataModelDisplayViewModel GetDataModelDisplayViewModel(Type propertyType);
DataModelInputViewModel GetDataModelInputViewModel(Type propertyType, DataModelPropertyAttribute description, object initialValue, Action<object, bool> updateCallback);
DataModelSelectionViewModel GetDataModelSelectionViewModel(Module module);
DataModelDynamicViewModel GetDynamicSelectionViewModel(Module module);
DataModelStaticViewModel GetStaticInputViewModel(Type targetType);
}
}