Selaa lähdekoodia

Merge remote-tracking branch 'origin/kenric' into frank

frankvandenbos 1 kuukausi sitten
vanhempi
commit
f35a6c3082

+ 9 - 17
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormViewer.axaml.cs

@@ -19,8 +19,6 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
         AvaloniaProperty.Register<DigitalFormViewer, IDigitalFormInstance>(nameof(Form));
     public static readonly StyledProperty<Entity> EntityProperty =
         AvaloniaProperty.Register<DigitalFormViewer, Entity>(nameof(Entity));
-    public static readonly StyledProperty<DFLayout> LayoutProperty =
-        AvaloniaProperty.Register<DigitalFormViewer, DFLayout>(nameof(Layout));
     public static readonly StyledProperty<bool> ReadOnlyProperty =
         AvaloniaProperty.Register<DigitalFormViewer, bool>(nameof(ReadOnly));
 
@@ -34,14 +32,21 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
         get => GetValue(EntityProperty);
     }
 
+    private DFLayout _layout;
     public DFLayout Layout
     {
-        get => GetValue(LayoutProperty);
+        get => _layout;
+        set
+        {
+            _layout = value;
+            Layout.Renderer = this;
+            Initialise();
+        }
     }
 
     public bool ReadOnly { get; set; }
 
-    private DFLoadStorage RetainedData { get; set; }
+    private DFLoadStorage RetainedData { get; set; } = new();
 
     private bool _changing;
     private bool _isChanged;
@@ -54,19 +59,6 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
 
     private static double RowMinHeight = 35;
 
-    static DigitalFormViewer()
-    {
-        LayoutProperty.Changed.AddClassHandler<DigitalFormViewer>(Layout_Changed);
-    }
-
-    private static void Layout_Changed(DigitalFormViewer viewer, AvaloniaPropertyChangedEventArgs args)
-    {
-        if (viewer.Layout is null) return;
-
-        viewer.Layout.Renderer = viewer;
-        viewer.Initialise();
-    }
-
     public DigitalFormViewer()
     {
         InitializeComponent();

+ 1 - 1
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormsHostView.axaml

@@ -9,7 +9,7 @@
 	<TabControl TabStripPlacement="Bottom">
 		<TabItem Header="Form">
 			<ScrollViewer>
-				<forms:DigitalFormViewer Layout="{Binding Layout}"
+				<forms:DigitalFormViewer Name="Viewer"
 										 Entity="{Binding Parent}"
 										 Form="{Binding Form}"/>
 			</ScrollViewer>

+ 34 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormsHostView.axaml.cs

@@ -1,6 +1,11 @@
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
+using CommunityToolkit.Mvvm.ComponentModel;
+using DynamicData.Binding;
+using ReactiveUI;
+using System;
 
 namespace PRS.Avalonia.DigitalForms;
 
@@ -10,4 +15,33 @@ public partial class DigitalFormsHostView : UserControl
     {
         InitializeComponent();
     }
+
+    protected override void OnDataContextChanged(EventArgs e)
+    {
+        base.OnDataContextChanged(e);
+
+        var model = DataContext as IDigitalFormsHostViewModel;
+        if (model is null) return;
+
+        model.WhenAnyValue(x => x.Layout).Subscribe(value =>
+        {
+            if(value is not null)
+            {
+                Viewer.Layout = value;
+            }
+        });
+        model.SaveValues = Viewer.SaveValues;
+        model.LoadValues = Viewer.LoadValues;
+        model.Validate = () =>
+        {
+            if (Viewer.Validate(out var errors))
+            {
+                return null;
+            }
+            else
+            {
+                return errors;
+            }
+        };
+    }
 }

+ 116 - 4
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormsHostViewModel.cs

@@ -1,11 +1,17 @@
-using Comal.Classes;
+using Avalonia.Data;
+using Avalonia.Media;
+using Avalonia.Threading;
+using Comal.Classes;
 using CommunityToolkit.Mvvm.ComponentModel;
 using InABox.Avalonia;
+using InABox.Avalonia.Components;
 using InABox.Clients;
 using InABox.Core;
+using PRS.Avalonia.Dialogs;
 using PRS.Avalonia.Modules;
 using System;
 using System.Collections.Generic;
+using System.ComponentModel;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
@@ -34,13 +40,19 @@ public class DigitalFormCacheModel<TParent, TParentLink, TForm> : ISerializeBina
     }
 }
 
-public interface IDigitalFormsHostViewModel
+public interface IDigitalFormsHostViewModel : INotifyPropertyChanged
 {
     Entity Parent { get; }
 
     IDigitalFormInstance Form { get; }
 
     DFLayout Layout { get; }
+
+    Action<DFLoadStorage> LoadValues { set; }
+
+    Func<DFSaveStorage> SaveValues { set; }
+
+    Func<List<string>?> Validate { set; }
 }
 
 public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentLink, TForm> : ModuleViewModel, IDigitalFormsHostViewModel
@@ -58,6 +70,9 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
     [ObservableProperty]
     private Guid _instanceID;
 
+    [ObservableProperty]
+    private DigitalForm _digitalForm;
+
     [ObservableProperty]
     private DigitalFormLayout _digitalFormLayout;
 
@@ -85,6 +100,18 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
     [ObservableProperty]
     private DFLayout _layout;
 
+    [ObservableProperty]
+    private DateTime _timeStarted = DateTime.MinValue;
+
+    [ObservableProperty]
+    private Action<DFLoadStorage> _loadValues = null!;
+
+    [ObservableProperty]
+    private Func<DFSaveStorage> _saveValues = null!;
+
+    [ObservableProperty]
+    private Func<List<string>?> _validate = null!;
+
     public event Action? OnSaved;
 
     private string CacheFileName => $"{typeof(TForm)}.{InstanceID}";
@@ -122,6 +149,7 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
     {
         await Model.RefreshAsync(DataAccess.Status == ConnectionStatus.Connected);
 
+        DigitalForm = Model.FirstOrDefault(x => x.ID == FormID)!.Entity;
         Variables = Model.Variables.Where(x => x.FormID == FormID).Select(x => x.Entity).ToArray();
         DigitalFormLayout = Model.Layouts.Where(x => x.FormID == FormID).First().Entity;
 
@@ -145,6 +173,7 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
                         x => x.FormCompleted,
                         x => x.FormCompletedBy.ID,
                         x => x.Created,
+                        x => x.FormStarted,
                         x => x.FormOpen,
                         x => x.BlobData))
                 .ToObjects<TForm>()
@@ -167,18 +196,101 @@ public partial class DigitalFormsHostViewModel<TModel, TShell, TParent, TParentL
         var layout = new DFLayout();
         layout.LoadLayout(DigitalFormLayout.Layout);
         layout.LoadVariables(Variables);
-        Layout = layout;
+
+
+        Dispatcher.UIThread.Invoke(() =>
+        {
+            Layout = layout;
+            LoadValues(DigitalForm.DeserializeFormData(Form) ?? new());
+        });
 
         NewForm = Form.FormData.IsNullOrWhiteSpace();
         ReadOnly = Form.FormCompleted != DateTime.MinValue;
 
+        TimeStarted = DateTime.Now;
+
         ProgressVisible = false;
         return TimeSpan.Zero;
     }
 
     private async Task<bool> SaveForm()
     {
-        throw new NotImplementedException();
+        string[] options;
+        if(DigitalForm.AppliesTo.Equals(nameof(Kanban)) || DigitalForm.AppliesTo.Equals(nameof(Job)))
+        {
+            options = ["Save Progress", "Complete Form", "Complete and Duplicate", "Delete Form"];
+        }
+        else
+        {
+            options = ["Save Progress", "Complete Form", "Delete Form"];
+        }
+        var chosenOption = await OptionSelector.Execute("Select Option", options);
+        if(chosenOption is null)
+        {
+            return true;
+        }
+
+        var completeDuplicate = chosenOption == "Complete and Duplicate";
+        var complete = chosenOption == "Complete Form" || completeDuplicate;
+        var delete = chosenOption == "Delete Form";
+
+        if(complete)
+        {
+            var errors = Dispatcher.UIThread.Invoke(Validate);
+            if(errors is not null)
+            {
+                await MessageDialog.ShowMessage($"Could not save form:\n - {string.Join("\n - ", errors)}\nPlease address these issues and try again.");
+                return true;
+            }
+        }
+
+        ProgressVisible = true;
+        DigitalForm.SerializeFormData(Form, Variables, SaveValues());
+
+        await Task.Run(() =>
+        {
+            if(Form.FormStarted == DateTime.MinValue)
+            {
+                Form.FormStarted = TimeStarted;
+            }
+            Form.FormOpen += (DateTime.Now - TimeStarted);
+
+            if(delete)
+            {
+                Form.FormCancelled = DateTime.Now;
+            }
+            else if (complete)
+            {
+                Form.FormCompleted = DateTime.Now;
+                Form.FormCompletedBy.ID = ClientFactory.UserGuid;
+                Form.FormCompletedBy.UserID = ClientFactory.UserID;
+                if(App.GPS is not null)
+                {
+                    Form.Location.Longitude = App.GPS.Longitude;
+                    Form.Location.Latitude = App.GPS.Latitude;
+                    Form.Location.Timestamp = Form.FormCompleted;
+                }
+            }
+
+            DigitalFormDataModel.Update(Form, Parent);
+        });
+        ProgressVisible = false;
+
+        if (completeDuplicate)
+        {
+            var formid = Form.Form.ID;
+            Form = new TForm();
+            Form.Parent.ID = Parent.ID;
+            Form.Form.ID = formid;
+            Dispatcher.UIThread.Invoke(() => LoadValues(new()));
+        }
+        else
+        {
+            Navigation.Back();
+            OnSaved?.Invoke();
+        }
+
+        return true;
     }
 
     public static void EditForm(TModel model, TShell shell, TParent parent)

+ 122 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFStringFieldControl.cs

@@ -0,0 +1,122 @@
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Layout;
+using Avalonia.Media;
+using CommunityToolkit.Mvvm.Input;
+using DialogHostAvalonia;
+using InABox.Avalonia;
+using InABox.Avalonia.Components;
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRS.Avalonia.DigitalForms;
+
+partial class DFStringFieldControl : DigitalFormFieldControl<DFLayoutStringField, DFLayoutStringFieldProperties, string, string?>
+{
+    private string? text;
+
+    private TextBox? TextBox;
+    private Button? Btn;
+    private TextBlock? TextBlock;
+
+    [NotNull]
+    private string? Text
+    {
+        get => (Field.Properties.PopupEditor ? text : TextBox?.Text) ?? "";
+        set
+        {
+            if (Field.Properties.PopupEditor)
+            {
+                text = value;
+                TextBlock!.Text = value;
+            }
+            else if(TextBox is not null)
+            {
+                TextBox.Text = value;
+            }
+        }
+    }
+
+    public override void SetSerializedValue(string? value)
+    {
+        Text = value;
+    }
+
+    public override string? GetSerializedValue()
+    {
+        return Text;
+    }
+
+    protected override Control Create()
+    {
+        if (Field.Properties.PopupEditor)
+        {
+            var panel = new DockPanel();
+
+            Btn = new Button { Content = "..." };
+            Btn.Command = PopupCommand;
+
+            TextBlock = new TextBlock();
+            TextBlock.Classes.Add("DFStringFieldControl");
+
+            DockPanel.SetDock(Btn, Dock.Left);
+            DockPanel.SetDock(TextBlock, Dock.Right);
+            panel.Children.Add(Btn);
+            panel.Children.Add(TextBlock);
+
+            return panel;
+        }
+        else
+        {
+            TextBox = new TextBox();
+            TextBox.Text = Field.Properties.Default;
+            TextBox.TextWrapping = Field.Properties.TextWrapping ? TextWrapping.Wrap : TextWrapping.NoWrap;
+            TextBox.TextAlignment = TextAlignment.Left;
+            TextBox.VerticalContentAlignment = VerticalAlignment.Center;
+            TextBox.VerticalAlignment = VerticalAlignment.Stretch;
+            TextBox.TextChanged += (sender, e) => ChangeField();
+
+            return TextBox;
+        }
+    }
+
+    public override void SetBackground(IBrush brush, bool defaultColour)
+    {
+        if (Field.Properties.PopupEditor)
+        {
+            Background = brush;
+        }
+        else
+        {
+            TextBox!.Background = brush;
+        }
+    }
+
+    [RelayCommand]
+    private async Task Popup()
+    {
+        var result = await Navigation.Popup<TextEditViewModel, string?>(x =>
+        {
+            x.Text = Text;
+            x.Multiline = true;
+        });
+        if(result is not null)
+        {
+            Text = result;
+            ChangeField();
+        }
+    }
+
+    public override string GetValue() => Text;
+
+    public override void SetValue(string? value) => Text = value;
+
+    protected override bool IsEmpty() => string.IsNullOrWhiteSpace(Text);
+}

+ 42 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFTimeFieldControl.cs

@@ -0,0 +1,42 @@
+using Avalonia.Controls;
+using Avalonia.Media;
+using InABox.Avalonia.Components;
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRS.Avalonia.DigitalForms;
+
+class DFTimeFieldControl : DigitalFormFieldControl<DFLayoutTimeField, DFLayoutTimeFieldProperties, TimeSpan, TimeSpan?>
+{
+    private TimeSelectorButton Time = null!; // late-initialising
+
+    protected override Control Create()
+    {
+        Time = new TimeSelectorButton();
+        var def = Field.Properties.Default;
+        Time.Time = def == default ? DateTime.Now.TimeOfDay : def;
+        Time.TimeChanged += (sender, e) => ChangeField();
+        
+        return Time;
+    }
+
+    public override TimeSpan? GetSerializedValue() => Time.Time;
+
+    public override void SetSerializedValue(TimeSpan? value) => Time.Time = value;
+
+    public override TimeSpan GetValue() => Time.Time ?? TimeSpan.MinValue;
+
+    public override void SetValue(TimeSpan value) => Time.Time = value;
+
+    protected override bool IsEmpty() => Time.Time == null || Time.Time == TimeSpan.MinValue;
+
+    public override void SetBackground(IBrush brush, bool defaultColour)
+    {
+        Time.Background = brush;
+    }
+}

+ 15 - 7
PRS.Avalonia/PRS.Avalonia/Components/FormsList/FormsList.axaml.cs

@@ -6,6 +6,7 @@ using Avalonia.Media;
 using Avalonia.Threading;
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
+using DynamicData.Binding;
 using InABox.Avalonia;
 using InABox.Avalonia.Components;
 using InABox.Avalonia.Converters;
@@ -74,8 +75,8 @@ public delegate bool FormsListSearchEvent(object sender, FormsListSearchEventArg
 
 public partial class FormsList : UserControl
 {
-    public static readonly StyledProperty<bool> SeparateHistoryProperty =
-        AvaloniaProperty.Register<FormsList, bool>(nameof(SeparateHistory), true);
+    // public static readonly StyledProperty<bool> SeparateHistoryProperty =
+    //     AvaloniaProperty.Register<FormsList, bool>("SeparateHistory", true);
     public static readonly StyledProperty<string> AppliesToProperty =
         AvaloniaProperty.Register<FormsList, string>(nameof(AppliesTo), "");
     public static readonly StyledProperty<ICoreRepository?> ModelProperty =
@@ -83,11 +84,8 @@ public partial class FormsList : UserControl
     public static readonly StyledProperty<ICommand?> FormClickedProperty =
         AvaloniaProperty.Register<FormsList, ICommand?>(nameof(FormClicked));
 
-    public bool SeparateHistory
-    {
-        get => GetValue(SeparateHistoryProperty);
-        set => SetValue(SeparateHistoryProperty, value);
-    }
+    public bool SeparateHistory { get; set; } = true;
+
     public string AppliesTo
     {
         get => GetValue(AppliesToProperty);
@@ -120,6 +118,16 @@ public partial class FormsList : UserControl
         InitializeComponent();
     }
 
+    // static FormsList()
+    // {
+    //     SeparateHistoryProperty.Changed.AddClassHandler<FormsList>(SeparateHistory_Changed);
+    // }
+
+    // private static void SeparateHistory_Changed(FormsList list, AvaloniaPropertyChangedEventArgs args)
+    // {
+    //     list._separateHistory = list.GetValue(SeparateHistoryProperty);
+    // }
+
     private bool FilterShell(IShell shell)
     {
         if (shell is not IDigitalFormInstanceShell formShell) return false;

+ 61 - 0
PRS.Avalonia/PRS.Avalonia/Dialogs/PopupPositioner.cs

@@ -0,0 +1,61 @@
+using Avalonia;
+using Avalonia.Layout;
+using DialogHostAvalonia.Positioners;
+using InABox.Avalonia;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRS.Avalonia;
+
+public class PopupPositioner : AvaloniaObject, IDialogPopupPositioner, IDialogPopupPositionerConstrainable
+{
+    public static readonly StyledProperty<Thickness> MarginProperty
+        = Layoutable.MarginProperty.AddOwner<AlignmentDialogPopupPositioner>();
+
+    public static readonly StyledProperty<object?> ContentProperty
+        = AvaloniaProperty.Register<PopupPositioner, object?>(nameof(Content));
+
+    public Thickness Margin
+    {
+        get => GetValue(MarginProperty);
+        set => SetValue(MarginProperty, value);
+    }
+    public object? Content
+    {
+        get => GetValue(ContentProperty);
+        set => SetValue(ContentProperty, value);
+    }
+
+    private HorizontalAlignment GetHorizontalAlignment()
+    {
+        return (Content as IAlignedPopup)?.HorizontalAlignment ?? HorizontalAlignment.Center;
+    }
+    private VerticalAlignment GetVerticalAlignment()
+    {
+        return (Content as IAlignedPopup)?.VerticalAlignment ?? VerticalAlignment.Center;
+    }
+
+    public Rect Update(Size anchorRectangle, Size size) {
+        var margin = GetValue(MarginProperty);
+
+        var availableSpaceRect = new Rect(anchorRectangle);
+        var constrainRect = availableSpaceRect.Deflate(margin);
+        var rect = new Rect(size);
+
+        var hAlign = GetHorizontalAlignment();
+        var vAlign = GetVerticalAlignment();
+
+        if (hAlign == HorizontalAlignment.Stretch) rect = rect.WithWidth(0);
+        if (vAlign == VerticalAlignment.Stretch) rect = rect.WithHeight(0);
+        var aligned = rect.Align(constrainRect, hAlign, vAlign);
+        return new Rect(margin.Left + aligned.Left, margin.Top + aligned.Top, aligned.Width, aligned.Height);
+    }
+
+    public Size Constrain(Size availableSize)
+    {
+        return availableSize.Deflate(Margin);
+    }
+}

+ 3 - 3
PRS.Avalonia/PRS.Avalonia/MainView.axaml

@@ -11,10 +11,10 @@
              x:Class="PRS.Avalonia.Modules.MainView"
              x:DataType="avalonia:MainViewModel">
 
-	<dialogHostAvalonia:DialogHost CloseOnClickAway="True" DialogMargin="10">
+	<dialogHostAvalonia:DialogHost Name="DialogHostElement" CloseOnClickAway="True" DialogMargin="10">
 		<dialogHostAvalonia:DialogHost.PopupPositioner>
-			<positioners:AlignmentDialogPopupPositioner HorizontalAlignment="Center" VerticalAlignment="Center"
-														Margin="20"/>
+			<avalonia:PopupPositioner Margin="20"
+									  Content="{Binding DialogContent,ElementName=DialogHostElement}"/>
 		</dialogHostAvalonia:DialogHost.PopupPositioner>
 		<Grid Background="{StaticResource PrsSurfaceBackground}">
 			<Grid.RowDefinitions>

+ 10 - 1
PRS.Avalonia/PRS.Avalonia/Modules/Site/SiteItps/SiteITPFormsView.axaml.cs

@@ -2,19 +2,28 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 using PRS.Avalonia.Components;
+using System;
 
 namespace PRS.Avalonia.Modules;
 
 public partial class SiteITPFormsView : UserControl
 {
+    private SiteITPFormsViewModel Model = null!;
+
     public SiteITPFormsView()
     {
         InitializeComponent();
     }
 
+    protected override void OnDataContextChanged(EventArgs e)
+    {
+        base.OnDataContextChanged(e);
+        Model = (DataContext as SiteITPFormsViewModel)!;
+    }
+
     private bool FormsList_Search(object sender, FormsListSearchEventArgs args)
     {
         if (args.Shell is not JobITPFormShell shell) return false;
-        return (DataContext as SiteITPFormsViewModel)?.Search(shell) ?? false;
+        return Model.Search(shell);
     }
 }

+ 1 - 1
PRS.Avalonia/PRS.Avalonia/Settings/SettingsViewModel.cs

@@ -158,7 +158,7 @@ public partial class SettingsViewModel : ViewModelBase
         return Task.FromResult(true);
     }
 
-    private Task<bool>  ImportProfiles()
+    private Task<bool> ImportProfiles()
     {
         return Task.FromResult(true);
     }

+ 15 - 0
PRS.Avalonia/PRS.Avalonia/Theme/FormControlStyles.axaml

@@ -11,6 +11,12 @@
         <Setter Property="Foreground" Value="{DynamicResource PrsButtonForeground}" />
         <Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}" />
 	</Style>
+	<Style Selector=":is(forms|DigitalFormControl).DFFieldControl components|TimeSelectorButton">
+        <Setter Property="BorderBrush" Value="{DynamicResource PrsButtonBorder}" />
+        <Setter Property="BorderThickness" Value="{DynamicResource PrsBorderThickness}"/>
+        <Setter Property="Foreground" Value="{DynamicResource PrsButtonForeground}" />
+        <Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}" />
+	</Style>
 	
 	<Style Selector=":is(forms|DigitalFormControl).DFFieldControl forms|RadioOptionControl">
         <Setter Property="BorderBrush" Value="{DynamicResource PrsButtonBorder}" />
@@ -18,4 +24,13 @@
         <Setter Property="Foreground" Value="{DynamicResource PrsButtonForeground}" />
 		<Setter Property="CornerRadius" Value="{DynamicResource PrsCornerRadius}"/>
 	</Style>
+	
+	<Style Selector=":is(forms|DigitalFormControl).DFFieldControl TextBlock.DFStringFieldControl">
+        <Setter Property="Foreground" Value="{DynamicResource PrsButtonForeground}" />
+		<Setter Property="VerticalAlignment" Value="Center"/>
+		<Setter Property="TextWrapping" Value="NoWrap"/>
+		<Setter Property="TextTrimming" Value="CharacterEllipsis"/>
+		<Setter Property="MaxLines" Value="1"/>
+		<Setter Property="Margin" Value="5,0"/>
+	</Style>
 </Styles>