Browse Source

小炒

样式分支
NXX 1 year ago
parent
commit
a05e10a95d
44 changed files with 2769 additions and 778 deletions
  1. +7
    -7
      BPASmart.RecipeManagement/App.xaml
  2. +1
    -0
      BPASmart.RecipeManagement/BPASmart.RecipeManagement.csproj
  3. +1
    -2
      BPASmart.RecipeManagement/View/RecipesConfigure.xaml
  4. +5
    -2
      BPASmart.RecipeManagement/ViewModel/RecipeManagerViewModel.cs
  5. +12
    -4
      BPASmartClient.MilkWithTea/App.xaml
  6. +19
    -8
      BPASmartClient.MilkWithTea/App.xaml.cs
  7. +6
    -1
      BPASmartClient.MilkWithTea/BPASmartClient.MilkWithTea.csproj
  8. +30
    -0
      BPASmartClient.MilkWithTea/Control/ContextMenuToggleButton.cs
  9. +225
    -0
      BPASmartClient.MilkWithTea/Control/ScrollViewer.cs
  10. +111
    -0
      BPASmartClient.MilkWithTea/Control/ScrollViewerAttach.cs
  11. +426
    -0
      BPASmartClient.MilkWithTea/Control/TabControl.cs
  12. +509
    -0
      BPASmartClient.MilkWithTea/Control/TabItem.cs
  13. +200
    -0
      BPASmartClient.MilkWithTea/Control/TabPanel.cs
  14. +12
    -0
      BPASmartClient.MilkWithTea/Data/CancelRoutedEventArgs.cs
  15. +69
    -0
      BPASmartClient.MilkWithTea/Data/ValueBoxes.cs
  16. +5
    -36
      BPASmartClient.MilkWithTea/GLobal.cs
  17. +49
    -2
      BPASmartClient.MilkWithTea/MainWindow.xaml.cs
  18. +13
    -0
      BPASmartClient.MilkWithTea/Model/JsonDeviceConfig.cs
  19. +23
    -0
      BPASmartClient.MilkWithTea/Model/JsonLocalRecipes.cs
  20. +93
    -154
      BPASmartClient.MilkWithTea/View/LocalConfigureView.xaml
  21. +8
    -1
      BPASmartClient.MilkWithTea/View/LocalConfigureView.xaml.cs
  22. +4
    -4
      BPASmartClient.MilkWithTea/View/MainControlView.xaml
  23. +2
    -3
      BPASmartClient.MilkWithTea/View/MainControlView.xaml.cs
  24. +23
    -14
      BPASmartClient.MilkWithTea/View/ParameterSetting.xaml
  25. +135
    -0
      BPASmartClient.MilkWithTea/View/RecipeConfige.xaml
  26. +174
    -0
      BPASmartClient.MilkWithTea/View/RecipeConfige.xaml.cs
  27. +30
    -169
      BPASmartClient.MilkWithTea/ViewModel/LocalConfigureViewModel.cs
  28. +37
    -28
      BPASmartClient.MilkWithTea/ViewModel/MainControlViewModel.cs
  29. +16
    -17
      BPASmartClient.MilkWithTea/ViewModel/MainWindowVeiwModel.cs
  30. +105
    -86
      BPASmartClient.MilkWithTea/ViewModel/PatrameterSettiongViewModel.cs
  31. +75
    -0
      BPASmartClient.MilkWithTea/ViewModel/RecipeConfigeViewModel.cs
  32. +4
    -0
      BPASmartClient.Model/BPASmartClient.Model.csproj
  33. +78
    -165
      BPASmartClient.MorkF/Control_MorkF.cs
  34. +38
    -0
      BPASmartClient.MorkF/GVL_MorkF.cs
  35. +38
    -18
      BPASmartClient.MorkF/View/DebugView.xaml
  36. +83
    -42
      BPASmartClient.MorkF/ViewModel/DebugViewModel.cs
  37. +6
    -1
      BPASmartClient.MorkMOC/BPASmartClient.MorkMOC.csproj
  38. +23
    -4
      BPASmartClient.MorkMOC/Control_MorkMOC.cs
  39. +55
    -0
      BPASmartClient.MorkMOC/Model/LocalMaterail.cs
  40. +3
    -0
      BPASmartClient.MorkMOC/OrderLocInfo.cs
  41. +2
    -0
      BPASmartClient.MorkS/Control_Morks.cs
  42. +1
    -0
      BPASmartClient.MorkS/GVL_MORKS.cs
  43. +4
    -0
      BPASmartClient.MorkTM/Model/LocalTeaWithMilkConfig.cs
  44. +9
    -10
      BPASmartClient/App.config

+ 7
- 7
BPASmart.RecipeManagement/App.xaml View File

@@ -87,7 +87,7 @@
</ControlTemplate>


<Style TargetType="{x:Type ComboBox}">
<Style TargetType="{x:Type ComboBox}">
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Background" Value=" #041039"/>
<Setter Property="BorderBrush" Value="#FF2AB2E7"/>
@@ -101,13 +101,12 @@
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Grid Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >
<Border x:Name="_borderbg" Background=" #041039" BorderBrush="#FF2AB2E7" BorderThickness="0"/>
<TextBlock
<ContentPresenter
x:Name="_txt"
Margin="5,0,3,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="#FF2AB2E7"
Text="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" />
/>

<Border
x:Name="_border"
@@ -123,7 +122,7 @@
<Setter TargetName="_borderbg" Property="Background" Value="#37405E" />
<Setter TargetName="_borderbg" Property="BorderBrush" Value="white" />
<Setter TargetName="_borderbg" Property="BorderThickness" Value="1" />
<Setter TargetName="_txt" Property="Foreground" Value="white" />
<!--<Setter TargetName="_txt" Property="Foreground" Value="white" />-->
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
@@ -132,7 +131,7 @@
<Setter TargetName="_borderbg" Property="Background" Value="#022352" />
<Setter TargetName="_borderbg" Property="BorderBrush" Value=" #00BFFF" />
<Setter TargetName="_borderbg" Property="BorderThickness" Value="1" />
<Setter TargetName="_txt" Property="Foreground" Value="white" />
<!--<Setter TargetName="_txt" Property="Foreground" Value="white" />-->
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
@@ -221,7 +220,8 @@
<StackPanel
Background="{TemplateBinding Background}"
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Contained"/>
KeyboardNavigation.DirectionalNavigation="Contained">
</StackPanel>
</ScrollViewer>
</Grid>
</Popup>


+ 1
- 0
BPASmart.RecipeManagement/BPASmart.RecipeManagement.csproj View File

@@ -49,6 +49,7 @@

<ItemGroup>
<ProjectReference Include="..\BPASmart.Model\BPASmart.Model.csproj" />
<ProjectReference Include="..\BPASmartClient.CustomResource\BPASmartClient.CustomResource.csproj" />
<ProjectReference Include="..\BPASmartClient.Model\BPASmartClient.Model.csproj" />
</ItemGroup>



+ 1
- 2
BPASmart.RecipeManagement/View/RecipesConfigure.xaml View File

@@ -66,7 +66,7 @@
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>

<ComboBox
<ComboBox
Name="cb"
Grid.Column="0"
Margin="3,1"
@@ -77,7 +77,6 @@
FontFamily="楷体"
FontSize="20"
IsEditable="False"
SelectedValuePath="Key" DisplayMemberPath="Value"
ItemsSource="{Binding DataContext.materialsName, RelativeSource={RelativeSource AncestorType=ItemsControl, Mode=FindAncestor}}"
SelectedValue="{Binding ID}"


+ 5
- 2
BPASmart.RecipeManagement/ViewModel/RecipeManagerViewModel.cs View File

@@ -1,5 +1,7 @@
using BPASmart.Model;
using BPASmart.RecipeManagement.View;
using BPASmartClient.CustomResource.UserControls;
using BPASmartClient.CustomResource.UserControls.MessageShow;
using BPASmartClient.Helper;
using BPASmartClient.RecipeManagement.View;
using Microsoft.Toolkit.Mvvm.ComponentModel;
@@ -10,6 +12,7 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;

namespace BPASmart.RecipeManagement.ViewModel
{
@@ -81,8 +84,8 @@ namespace BPASmart.RecipeManagement.ViewModel
var res = Json<LocalRecipes>.Data.locaRecipes.FirstOrDefault(p => p.ID == id);
if (res != null)
{
//下发配方
//下发配方
NoticeDemoViewModel.OpenMsg(EnumPromptType.Success, Application.Current.MainWindow, "提示", $"配方下发成功!");
}
}
}


+ 12
- 4
BPASmartClient.MilkWithTea/App.xaml View File

@@ -424,7 +424,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Back" Background="Transparent" BorderThickness="0,0,0,0" BorderBrush="#81D779" >
<Border Name="Back" Background="Transparent" BorderThickness="0,0,0,0" BorderBrush="#81D779" Height="{TemplateBinding Height}" >
<ContentPresenter VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0"></ContentPresenter>
</Border>
<ControlTemplate.Triggers>
@@ -444,13 +444,13 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border BorderThickness="1" BorderBrush="#CDC9C9 " CornerRadius="3" Width="{TemplateBinding Width}" Height="30" Background="{TemplateBinding Background}" >
<Grid >
<Border BorderThickness="1" BorderBrush="#CDC9C9 " CornerRadius="3" Height="{TemplateBinding Height}" Width="{TemplateBinding Width}" Background="{TemplateBinding Background}" >
<Grid Height="{TemplateBinding Height}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" x:Name="grid">
<Grid Grid.Column="0" x:Name="grid" >
<ToggleButton
Width="{Binding ElementName=grid,Path=ActualWidth}"
Height="{Binding ElementName=grid, Path=ActualHeight}"
@@ -672,5 +672,13 @@
</DoubleAnimationUsingKeyFrames>
</Storyboard>

<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="DarkSlateGray"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="18"/>
</Style>

</Application.Resources>
</Application>

+ 19
- 8
BPASmartClient.MilkWithTea/App.xaml.cs View File

@@ -1,11 +1,22 @@
using BPASmartClient.Helper;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
global using BPA.Message;
global using BPA.Message.Enum;
global using BPASmartClient.Device;
global using BPASmartClient.EventBus;
global using BPASmartClient.Helper;
global using BPASmartClient.MilkWithTea.Model;
global using BPASmartClient.Model;
global using BPASmartClient.MorkMOC;
global using System;
global using System.Collections.Generic;
global using System.Collections.ObjectModel;
global using System.Linq;
global using System.Text;
global using System.Threading.Tasks;
global using System.Windows;
global using System.Configuration;
global using System.Data;



namespace BPASmartClient.MilkWithTea
{


+ 6
- 1
BPASmartClient.MilkWithTea/BPASmartClient.MilkWithTea.csproj View File

@@ -23,14 +23,19 @@
</EmbeddedResource>
</ItemGroup>

<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BPASmartClient.Business\BPASmartClient.Business.csproj" />
<ProjectReference Include="..\BPASmartClient.CustomResource\BPASmartClient.CustomResource.csproj" />
<ProjectReference Include="..\BPASmartClient.EventBus\BPASmartClient.EventBus.csproj" />
<ProjectReference Include="..\BPASmartClient.Helper\BPASmartClient.Helper.csproj" />
<ProjectReference Include="..\BPASmartClient.IoT\BPASmartClient.IoT.csproj" />
<ProjectReference Include="..\BPASmartClient.Model\BPASmartClient.Model.csproj" />
<ProjectReference Include="..\BPASmartClient.MorkMOC\BPASmartClient.MorkMOC.csproj" />
<ProjectReference Include="..\BPASmartClient.MORKSM.BK.PLC\BPASmartClient.PLC.csproj" />
<ProjectReference Include="..\BPASmartClient.MorkTM\BPASmartClient.MorkTM.csproj" />
<ProjectReference Include="..\BPASmartClient.ViewModel\BPASmartClient.ViewModel.csproj" />
</ItemGroup>



+ 30
- 0
BPASmartClient.MilkWithTea/Control/ContextMenuToggleButton.cs View File

@@ -0,0 +1,30 @@
using System.Windows.Controls;
using System.Windows.Controls.Primitives;


namespace BPASmartClient.MilkWithTea.Control;

/// <summary>
/// 带上下文菜单的切换按钮
/// </summary>
public class ContextMenuToggleButton : ToggleButton
{
public ContextMenu Menu { get; set; }

protected override void OnClick()
{
base.OnClick();
if (Menu != null)
{
if (IsChecked == true)
{
Menu.PlacementTarget = this;
Menu.IsOpen = true;
}
else
{
Menu.IsOpen = false;
}
}
}
}

+ 225
- 0
BPASmartClient.MilkWithTea/Control/ScrollViewer.cs View File

@@ -0,0 +1,225 @@
using BPASmartClient.MilkWithTea.Data;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace BPASmartClient.MilkWithTea.Control;

public class ScrollViewer : System.Windows.Controls.ScrollViewer
{
private double _totalVerticalOffset;

private double _totalHorizontalOffset;

private bool _isRunning;

/// <summary>
/// 是否响应鼠标滚轮操作
/// </summary>
public static readonly DependencyProperty CanMouseWheelProperty = DependencyProperty.Register(
"CanMouseWheel", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.TrueBox));

/// <summary>
/// 是否响应鼠标滚轮操作
/// </summary>
public bool CanMouseWheel
{
get => (bool) GetValue(CanMouseWheelProperty);
set => SetValue(CanMouseWheelProperty, ValueBoxes.BooleanBox(value));
}

protected override void OnMouseWheel(MouseWheelEventArgs e)
{
if (!CanMouseWheel) return;

if (!IsInertiaEnabled)
{
if (ScrollViewerAttach.GetOrientation(this) == Orientation.Vertical)
{
base.OnMouseWheel(e);
}
else
{
_totalHorizontalOffset = HorizontalOffset;
CurrentHorizontalOffset = HorizontalOffset;
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
CurrentHorizontalOffset = _totalHorizontalOffset;
}
return;
}
e.Handled = true;

if (ScrollViewerAttach.GetOrientation(this) == Orientation.Vertical)
{
if (!_isRunning)
{
_totalVerticalOffset = VerticalOffset;
CurrentVerticalOffset = VerticalOffset;
}
_totalVerticalOffset = Math.Min(Math.Max(0, _totalVerticalOffset - e.Delta), ScrollableHeight);
ScrollToVerticalOffsetWithAnimation(_totalVerticalOffset);
}
else
{
if (!_isRunning)
{
_totalHorizontalOffset = HorizontalOffset;
CurrentHorizontalOffset = HorizontalOffset;
}
_totalHorizontalOffset = Math.Min(Math.Max(0, _totalHorizontalOffset - e.Delta), ScrollableWidth);
ScrollToHorizontalOffsetWithAnimation(_totalHorizontalOffset);
}
}

internal void ScrollToTopInternal(double milliseconds = 500)
{
if (!_isRunning)
{
_totalVerticalOffset = VerticalOffset;
CurrentVerticalOffset = VerticalOffset;
}
ScrollToVerticalOffsetWithAnimation(0, milliseconds);
}

public void ScrollToVerticalOffsetWithAnimation(double offset, double milliseconds = 500)
{
var animation = CreateAnimation(offset, milliseconds);
animation.EasingFunction = new CubicEase
{
EasingMode = EasingMode.EaseOut
};
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s, e1) =>
{
CurrentVerticalOffset = offset;
_isRunning = false;
};
_isRunning = true;

BeginAnimation(CurrentVerticalOffsetProperty, animation, HandoffBehavior.Compose);
}

public void ScrollToHorizontalOffsetWithAnimation(double offset, double milliseconds = 500)
{
var animation = CreateAnimation(offset, milliseconds);
animation.EasingFunction = new CubicEase
{
EasingMode = EasingMode.EaseOut
};
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s, e1) =>
{
CurrentHorizontalOffset = offset;
_isRunning = false;
};
_isRunning = true;

BeginAnimation(CurrentHorizontalOffsetProperty, animation, HandoffBehavior.Compose);
}

protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) =>
IsPenetrating ? null : base.HitTestCore(hitTestParameters);

/// <summary>
/// 是否支持惯性
/// </summary>
public static readonly DependencyProperty IsInertiaEnabledProperty = DependencyProperty.RegisterAttached(
"IsInertiaEnabled", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));

public static void SetIsInertiaEnabled(DependencyObject element, bool value) => element.SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));

public static bool GetIsInertiaEnabled(DependencyObject element) => (bool) element.GetValue(IsInertiaEnabledProperty);

/// <summary>
/// 是否支持惯性
/// </summary>
public bool IsInertiaEnabled
{
get => (bool) GetValue(IsInertiaEnabledProperty);
set => SetValue(IsInertiaEnabledProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 控件是否可以穿透点击
/// </summary>
public static readonly DependencyProperty IsPenetratingProperty = DependencyProperty.RegisterAttached(
"IsPenetrating", typeof(bool), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 控件是否可以穿透点击
/// </summary>
public bool IsPenetrating
{
get => (bool) GetValue(IsPenetratingProperty);
set => SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));
}

public static void SetIsPenetrating(DependencyObject element, bool value) => element.SetValue(IsPenetratingProperty, ValueBoxes.BooleanBox(value));

public static bool GetIsPenetrating(DependencyObject element) => (bool) element.GetValue(IsPenetratingProperty);

/// <summary>
/// 当前垂直滚动偏移
/// </summary>
internal static readonly DependencyProperty CurrentVerticalOffsetProperty = DependencyProperty.Register(
"CurrentVerticalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentVerticalOffsetChanged));

private static void OnCurrentVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer ctl && e.NewValue is double v)
{
ctl.ScrollToVerticalOffset(v);
}
}

/// <summary>
/// 当前垂直滚动偏移
/// </summary>
internal double CurrentVerticalOffset
{
// ReSharper disable once UnusedMember.Local
get => (double) GetValue(CurrentVerticalOffsetProperty);
set => SetValue(CurrentVerticalOffsetProperty, value);
}

/// <summary>
/// 当前水平滚动偏移
/// </summary>
internal static readonly DependencyProperty CurrentHorizontalOffsetProperty = DependencyProperty.Register(
"CurrentHorizontalOffset", typeof(double), typeof(ScrollViewer), new PropertyMetadata(ValueBoxes.Double0Box, OnCurrentHorizontalOffsetChanged));

private static void OnCurrentHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer ctl && e.NewValue is double v)
{
ctl.ScrollToHorizontalOffset(v);
}
}

/// <summary>
/// 当前水平滚动偏移
/// </summary>
internal double CurrentHorizontalOffset
{
get => (double) GetValue(CurrentHorizontalOffsetProperty);
set => SetValue(CurrentHorizontalOffsetProperty, value);
}


/// <summary>
/// 创建一个Double动画
/// </summary>
/// <param name="toValue"></param>
/// <param name="milliseconds"></param>
/// <returns></returns>
public DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
{
return new(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
{
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
};
}
}

+ 111
- 0
BPASmartClient.MilkWithTea/Control/ScrollViewerAttach.cs View File

@@ -0,0 +1,111 @@
using BPASmartClient.MilkWithTea.Data;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace BPASmartClient.MilkWithTea.Control;

public class ScrollViewerAttach
{
public static readonly DependencyProperty AutoHideProperty = DependencyProperty.RegisterAttached(
"AutoHide", typeof(bool), typeof(ScrollViewerAttach), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));

public static void SetAutoHide(DependencyObject element, bool value)
=> element.SetValue(AutoHideProperty, ValueBoxes.BooleanBox(value));

public static bool GetAutoHide(DependencyObject element)
=> (bool) element.GetValue(AutoHideProperty);

public static readonly DependencyProperty OrientationProperty = DependencyProperty.RegisterAttached(
"Orientation", typeof(Orientation), typeof(ScrollViewerAttach), new FrameworkPropertyMetadata(ValueBoxes.VerticalBox, FrameworkPropertyMetadataOptions.Inherits, OnOrientationChanged));

private static void OnOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ScrollViewer)
{
return;
}

if (d is System.Windows.Controls.ScrollViewer scrollViewer)
{
if ((Orientation) e.NewValue == Orientation.Horizontal)
{
scrollViewer.PreviewMouseWheel += ScrollViewerPreviewMouseWheel;
}
else
{
scrollViewer.PreviewMouseWheel -= ScrollViewerPreviewMouseWheel;
}
}

void ScrollViewerPreviewMouseWheel(object sender, MouseWheelEventArgs args)
{
var scrollViewerNative = (System.Windows.Controls.ScrollViewer) sender;
scrollViewerNative.ScrollToHorizontalOffset(Math.Min(Math.Max(0, scrollViewerNative.HorizontalOffset - args.Delta), scrollViewerNative.ScrollableWidth));

args.Handled = true;
}
}

public static void SetOrientation(DependencyObject element, Orientation value)
=> element.SetValue(OrientationProperty, ValueBoxes.OrientationBox(value));

public static Orientation GetOrientation(DependencyObject element)
=> (Orientation) element.GetValue(OrientationProperty);

public static readonly DependencyProperty IsDisabledProperty = DependencyProperty.RegisterAttached(
"IsDisabled", typeof(bool), typeof(ScrollViewerAttach), new PropertyMetadata(ValueBoxes.FalseBox, OnIsDisabledChanged));

private static void OnIsDisabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UIElement element)
{
if ((bool) e.NewValue)
{
element.PreviewMouseWheel += ScrollViewerPreviewMouseWheel;
}
else
{
element.PreviewMouseWheel -= ScrollViewerPreviewMouseWheel;
}
}

void ScrollViewerPreviewMouseWheel(object sender, MouseWheelEventArgs args)
{
if (args.Handled)
{
return;
}

args.Handled = true;

if (GetParent<System.Windows.Controls.ScrollViewer>((UIElement) sender) is { } scrollViewer)
{
scrollViewer.RaiseEvent(new MouseWheelEventArgs(args.MouseDevice, args.Timestamp, args.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent,
Source = sender
});
}
}

static T GetParent<T>(DependencyObject d) where T : DependencyObject =>
d switch
{
null => default,
T t => t,
Window _ => null,
_ => GetParent<T>(VisualTreeHelper.GetParent(d))
};
}

public static void SetIsDisabled(DependencyObject element, bool value)
=> element.SetValue(IsDisabledProperty, ValueBoxes.BooleanBox(value));

public static bool GetIsDisabled(DependencyObject element)
=> (bool) element.GetValue(IsDisabledProperty);

}

+ 426
- 0
BPASmartClient.MilkWithTea/Control/TabControl.cs View File

@@ -0,0 +1,426 @@
using BPASmartClient.MilkWithTea.Data;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;

namespace BPASmartClient.MilkWithTea.Control;

[TemplatePart(Name = HeaderPanelKey, Type = typeof(TabPanel))]
[TemplatePart(Name = OverflowScrollviewer, Type = typeof(ScrollViewer))]
[TemplatePart(Name = ScrollButtonLeft, Type = typeof(ButtonBase))]
[TemplatePart(Name = ScrollButtonRight, Type = typeof(ButtonBase))]
[TemplatePart(Name = HeaderBorder, Type = typeof(Border))]
public class TabControl : System.Windows.Controls.TabControl
{
private const string OverflowButtonKey = "PART_OverflowButton";

private const string HeaderPanelKey = "PART_HeaderPanel";

private const string OverflowScrollviewer = "PART_OverflowScrollviewer";

private const string ScrollButtonLeft = "PART_ScrollButtonLeft";

private const string ScrollButtonRight = "PART_ScrollButtonRight";

private const string HeaderBorder = "PART_HeaderBorder";

private ContextMenuToggleButton _buttonOverflow;

internal TabPanel HeaderPanel { get; private set; }

private ScrollViewer _scrollViewerOverflow;

private ButtonBase _buttonScrollLeft;

private ButtonBase _buttonScrollRight;

private Border _headerBorder;

/// <summary>
/// 是否为内部操作
/// </summary>
internal bool IsInternalAction;

/// <summary>
/// 是否启用动画
/// </summary>
public static readonly DependencyProperty IsAnimationEnabledProperty = DependencyProperty.Register(
"IsAnimationEnabled", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 是否启用动画
/// </summary>
public bool IsAnimationEnabled
{
get => (bool) GetValue(IsAnimationEnabledProperty);
set => SetValue(IsAnimationEnabledProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 是否可以拖动
/// </summary>
public static readonly DependencyProperty IsDraggableProperty = DependencyProperty.Register(
"IsDraggable", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 是否可以拖动
/// </summary>
public bool IsDraggable
{
get => (bool) GetValue(IsDraggableProperty);
set => SetValue(IsDraggableProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 是否显示关闭按钮
/// </summary>
public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.RegisterAttached(
"ShowCloseButton", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.Inherits));

public static void SetShowCloseButton(DependencyObject element, bool value)
=> element.SetValue(ShowCloseButtonProperty, ValueBoxes.BooleanBox(value));

public static bool GetShowCloseButton(DependencyObject element)
=> (bool) element.GetValue(ShowCloseButtonProperty);

/// <summary>
/// 是否显示关闭按钮
/// </summary>
public bool ShowCloseButton
{
get => (bool) GetValue(ShowCloseButtonProperty);
set => SetValue(ShowCloseButtonProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 是否显示上下文菜单
/// </summary>
public static readonly DependencyProperty ShowContextMenuProperty = DependencyProperty.RegisterAttached(
"ShowContextMenu", typeof(bool), typeof(TabControl), new FrameworkPropertyMetadata(ValueBoxes.TrueBox, FrameworkPropertyMetadataOptions.Inherits));

public static void SetShowContextMenu(DependencyObject element, bool value)
=> element.SetValue(ShowContextMenuProperty, ValueBoxes.BooleanBox(value));

public static bool GetShowContextMenu(DependencyObject element)
=> (bool) element.GetValue(ShowContextMenuProperty);

/// <summary>
/// 是否显示上下文菜单
/// </summary>
public bool ShowContextMenu
{
get => (bool) GetValue(ShowContextMenuProperty);
set => SetValue(ShowContextMenuProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 是否将标签填充
/// </summary>
public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
"IsTabFillEnabled", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 是否将标签填充
/// </summary>
public bool IsTabFillEnabled
{
get => (bool) GetValue(IsTabFillEnabledProperty);
set => SetValue(IsTabFillEnabledProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 标签宽度
/// </summary>
public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
"TabItemWidth", typeof(double), typeof(TabControl), new PropertyMetadata(200.0));

/// <summary>
/// 标签宽度
/// </summary>
public double TabItemWidth
{
get => (double) GetValue(TabItemWidthProperty);
set => SetValue(TabItemWidthProperty, value);
}

/// <summary>
/// 标签高度
/// </summary>
public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
"TabItemHeight", typeof(double), typeof(TabControl), new PropertyMetadata(30.0));

/// <summary>
/// 标签高度
/// </summary>
public double TabItemHeight
{
get => (double) GetValue(TabItemHeightProperty);
set => SetValue(TabItemHeightProperty, value);
}

/// <summary>
/// 是否可以滚动
/// </summary>
public static readonly DependencyProperty IsScrollableProperty = DependencyProperty.Register(
"IsScrollable", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 是否可以滚动
/// </summary>
public bool IsScrollable
{
get => (bool) GetValue(IsScrollableProperty);
set => SetValue(IsScrollableProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 是否显示溢出按钮
/// </summary>
public static readonly DependencyProperty ShowOverflowButtonProperty = DependencyProperty.Register(
"ShowOverflowButton", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.TrueBox));

/// <summary>
/// 是否显示溢出按钮
/// </summary>
public bool ShowOverflowButton
{
get => (bool) GetValue(ShowOverflowButtonProperty);
set => SetValue(ShowOverflowButtonProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 是否显示滚动按钮
/// </summary>
public static readonly DependencyProperty ShowScrollButtonProperty = DependencyProperty.Register(
"ShowScrollButton", typeof(bool), typeof(TabControl), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 是否显示滚动按钮
/// </summary>
public bool ShowScrollButton
{
get => (bool) GetValue(ShowScrollButtonProperty);
set => SetValue(ShowScrollButtonProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 可见的标签数量
/// </summary>
private int _itemShowCount;

protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);

if (HeaderPanel == null)
{
IsInternalAction = false;
return;
}

UpdateOverflowButton();

if (IsInternalAction)
{
IsInternalAction = false;
return;
}

if (e.Action == NotifyCollectionChangedAction.Add)
{
for (var i = 0; i < Items.Count; i++)
{
if (ItemContainerGenerator.ContainerFromIndex(i) is not TabItem item) return;
item.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
item.TabPanel = HeaderPanel;
}
}

_headerBorder?.InvalidateMeasure();
IsInternalAction = false;
}

public override void OnApplyTemplate()
{
if (_buttonOverflow != null)
{
if (_buttonOverflow.Menu != null)
{
_buttonOverflow.Menu.Closed -= Menu_Closed;
_buttonOverflow.Menu = null;
}

_buttonOverflow.Click -= ButtonOverflow_Click;
}

if (_buttonScrollLeft != null) _buttonScrollLeft.Click -= ButtonScrollLeft_Click;
if (_buttonScrollRight != null) _buttonScrollRight.Click -= ButtonScrollRight_Click;

base.OnApplyTemplate();
HeaderPanel = GetTemplateChild(HeaderPanelKey) as TabPanel;

if (IsTabFillEnabled) return;

_buttonOverflow = GetTemplateChild(OverflowButtonKey) as ContextMenuToggleButton;
_scrollViewerOverflow = GetTemplateChild(OverflowScrollviewer) as ScrollViewer;
_buttonScrollLeft = GetTemplateChild(ScrollButtonLeft) as ButtonBase;
_buttonScrollRight = GetTemplateChild(ScrollButtonRight) as ButtonBase;
_headerBorder = GetTemplateChild(HeaderBorder) as Border;

if (_buttonScrollLeft != null) _buttonScrollLeft.Click += ButtonScrollLeft_Click;
if (_buttonScrollRight != null) _buttonScrollRight.Click += ButtonScrollRight_Click;

if (_buttonOverflow != null)
{
var menu = new ContextMenu
{
Placement = PlacementMode.Bottom,
PlacementTarget = _buttonOverflow
};
menu.Closed += Menu_Closed;
_buttonOverflow.Menu = menu;
_buttonOverflow.Click += ButtonOverflow_Click;
}
}

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
UpdateOverflowButton();
}

private void UpdateOverflowButton()
{
if (!IsTabFillEnabled)
{
_itemShowCount = (int) (ActualWidth / TabItemWidth);
//_buttonOverflow?.Show(ShowOverflowButton && Items.Count > 0 && Items.Count >= _itemShowCount);
}
}

private void Menu_Closed(object sender, RoutedEventArgs e) => _buttonOverflow.IsChecked = false;

private void ButtonScrollRight_Click(object sender, RoutedEventArgs e) =>
_scrollViewerOverflow.ScrollToHorizontalOffsetWithAnimation(Math.Min(
_scrollViewerOverflow.CurrentHorizontalOffset + TabItemWidth, _scrollViewerOverflow.ScrollableWidth));

private void ButtonScrollLeft_Click(object sender, RoutedEventArgs e) =>
_scrollViewerOverflow.ScrollToHorizontalOffsetWithAnimation(Math.Max(
_scrollViewerOverflow.CurrentHorizontalOffset - TabItemWidth, 0));

private void ButtonOverflow_Click(object sender, RoutedEventArgs e)
{
if (_buttonOverflow.IsChecked == true)
{
_buttonOverflow.Menu.Items.Clear();
for (var i = 0; i < Items.Count; i++)
{
if (ItemContainerGenerator.ContainerFromIndex(i) is not TabItem item) continue;

var menuItem = new MenuItem
{
HeaderStringFormat = ItemStringFormat,
HeaderTemplate = ItemTemplate,
HeaderTemplateSelector = ItemTemplateSelector,
Header = item.Header,
Width = TabItemWidth,
IsChecked = item.IsSelected,
IsCheckable = true,
IsEnabled = item.IsEnabled
};

menuItem.Click += delegate
{
_buttonOverflow.IsChecked = false;

var list = GetActualList();
if (list == null) return;

var actualItem = ItemContainerGenerator.ItemFromContainer(item);
if (actualItem == null) return;

var index = list.IndexOf(actualItem);
if (index >= _itemShowCount)
{
list.Remove(actualItem);
list.Insert(0, actualItem);
HeaderPanel.SetValue(TabPanel.FluidMoveDurationPropertyKey,
IsAnimationEnabled
? new Duration(TimeSpan.FromMilliseconds(200))
: new Duration(TimeSpan.FromMilliseconds(0)));
HeaderPanel.ForceUpdate = true;
HeaderPanel.Measure(new Size(HeaderPanel.DesiredSize.Width, ActualHeight));
HeaderPanel.ForceUpdate = false;
SetCurrentValue(SelectedIndexProperty, ValueBoxes.Int0Box);
}

item.IsSelected = true;
};
_buttonOverflow.Menu.Items.Add(menuItem);
}
}
}

internal double GetHorizontalOffset() => _scrollViewerOverflow?.CurrentHorizontalOffset ?? 0;

internal void UpdateScroll() => _scrollViewerOverflow?.RaiseEvent(new MouseWheelEventArgs(Mouse.PrimaryDevice, Environment.TickCount, 0)
{
RoutedEvent = MouseWheelEvent
});

internal void CloseAllItems() => CloseOtherItems(null);

internal void CloseOtherItems(TabItem currentItem)
{
var actualItem = currentItem != null ? ItemContainerGenerator.ItemFromContainer(currentItem) : null;

var list = GetActualList();
if (list == null) return;

IsInternalAction = true;

for (var i = 0; i < Items.Count; i++)
{
var item = list[i];
if (!Equals(item, actualItem) && item != null)
{
var argsClosing = new CancelRoutedEventArgs(TabItem.ClosingEvent, item);

if (ItemContainerGenerator.ContainerFromItem(item) is not TabItem tabItem) continue;

tabItem.RaiseEvent(argsClosing);
if (argsClosing.Cancel) return;

tabItem.RaiseEvent(new RoutedEventArgs(TabItem.ClosedEvent, item));
list.Remove(item);

i--;
}
}

SetCurrentValue(SelectedIndexProperty, Items.Count == 0 ? -1 : 0);
}

internal IList GetActualList()
{
IList list;
if (ItemsSource != null)
{
list = ItemsSource as IList;
}
else
{
list = Items;
}

return list;
}

protected override bool IsItemItsOwnContainerOverride(object item) => item is TabItem;

protected override DependencyObject GetContainerForItemOverride() => new TabItem();
}

+ 509
- 0
BPASmartClient.MilkWithTea/Control/TabItem.cs View File

@@ -0,0 +1,509 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using BPASmartClient.MilkWithTea.Control;
using BPASmartClient.MilkWithTea.Data;
using TabControl = BPASmartClient.MilkWithTea.Control.TabControl;

namespace BPASmartClient.MilkWithTea.Control;

public class TabItem : System.Windows.Controls.TabItem
{
/// <summary>
/// 动画速度
/// </summary>
private const int AnimationSpeed = 150;

/// <summary>
/// 选项卡是否处于拖动状态
/// </summary>
private static bool ItemIsDragging;

/// <summary>
/// 选项卡是否等待被拖动
/// </summary>
private bool _isWaiting;

/// <summary>
/// 拖动中的选项卡坐标
/// </summary>
private Point _dragPoint;

/// <summary>
/// 鼠标按下时选项卡位置
/// </summary>
private int _mouseDownIndex;

/// <summary>
/// 鼠标按下时选项卡横向偏移
/// </summary>
private double _mouseDownOffsetX;

/// <summary>
/// 鼠标按下时的坐标
/// </summary>
private Point _mouseDownPoint;

/// <summary>
/// 右侧可移动的最大值
/// </summary>
private double _maxMoveRight;

/// <summary>
/// 左侧可移动的最大值
/// </summary>
private double _maxMoveLeft;

/// <summary>
/// 选项卡宽度
/// </summary>
public double ItemWidth { get; internal set; }

/// <summary>
/// 选项卡拖动等待距离(在鼠标移动了超过20个像素无关单位后,选项卡才开始被拖动)
/// </summary>
private const double WaitLength = 20;

/// <summary>
/// 选项卡是否处于拖动状态
/// </summary>
private bool _isDragging;

/// <summary>
/// 选项卡是否已经被拖动
/// </summary>
private bool _isDragged;

/// <summary>
/// 目标横向位移
/// </summary>
internal double TargetOffsetX { get; set; }

/// <summary>
/// 当前编号
/// </summary>
private int _currentIndex;

/// <summary>
/// 标签容器横向滚动距离
/// </summary>
private double _scrollHorizontalOffset;


private TabPanel _tabPanel;


/// <summary>
/// 标签容器
/// </summary>
internal TabPanel TabPanel
{
get
{
if (_tabPanel == null && TabControlParent != null)
{
_tabPanel = TabControlParent.HeaderPanel;
}

return _tabPanel;
}
set => _tabPanel = value;
}

private TabControl TabControlParent => ItemsControl.ItemsControlFromItemContainer(this) as TabControl;


/// <summary>
/// 当前编号
/// </summary>
internal int CurrentIndex
{
get => _currentIndex;
set
{
if (_currentIndex == value || value < 0) return;
var oldIndex = _currentIndex;
_currentIndex = value;
UpdateItemOffsetX(oldIndex);
}
}

/// <summary>
/// 是否显示关闭按钮
/// </summary>
public static readonly DependencyProperty ShowCloseButtonProperty =
TabControl.ShowCloseButtonProperty.AddOwner(typeof(TabItem));

/// <summary>
/// 是否显示关闭按钮
/// </summary>
public bool ShowCloseButton
{
get => (bool) GetValue(ShowCloseButtonProperty);
set => SetValue(ShowCloseButtonProperty, ValueBoxes.BooleanBox(value));
}

public static void SetShowCloseButton(DependencyObject element, bool value)
=> element.SetValue(ShowCloseButtonProperty, ValueBoxes.BooleanBox(value));

public static bool GetShowCloseButton(DependencyObject element)
=> (bool) element.GetValue(ShowCloseButtonProperty);

/// <summary>
/// 是否显示上下文菜单
/// </summary>
public static readonly DependencyProperty ShowContextMenuProperty =
TabControl.ShowContextMenuProperty.AddOwner(typeof(TabItem), new FrameworkPropertyMetadata(OnShowContextMenuChanged));

private static void OnShowContextMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (TabItem) d;
if (ctl.Menu != null)
{
var show = (bool) e.NewValue;
ctl.Menu.IsEnabled = show;
//ctl.Menu.Show(show);
}
}

/// <summary>
/// 是否显示上下文菜单
/// </summary>
public bool ShowContextMenu
{
get => (bool) GetValue(ShowContextMenuProperty);
set => SetValue(ShowContextMenuProperty, ValueBoxes.BooleanBox(value));
}

public static void SetShowContextMenu(DependencyObject element, bool value)
=> element.SetValue(ShowContextMenuProperty, ValueBoxes.BooleanBox(value));

public static bool GetShowContextMenu(DependencyObject element)
=> (bool) element.GetValue(ShowContextMenuProperty);

public static readonly DependencyProperty MenuProperty = DependencyProperty.Register(
"Menu", typeof(ContextMenu), typeof(TabItem), new PropertyMetadata(default(ContextMenu), OnMenuChanged));

private static void OnMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ctl = (TabItem) d;
//ctl.OnMenuChanged(e.NewValue as ContextMenu);
}

//private void OnMenuChanged(ContextMenu menu)
//{
// if (IsLoaded && menu != null)
// {
// var parent = TabControlParent;
// if (parent == null) return;

// var item = parent.ItemContainerGenerator.ItemFromContainer(this);

// menu.DataContext = item;
// menu.SetBinding(IsEnabledProperty, new Binding(ShowContextMenuProperty.Name)
// {
// Source = this
// });
// menu.SetBinding(VisibilityProperty, new Binding(ShowContextMenuProperty.Name)
// {
// Source = this,
// Converter = GetResourceInternal<IValueConverter>(ResourceToken.Boolean2VisibilityConverter)
// });
// }
//}


public ContextMenu Menu
{
get => (ContextMenu) GetValue(MenuProperty);
set => SetValue(MenuProperty, value);
}

/// <summary>
/// 更新选项卡横向偏移
/// </summary>
/// <param name="oldIndex"></param>
private void UpdateItemOffsetX(int oldIndex)
{
if (!_isDragging || CurrentIndex >= TabPanel.ItemDic.Count)
{
return;
}

var moveItem = TabPanel.ItemDic[CurrentIndex];
moveItem.CurrentIndex -= CurrentIndex - oldIndex;
var offsetX = moveItem.TargetOffsetX;
var resultX = offsetX + (oldIndex - CurrentIndex) * ItemWidth;
TabPanel.ItemDic[CurrentIndex] = this;
TabPanel.ItemDic[moveItem.CurrentIndex] = moveItem;
moveItem.CreateAnimation(offsetX, resultX);
}

public TabItem()
{
//CommandBindings.Add(new CommandBinding(ControlCommands.Close, (s, e) => Close()));
//CommandBindings.Add(new CommandBinding(ControlCommands.CloseAll,
// (s, e) => { TabControlParent.CloseAllItems(); }));
//CommandBindings.Add(new CommandBinding(ControlCommands.CloseOther,
// (s, e) => { TabControlParent.CloseOtherItems(this); }));

//Loaded += (s, e) => OnMenuChanged(Menu);
}

protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(e);

if (VisualTreeHelper.HitTest(this, e.GetPosition(this)) == null) return;
IsSelected = true;
Focus();
}

protected override void OnHeaderChanged(object oldHeader, object newHeader)
{
base.OnHeaderChanged(oldHeader, newHeader);

if (TabPanel != null)
{
TabPanel.ForceUpdate = true;
InvalidateMeasure();
TabPanel.ForceUpdate = true;
}
}

internal void Close()
{
var parent = TabControlParent;
if (parent == null) return;

var item = parent.ItemContainerGenerator.ItemFromContainer(this);

var argsClosing = new CancelRoutedEventArgs(ClosingEvent, item);
RaiseEvent(argsClosing);
if (argsClosing.Cancel) return;

TabPanel.SetValue(TabPanel.FluidMoveDurationPropertyKey, parent.IsAnimationEnabled
? new Duration(TimeSpan.FromMilliseconds(200))
: new Duration(TimeSpan.FromMilliseconds(1)));

parent.IsInternalAction = true;
RaiseEvent(new RoutedEventArgs(ClosedEvent, item));

var list = parent.GetActualList();
list?.Remove(item);
}

protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);

if (VisualTreeHelper.HitTest(this, e.GetPosition(this)) == null) return;
var parent = TabControlParent;
if (parent == null) return;

if (parent.IsDraggable && !ItemIsDragging && !_isDragging)
{
parent.UpdateScroll();
TabPanel.SetValue(TabPanel.FluidMoveDurationPropertyKey, new Duration(TimeSpan.FromSeconds(0)));
_mouseDownOffsetX = RenderTransform.Value.OffsetX;
_scrollHorizontalOffset = parent.GetHorizontalOffset();
var mx = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
_mouseDownIndex = CalLocationIndex(mx);
var subIndex = _mouseDownIndex - CalLocationIndex(_scrollHorizontalOffset);
_maxMoveLeft = -subIndex * ItemWidth;
_maxMoveRight = parent.ActualWidth - ActualWidth + _maxMoveLeft;

_isDragging = true;
ItemIsDragging = true;
_isWaiting = true;
_dragPoint = e.GetPosition(parent);
_dragPoint = new Point(_dragPoint.X + _scrollHorizontalOffset, _dragPoint.Y);
_mouseDownPoint = _dragPoint;
CaptureMouse();
}
}

protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);

if (ItemIsDragging && _isDragging)
{
var parent = TabControlParent;
if (parent == null) return;

var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
CurrentIndex = CalLocationIndex(subX);

var p = e.GetPosition(parent);
p = new Point(p.X + _scrollHorizontalOffset, p.Y);

var subLeft = p.X - _dragPoint.X;
var totalLeft = p.X - _mouseDownPoint.X;

if (Math.Abs(subLeft) <= WaitLength && _isWaiting) return;

_isWaiting = false;
_isDragged = true;

var left = subLeft + RenderTransform.Value.OffsetX;
if (totalLeft < _maxMoveLeft)
{
left = _maxMoveLeft + _mouseDownOffsetX;
}
else if (totalLeft > _maxMoveRight)
{
left = _maxMoveRight + _mouseDownOffsetX;
}

var t = new TranslateTransform(left, 0);
RenderTransform = t;
_dragPoint = p;
}
}

protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);

ReleaseMouseCapture();

if (_isDragged)
{
var parent = TabControlParent;
if (parent == null) return;

var subX = TranslatePoint(new Point(), parent).X + _scrollHorizontalOffset;
var index = CalLocationIndex(subX);
var left = index * ItemWidth;
var offsetX = RenderTransform.Value.OffsetX;
CreateAnimation(offsetX, offsetX - subX + left, index);
}

_isDragging = false;
ItemIsDragging = false;
_isDragged = false;
}

protected override void OnMouseDown(MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Pressed)
{
if (ShowCloseButton || ShowContextMenu)
{
Close();
}
}
}

/// <summary>
/// 创建动画
/// </summary>
internal void CreateAnimation(double offsetX, double resultX, int index = -1)
{
var parent = TabControlParent;

void AnimationCompleted()
{
RenderTransform = new TranslateTransform(resultX, 0);
if (index == -1) return;

var list = parent.GetActualList();
if (list == null) return;

var item = parent.ItemContainerGenerator.ItemFromContainer(this);
if (item == null) return;

TabPanel.CanUpdate = false;
parent.IsInternalAction = true;

list.Remove(item);
parent.IsInternalAction = true;
list.Insert(index, item);
_tabPanel.SetValue(TabPanel.FluidMoveDurationPropertyKey, new Duration(TimeSpan.FromMilliseconds(0)));
TabPanel.CanUpdate = true;
TabPanel.ForceUpdate = true;
TabPanel.Measure(new Size(TabPanel.DesiredSize.Width, ActualHeight));
TabPanel.ForceUpdate = false;

Focus();
IsSelected = true;

if (!IsMouseCaptured)
{
parent.SetCurrentValue(Selector.SelectedIndexProperty, _currentIndex);
}
}

TargetOffsetX = resultX;
if (!parent.IsAnimationEnabled)
{
AnimationCompleted();
return;
}

var animation = CreateAnimation(resultX, AnimationSpeed);
animation.FillBehavior = FillBehavior.Stop;
animation.Completed += (s1, e1) => AnimationCompleted();
var f = new TranslateTransform(offsetX, 0);
RenderTransform = f;
f.BeginAnimation(TranslateTransform.XProperty, animation, HandoffBehavior.Compose);
}
/// <summary>
/// 创建一个Double动画
/// </summary>
/// <param name="toValue"></param>
/// <param name="milliseconds"></param>
/// <returns></returns>
public static DoubleAnimation CreateAnimation(double toValue, double milliseconds = 200)
{
return new(toValue, new Duration(TimeSpan.FromMilliseconds(milliseconds)))
{
EasingFunction = new PowerEase { EasingMode = EasingMode.EaseInOut }
};
}


/// <summary>
/// 计算选项卡当前合适的位置编号
/// </summary>
/// <param name="left"></param>
/// <returns></returns>
private int CalLocationIndex(double left)
{
if (_isWaiting)
{
return CurrentIndex;
}

var maxIndex = TabControlParent.Items.Count - 1;
var div = (int) (left / ItemWidth);
var rest = left % ItemWidth;
var result = rest / ItemWidth > .5 ? div + 1 : div;

return result > maxIndex ? maxIndex : result;
}

public static readonly RoutedEvent ClosingEvent = EventManager.RegisterRoutedEvent("Closing", RoutingStrategy.Bubble, typeof(EventHandler), typeof(TabItem));

public event EventHandler Closing
{
add => AddHandler(ClosingEvent, value);
remove => RemoveHandler(ClosingEvent, value);
}

public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent("Closed", RoutingStrategy.Bubble, typeof(EventHandler), typeof(TabItem));

public event EventHandler Closed
{
add => AddHandler(ClosedEvent, value);
remove => RemoveHandler(ClosedEvent, value);
}
}

+ 200
- 0
BPASmartClient.MilkWithTea/Control/TabPanel.cs View File

@@ -0,0 +1,200 @@
using BPASmartClient.MilkWithTea.Data;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;


namespace BPASmartClient.MilkWithTea.Control;

public class TabPanel : Panel
{
private int _itemCount;

/// <summary>
/// 是否可以更新
/// </summary>
internal bool CanUpdate = true;

/// <summary>
/// 选项卡字典
/// </summary>
internal Dictionary<int, TabItem> ItemDic = new();

public static readonly DependencyPropertyKey FluidMoveDurationPropertyKey =
DependencyProperty.RegisterReadOnly("FluidMoveDuration", typeof(Duration), typeof(TabPanel),
new PropertyMetadata(new Duration(TimeSpan.FromMilliseconds(0))));

/// <summary>
/// 流式行为持续时间
/// </summary>
public static readonly DependencyProperty FluidMoveDurationProperty =
FluidMoveDurationPropertyKey.DependencyProperty;

/// <summary>
/// 流式行为持续时间
/// </summary>
public Duration FluidMoveDuration
{
get => (Duration) GetValue(FluidMoveDurationProperty);
set => SetValue(FluidMoveDurationProperty, value);
}

/// <summary>
/// 是否将标签填充
/// </summary>
public static readonly DependencyProperty IsTabFillEnabledProperty = DependencyProperty.Register(
"IsTabFillEnabled", typeof(bool), typeof(TabPanel), new PropertyMetadata(ValueBoxes.FalseBox));

/// <summary>
/// 是否将标签填充
/// </summary>
public bool IsTabFillEnabled
{
get => (bool) GetValue(IsTabFillEnabledProperty);
set => SetValue(IsTabFillEnabledProperty, ValueBoxes.BooleanBox(value));
}

/// <summary>
/// 标签宽度
/// </summary>
public static readonly DependencyProperty TabItemWidthProperty = DependencyProperty.Register(
"TabItemWidth", typeof(double), typeof(TabPanel), new PropertyMetadata(200.0));

/// <summary>
/// 标签宽度
/// </summary>
public double TabItemWidth
{
get => (double) GetValue(TabItemWidthProperty);
set => SetValue(TabItemWidthProperty, value);
}

/// <summary>
/// 标签高度
/// </summary>
public static readonly DependencyProperty TabItemHeightProperty = DependencyProperty.Register(
"TabItemHeight", typeof(double), typeof(TabPanel), new PropertyMetadata(30.0));

/// <summary>
/// 标签高度
/// </summary>
public double TabItemHeight
{
get => (double) GetValue(TabItemHeightProperty);
set => SetValue(TabItemHeightProperty, value);
}

/// <summary>
/// 是否可以强制更新
/// </summary>
internal bool ForceUpdate;

private Size _oldSize;

/// <summary>
/// 是否已经加载
/// </summary>
private bool _isLoaded;

protected override Size MeasureOverride(Size constraint)
{
if ((_itemCount == InternalChildren.Count || !CanUpdate) && !ForceUpdate && !IsTabFillEnabled) return _oldSize;
constraint.Height = TabItemHeight;
_itemCount = InternalChildren.Count;

var size = new Size();

ItemDic.Clear();

var count = InternalChildren.Count;
if (count == 0)
{
_oldSize = new Size();
return _oldSize;
}
constraint.Width += InternalChildren.Count;

var itemWidth = .0;
var arr = new int[count];

if (!IsTabFillEnabled)
{
itemWidth = TabItemWidth;
}
else
{
if (TemplatedParent is TabControl tabControl)
{
arr = DivideInt2Arr((int) tabControl.ActualWidth + InternalChildren.Count, count);
}
}

for (var index = 0; index < count; index++)
{
if (IsTabFillEnabled)
{
itemWidth = arr[index];
}
if (InternalChildren[index] is TabItem tabItem)
{
tabItem.RenderTransform = new TranslateTransform();
tabItem.MaxWidth = itemWidth;
var rect = new Rect
{
X = size.Width - tabItem.BorderThickness.Left,
Width = itemWidth,
Height = TabItemHeight
};
tabItem.Arrange(rect);
tabItem.ItemWidth = itemWidth - tabItem.BorderThickness.Left;
tabItem.CurrentIndex = index;
tabItem.TargetOffsetX = 0;
ItemDic[index] = tabItem;
size.Width += tabItem.ItemWidth;
}
}
size.Height = constraint.Height;
_oldSize = size;
return _oldSize;
}

/// <summary>
/// 平分一个整数到一个数组中
/// </summary>
/// <param name="num"></param>
/// <param name="count"></param>
/// <returns></returns>
public static int[] DivideInt2Arr(int num, int count)
{
var arr = new int[count];
var div = num / count;
var rest = num % count;
for (var i = 0; i < count; i++)
{
arr[i] = div;
}
for (var i = 0; i < rest; i++)
{
arr[i] += 1;
}
return arr;
}

public TabPanel()
{
Loaded += (s, e) =>
{
if (_isLoaded) return;
ForceUpdate = true;
Measure(new Size(DesiredSize.Width, ActualHeight));
ForceUpdate = false;
foreach (var item in ItemDic.Values)
{
item.TabPanel = this;
}
_isLoaded = true;
};
}
}

+ 12
- 0
BPASmartClient.MilkWithTea/Data/CancelRoutedEventArgs.cs View File

@@ -0,0 +1,12 @@
using System.Windows;

namespace BPASmartClient.MilkWithTea.Data;

public class CancelRoutedEventArgs : RoutedEventArgs
{
public CancelRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source)
{
}

public bool Cancel { get; set; }
}

+ 69
- 0
BPASmartClient.MilkWithTea/Data/ValueBoxes.cs View File

@@ -0,0 +1,69 @@
using System;
using System.Windows;
using System.Windows.Controls;

namespace BPASmartClient.MilkWithTea.Data;

/// <summary>
/// 装箱后的值类型(用于提高效率)
/// </summary>
internal static class ValueBoxes
{
internal static object TrueBox = true;

internal static object FalseBox = false;

internal static object VerticalBox = Orientation.Vertical;

internal static object HorizontalBox = Orientation.Horizontal;

internal static object VisibleBox = Visibility.Visible;

internal static object CollapsedBox = Visibility.Collapsed;

internal static object HiddenBox = Visibility.Hidden;

internal static object Double01Box = .1;

internal static object Double0Box = .0;

internal static object Double1Box = 1.0;

internal static object Double10Box = 10.0;

internal static object Double20Box = 20.0;

internal static object Double100Box = 100.0;

internal static object Double200Box = 200.0;

internal static object Double300Box = 300.0;

internal static object DoubleNeg1Box = -1.0;

internal static object Int0Box = 0;

internal static object Int1Box = 1;

internal static object Int2Box = 2;

internal static object Int5Box = 5;

internal static object Int99Box = 99;

internal static object BooleanBox(bool value) => value ? TrueBox : FalseBox;

internal static object OrientationBox(Orientation value) =>
value == Orientation.Horizontal ? HorizontalBox : VerticalBox;

internal static object VisibilityBox(Visibility value)
{
return value switch
{
Visibility.Visible => VisibleBox,
Visibility.Hidden => HiddenBox,
Visibility.Collapsed => CollapsedBox,
_ => throw new ArgumentOutOfRangeException(nameof(value), value, null)
};
}
}

+ 5
- 36
BPASmartClient.MilkWithTea/GLobal.cs View File

@@ -1,5 +1,5 @@
using BPASmartClient.Model;
using Model;
using BPASmartClient.MorkMOC;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -17,46 +17,15 @@ namespace BPASmartClient.MilkWithTea
public static string recipePath = string.Empty;
public static string posionPath = string.Empty;

public static bool makeEnable = false;

public static ObservableCollection<LocalTeaWithMilkConfig> MaterialRecipes { get; set; } = new ObservableCollection<LocalTeaWithMilkConfig>();
public static bool makeEnable = true;
/// <summary>
/// 设备信息列表
/// 设备信息集合
/// </summary>
public static ObservableCollection<DeviceConfigModelJson> deviceConfig { get; set; } = new ObservableCollection<DeviceConfigModelJson>();


/// <summary>
/// 获取Json文件内容,转换成ObservableCollection
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="path"></param>
/// <returns></returns>
public static ObservableCollection<T> GetJsonToT<T>(string path)
{
if (!File.Exists(path))
{
//创建该文件
File.Create(path);
return default;
}
else
{
using (StreamReader recipeReader = new StreamReader(path))//读取json文件
{
string datacache = "";
string line;
while ((line = recipeReader.ReadLine()) != null) //循环将每一行数据拼接为一个完整的字符串
{
datacache = datacache + line;
}

var res = JsonConvert.DeserializeObject<ObservableCollection<T>>(datacache); //将string转换为class类,从而达到json文件转换的目的
if (res != null)
return res;
else return new ObservableCollection<T> { };
}
}
}


}
}

+ 49
- 2
BPASmartClient.MilkWithTea/MainWindow.xaml.cs View File

@@ -7,6 +7,7 @@ using BPASmartClient.IoT;
using BPASmartClient.Message;
using BPASmartClient.Peripheral;
using BPASmartClient.ViewModel;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
@@ -36,8 +37,10 @@ namespace BPASmartClient.MilkWithTea
public MainWindow()
{
InitializeComponent();

Initialize();
TextHelper.GetInstance.WriteTextInfo("MOC", "StartShop", "DeviceConfig");
CreateDevice();
//Initialize();

}

@@ -45,6 +48,50 @@ namespace BPASmartClient.MilkWithTea
DoubleAnimation yd1 = new DoubleAnimation();//实例化浮点动画
DoubleAnimation yd2 = new DoubleAnimation();

private void CreateDevice()
{
DirectoryInfo directoryInfo = new DirectoryInfo(LocaPath.GetInstance().GetDeviceConfigPath);
if(!File.Exists($"{directoryInfo}Moc.json"))
{
File.WriteAllText($"{directoryInfo}Moc.json", JsonConvert.SerializeObject(GLobal.deviceConfig));
}
string JsonString = File.ReadAllText($"{directoryInfo}MOC.json");
var result = JsonConvert.DeserializeObject<ObservableCollection<DeviceConfigModelJson>>(JsonString);
if (result != null)
{
ShopDeviceConfigViewModel.deviceConfig.Clear();
foreach (var item in result)
{
GLobal.deviceConfig.Add(item);
}
}

if(GLobal.deviceConfig.Count <1)
{
GLobal.deviceConfig.Add(new DeviceConfigModelJson());
if(GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.Count <1)
{
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.Add(new DeviceModel());
if(GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.Count <1)
{
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.Add(new CommunicationModel());
}
}
}
if (GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).communicationDevcies.ElementAt(0).variables.Count < 1)
{
for (int i = 0; i < 20; i++)
{
GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).communicationDevcies.ElementAt(0).variables.Add(new Variable()
{
Id = GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).communicationDevcies.ElementAt(0).variables.Count,
Address = string.Empty,
ReadLeng = 0
});
}
File.WriteAllText($"{LocaPath.GetInstance().GetDeviceConfigPath}MOC.json", JsonConvert.SerializeObject(GLobal.deviceConfig));
}
}

private void Initialize()
{


+ 13
- 0
BPASmartClient.MilkWithTea/Model/JsonDeviceConfig.cs View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPASmartClient.MilkWithTea.Model
{
public class JsonDeviceConfig
{
public ObservableCollection<DeviceConfigModelJson> deviceConfig { get; set; } = new ObservableCollection<DeviceConfigModelJson>();
}
}

+ 23
- 0
BPASmartClient.MilkWithTea/Model/JsonLocalRecipes.cs View File

@@ -0,0 +1,23 @@
using BPASmartClient.MorkMOC;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPASmartClient.MilkWithTea.Model
{
partial class JsonLocalRecipes
{
/// <summary>
/// 本地奶茶配方
/// </summary>
public ObservableCollection<LocalRecipe> localRecipes { get; set; } = new ObservableCollection<LocalRecipe>();
/// <summary>
/// 本地原料
/// </summary>
public ObservableCollection<LocalMaterail> localMaterails { get; set; } = new ObservableCollection<LocalMaterail>();

}
}

+ 93
- 154
BPASmartClient.MilkWithTea/View/LocalConfigureView.xaml View File

@@ -11,48 +11,6 @@
<vm:LocalConfigureViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="TextBlock.FontSize" Value="13" />
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Mode=Self},Path=Content.Text}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<!--HorizontalAlignment 可以设置内容展示位置-->
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" HorizontalAlignment="Center"
Margin="{TemplateBinding Padding}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value=".56"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="DataGridRow">
<Setter Property="FontSize" Value="16"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,5"/>
<Style.Triggers>
<!-- 隔行换色 -->
<Trigger Property="AlternationIndex" Value="0">
<Setter Property="Background" Value="#FFFAFAFA" />
</Trigger>
<Trigger Property="AlternationIndex" Value="1">
<Setter Property="Background" Value="#FFF5F5F7" />
</Trigger>

<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#87CEFA" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="Button">
<Setter Property="Width" Value="90"/>
<Setter Property="Height" Value="20"/>
@@ -78,12 +36,47 @@
</Setter.Value>
</Setter>
</Style>

<Style TargetType="ListViewItem" >
<Setter Property="Margin" Value="60,20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Padding="4" x:Name="mborder" BorderBrush="Transparent" BorderThickness="1">

<Border >
<Grid Width="250" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MaterialPosition}" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10,0"/>
<TextBox Text="{Binding MaterialName}" Grid.Column="1" Width="140"
HorizontalAlignment="Center" VerticalAlignment="Center"></TextBox>
</Grid>
</Border>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">

</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid Background="#F3F6F9" Margin="20">
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible">
<StackPanel>
<!--奶茶配方录入-->
<Expander Style="{StaticResource ExpanderStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Content="奶茶配方录入" HorizontalAlignment="Right" VerticalAlignment="Center" Width="150" Click="Button_Click"/>
<ScrollViewer VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible" Grid.Row="1">
<StackPanel>
<!--奶茶配方录入-->
<!--<Expander Style="{StaticResource ExpanderStyle}">
<Expander.Header>
<TextBlock Text="奶茶配方录入" />
</Expander.Header>
@@ -154,128 +147,74 @@
</DataGrid>
</Grid>
</Expander.Content>
</Expander>
<!--配料录入-->
<Expander Grid.Row="1" Style="{StaticResource ExpanderStyle}">
<Expander.Header>
<TextBlock Text="本地配料录入" />
</Expander.Header>
<Expander.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Content="保存物料位置名称" Grid.ColumnSpan="2" Style="{StaticResource buttonNormal}" Height="34" Width="200" Command="{Binding UpdateMaterialPosionCommand}"/>
<DataGrid Grid.Row="1" Margin="50,5" AutoGenerateColumns="False" ItemsSource="{Binding materail1,Mode=TwoWay}"
FrozenColumnCount="1" RowHeight="34"
VerticalAlignment="Top" HorizontalAlignment="Right"
IsReadOnly="True"
CanUserResizeColumns="False" CanUserResizeRows="False" SelectionMode="Single"
CanUserReorderColumns="False" AlternationCount="2" RowHeaderWidth="0" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="物料位置" Width="170">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Foreground="Black" Text="{Binding MaterialPosion}"
VerticalAlignment="Center" HorizontalAlignment="Left"
Margin="5,0" FontSize="16"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="物料" Width="250">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding MaterialName ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Margin="2" FontSize="16"
Width="160" Height="28" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Row="1" Grid.Column="1" Margin="50,5" AutoGenerateColumns="False" ItemsSource="{Binding materail2,Mode=TwoWay}"
FrozenColumnCount="1" RowHeight="34"
VerticalAlignment="Top" HorizontalAlignment="Left"
IsReadOnly="True"
CanUserResizeColumns="False" CanUserResizeRows="False" SelectionMode="Single"
CanUserReorderColumns="False" AlternationCount="2" RowHeaderWidth="0" CanUserAddRows="False">
</Expander>-->
<!--配料录入-->
<Expander Grid.Row="1" Style="{StaticResource ExpanderStyle}">
<Expander.Header>
<TextBlock Text="本地配料录入" />
</Expander.Header>
<Expander.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Content="保存物料位置名称" Grid.ColumnSpan="2" Style="{StaticResource buttonNormal}" Height="34" Width="200"
Command="{Binding UpdateMaterialPosionCommand}"/>
<ListView ItemsSource="{Binding localMaterails}" Grid.Row="1"
Width="800" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Margin="10"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
</Expander.Content>
</Expander>
<!--奶茶清单-->
<Expander Grid.Row="2" Style="{StaticResource ExpanderStyle}" >
<Expander.Header>
<TextBlock Text="本地奶茶配方"/>
</Expander.Header>
<Expander.Content>
<DataGrid Grid.Row="4" Margin="100,5" AutoGenerateColumns="False" RowHeight="32" ItemsSource="{Binding localMaterialRecipes}" Width="500"
FrozenColumnCount="1"
VerticalAlignment="Top"
IsReadOnly="True"
CanUserResizeColumns="False" CanUserResizeRows="False" SelectionMode="Single"
CanUserReorderColumns="False" AlternationCount="2" RowHeaderWidth="0" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="物料位置" Width="170">
<DataGridTemplateColumn Header="奶茶" Width="200">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Foreground="Black" Text="{Binding MaterialPosion}"
VerticalAlignment="Center" HorizontalAlignment="Left"
Margin="5,0" FontSize="16"/>
<TextBlock Text="{Binding RecipeName}" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Center"
Margin="5,2" FontSize="16"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="物料" Width="250">
<DataGridTemplateColumn Header="操作" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding MaterialName ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center" HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Margin="2" Height="28"
Width="160" FontSize="16"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Content="删除" Margin="2"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.DeleteRecipeCommand}"
CommandParameter="{Binding RecipeID}"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Expander.Content>
</Expander>
<!--奶茶清单-->
<Expander Grid.Row="2" Style="{StaticResource ExpanderStyle}" >
<Expander.Header>
<TextBlock Text="本地奶茶配方"/>
</Expander.Header>
<Expander.Content>
<DataGrid Grid.Row="4" Margin="100,5" AutoGenerateColumns="False" RowHeight="32" ItemsSource="{Binding localMaterialRecipes}" Width="500"
FrozenColumnCount="1"
VerticalAlignment="Top"
IsReadOnly="True"
CanUserResizeColumns="False" CanUserResizeRows="False" SelectionMode="Single"
CanUserReorderColumns="False" AlternationCount="2" RowHeaderWidth="0" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="奶茶" Width="200">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="{Binding GoodNames}" Foreground="Black"
VerticalAlignment="Center" HorizontalAlignment="Center"
Margin="5,2" FontSize="16"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="操作" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button Content="删除" Margin="2"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.DeleteRecipeCommand}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=SelectedIndex}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Expander.Content>
</Expander>
</StackPanel>
</ScrollViewer>
</Expander.Content>
</Expander>
</StackPanel>
</ScrollViewer>
</Grid>
</Grid>
</UserControl>

+ 8
- 1
BPASmartClient.MilkWithTea/View/LocalConfigureView.xaml.cs View File

@@ -1,4 +1,5 @@
using System;
using BPASmartClient.MilkWithTea.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -24,5 +25,11 @@ namespace BPASmartClient.MilkWithTea.View
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
RecipeConfige recipeConfige = new RecipeConfige();
recipeConfige.ShowDialog();
}
}
}

+ 4
- 4
BPASmartClient.MilkWithTea/View/MainControlView.xaml View File

@@ -168,11 +168,11 @@
<TextBlock Text="配方" Grid.Row="2" Grid.Column="1" Margin="10" FontSize="22" />
<Border BorderBrush="#D5DFE5" BorderThickness="4" Grid.Row="3" Margin="20,0,0,0">
<ListBox ItemsSource="{Binding localTeaWithMilks}" SelectionChanged="ListBox_SelectionChanged" IsEnabled="{Binding MakeEnable}"
Foreground="LightSlateGray">
Foreground="LightSlateGray" SelectedValue="{Binding SelectedRecipe,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListBox.ItemTemplate>
<DataTemplate >
<Grid>
<TextBlock Text="{Binding GoodNames}" Margin="5,10" FontSize="22"
<TextBlock Text="{Binding RecipeName}" Margin="5,10" FontSize="22"
Background="Transparent" />
</Grid>
</DataTemplate>
@@ -181,7 +181,7 @@
</Border>
<ListBox x:Name="recipeList" Grid.Row="3" Grid.Column="1" Margin="5,10"
ItemsSource="{Binding materialRecipes}" FontSize="18"
ItemsSource="{Binding localMaterails}" FontSize="18"
Width="200" HorizontalAlignment="Left" Foreground="LightSlateGray">
<ListBox.ItemTemplate>
<DataTemplate >
@@ -191,7 +191,7 @@
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="15"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Material}" Margin="20,10" FontSize="16"/>
<TextBlock Text="{Binding MaterialName}" Margin="20,10" FontSize="16"/>
<TextBlock Text="{Binding MaterialWeight}" Margin="5,10,0,10" Grid.Column="1" HorizontalAlignment="Left" />
<TextBlock Text="g" Margin="0,10" HorizontalAlignment="Right" Grid.Column="2"/>
</Grid>


+ 2
- 3
BPASmartClient.MilkWithTea/View/MainControlView.xaml.cs View File

@@ -1,5 +1,4 @@
using BPASmartClient.MilkWithTea.ViewModel;
using Model;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -29,9 +28,9 @@ namespace BPASmartClient.MilkWithTea.View

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if((sender as ListBox).SelectedItem is LocalTeaWithMilkConfig config)
if((sender as ListBox).SelectedItem is LocalRecipe config)
{
recipeList.ItemsSource = config.materialRecipes;
recipeList.ItemsSource = config.localMaterails;
}
}
}


+ 23
- 14
BPASmartClient.MilkWithTea/View/ParameterSetting.xaml View File

@@ -11,13 +11,7 @@
<vm:PatrameterSettiongViewModel/>
</UserControl.DataContext>
<UserControl.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="18"/>
<Setter Property="Foreground" Value="DarkSlateGray"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="FontSize" Value="18"/>
</Style>
</UserControl.Resources>
<Grid Background="#F3F6F9" Margin="20" >
<Grid.ColumnDefinitions>
@@ -40,18 +34,18 @@
<StackPanel Orientation="Horizontal">
<TextBlock Text="通道口:"/>
<ComboBox ItemsSource="{Binding materialPosions}"
SelectedIndex="{Binding MaterialID ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding MaterialID ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
Margin="10,0" Width="120 " Style="{StaticResource cmbstyle}"/>
<TextBlock Text="出料量:" Margin="10,0,0,0" />
<TextBox Text="{Binding OutMaterailWeight}" Width="60" Margin="10,0" VerticalContentAlignment="Center"/>
<TextBlock Text="g" Margin="2,0"/>
<Button Content="出料" Style="{StaticResource buttonNormal}" Height="36" Width="100" Margin="30,0" Command="{Binding OutMaterailCommad}"/>
<TextBlock Text="转盘位置:" Margin="60,0,10,0"/>
<ComboBox ItemsSource="{Binding TurntablePosion}"
<!--<TextBlock Text="转盘位置:" Margin="60,0,10,0"/>-->
<!--<ComboBox ItemsSource="{Binding TurntablePosion}"
SelectedIndex="{Binding TurntableID,Mode=TwoWay ,UpdateSourceTrigger=PropertyChanged}"
Margin="10,0" Width="100 " Style="{StaticResource cmbstyle}"/>
<Button Content="转动" Style="{StaticResource buttonNormal}" Height="36" Width="80" Margin="30,0"
Command="{Binding TurntableCommad}"/>
Command="{Binding TurntableCommad}"/>-->
</StackPanel>
<CheckBox Grid.Row="2" Content="禁用本地奶茶下单" HorizontalAlignment="Left" Margin="0,10"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
@@ -84,7 +78,7 @@
<TextBlock Text="校正后的重量" Grid.Column="5"/>
<TextBlock Text="出料时间" Grid.Column="3"/>

<ComboBox Grid.Row="1" Width="100" Style="{StaticResource cmbstyle}" ItemsSource="{Binding materialPosions}"
<ComboBox Grid.Row="1" Width="100" Style="{StaticResource cmbstyle}" ItemsSource="{Binding materialPosions}" Height="30"
SelectedIndex="{Binding CorrectPassway ,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectionChanged="ComboBox_SelectionChanged" />
<TextBlock Grid.Row="1" Grid.Column="1" ></TextBlock>
<CheckBox x:Name="OpenIsCheck"
@@ -126,16 +120,31 @@
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<TextBlock Text="店铺名称:" Grid.ColumnSpan="2" FontSize="22" Height="28" Width="94" HorizontalAlignment="Left" Margin="20,0"/>
<TextBox Text="{Binding ShopName}" Grid.Column="2" Grid.ColumnSpan="2" Margin="-20,10,30,10" VerticalContentAlignment="Center"/>
<TextBlock Text="店铺ID:" Grid.Row="1" Height="23" Width="60" HorizontalAlignment="Left" Margin="20,0"/>
<TextBlock Text="设备ID:" Grid.Column="2" Grid.Row="1" Height="23" Width="60" />
<TextBlock Text="PLC地址:" Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Height="23" Width="72" HorizontalAlignment="Left" Margin="20,0"/>
<TextBox Text="{Binding ShopID}" Width="60" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Left" VerticalContentAlignment="Center" Margin="0,12"/>
<TextBox Text="{Binding DeviceID}" Width="60" Grid.Column="3" Grid.Row="1" HorizontalAlignment="Left" VerticalContentAlignment="Center" Margin="0,12"/>
<TextBox Text="{Binding PLCAdress}" Grid.Column="2" Grid.Row="2" Grid.ColumnSpan="2" Margin="-20,10,30,10"

<RadioButton Content="网口" GroupName="a" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
Command="{Binding ChangeCommunationCommand}"/>
<StackPanel Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3" Orientation="Horizontal" Visibility="{Binding VsIP}"
HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Text="IP:" Height="23" Margin="20,0"/>
<TextBox Text="{Binding PLCAdress}" Margin="0,10,30,10" Width="160"
VerticalContentAlignment="Center"/>
</StackPanel>
<RadioButton Content="串口" GroupName="a" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center"
IsChecked="{Binding IsPort}" Command="{Binding ChangeCommunationCommand}"/>
<StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" Orientation="Horizontal" Visibility="{Binding VsPort}">
<TextBlock Text="串口号:" />
<ComboBox Style="{DynamicResource cmbstyle}" Height="26" Width="100" ItemsSource="{Binding Ports}"
SelectedValue="{Binding Prot}"/>
</StackPanel>
<Button Style="{StaticResource buttonNormal}"
Grid.Column="4" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="3"


+ 135
- 0
BPASmartClient.MilkWithTea/View/RecipeConfige.xaml View File

@@ -0,0 +1,135 @@
<Window x:Class="BPASmartClient.MilkWithTea.View.RecipeConfige"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BPASmartClient.MilkWithTea.View"
xmlns:vm="clr-namespace:BPASmartClient.MilkWithTea.ViewModel"
mc:Ignorable="d"
Title="RecipeConfige"
Height="800" Width="800" WindowStartupLocation="CenterScreen" WindowStyle="None" AllowsTransparency="True"
>
<Window.DataContext>
<vm:RecipeConfigeViewModel/>
</Window.DataContext>
<Window.Resources>


</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>

</Grid.RowDefinitions>

<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="奶茶名称" Margin="10,0" />
<TextBox Text="{Binding Name}" Width="120" Foreground="DarkSlateGray" Margin="10,0"/>
<Button Content="添加配料" Margin="10,0" Width="100" Command="{Binding AddMaterialCommand}"/>
<Button Content="保存" Margin="10,0" Width="100" Command="{Binding SaveCommand}"/>
<Button Content="取消" Margin="10,0" Width="100" Click="Button_Click"/>
</StackPanel>
<Grid Grid.Row="1">
<ScrollViewer
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{Binding Materails}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<RadioButton GroupName="all">
<RadioButton.Template>
<ControlTemplate TargetType="RadioButton">
<Grid Name="gr" Height="40" Margin="20,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<ComboBox Name="cb" Width="120" Height="30"
ItemsSource="{Binding DataContext.materialNames, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
SelectedValue="{Binding MaterialID}"
SelectedValuePath="Key" DisplayMemberPath="Value"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Text="{Binding MaterialWeight}" Width="120" Margin="10,0"/>
<TextBlock Text="g" />
</StackPanel>
<Button Grid.Column="2"
Width="70"
Height="25"
Margin="15,0,0,0"
FontSize="16"
BorderBrush="#FF2AB2E7"
BorderThickness="1"
HorizontalAlignment="Left"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
Content="删 除" />

</Grid>


</ControlTemplate>
</RadioButton.Template>
</RadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
<Grid Grid.Row="2">
<ListBox x:Name="listview1" AllowDrop="True" SelectionMode="Extended" MouseMove="listview1_MouseMove"
ItemsSource="{Binding Materails}" PreviewMouseLeftButtonUp="listview1_MouseLeftButtonUp">
<ListBox.ItemTemplate>
<DataTemplate>
<Border PreviewMouseLeftButtonDown="listview1_MouseLeftButtonDown" Width="800" BorderBrush="Black" BorderThickness="1" Background="White"
>
<RadioButton GroupName="all" >
<RadioButton.Template>
<ControlTemplate TargetType="RadioButton">
<Grid Name="gr" Height="40" Margin="20,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<ComboBox Name="cb" Width="120" Height="30"
ItemsSource="{Binding DataContext.materialNames, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
SelectedValue="{Binding MaterialID }"
SelectedValuePath="Key" DisplayMemberPath="Value"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Text="{Binding MaterialWeight}" Width="120" Margin="10,0"/>
<TextBlock Text="g" />
</StackPanel>
<Button Grid.Column="2"
Width="70"
Height="25"
Margin="15,0,0,0"
FontSize="16"
BorderBrush="#FF2AB2E7"
BorderThickness="1"
HorizontalAlignment="Left"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}}"
CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem, Mode=FindAncestor}}"
Content="删 除" />
</Grid>


</ControlTemplate>
</RadioButton.Template>
</RadioButton>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
</Window>

+ 174
- 0
BPASmartClient.MilkWithTea/View/RecipeConfige.xaml.cs View File

@@ -0,0 +1,174 @@
using BPASmartClient.MilkWithTea.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace BPASmartClient.MilkWithTea.View
{
/// <summary>
/// RecipeConfige.xaml 的交互逻辑
/// </summary>
public partial class RecipeConfige : Window
{
double X,Y;
Border ultUE;
Popup mypopup;
ListBoxItem OldItem;

public RecipeConfige()
{
InitializeComponent();
ActionManage.GetInstance.CancelRegister("RecipeConfigeViewClose");
ActionManage.GetInstance.Register(new Action(()=> this.Close()), "RecipeConfigeViewClose");
}

private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}




private int GetCurrentIndex(GetPositionDelegate getPosition)
{
int index = -1;
for (int i = 0; i < listview1.Items.Count; ++i)
{
ListViewItem item = GetListViewItem(i);
if (item != null && this.IsMouseOverTarget(item, getPosition))
{
index = i;
break;
}
}
return index;
}

private bool IsMouseOverTarget(Visual target, GetPositionDelegate getPosition)
{
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
Point mousePos = getPosition((IInputElement)target);
return bounds.Contains(mousePos);
}

delegate Point GetPositionDelegate(IInputElement element);

ListViewItem GetListViewItem(int index)
{
if (listview1.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
return null;
return listview1.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
}

private void CloneVisual(Border border, MouseButtonEventArgs e)
{
ListBoxItem listBoxItem = new ListBoxItem();
Point ptLeftUp = new Point(0, 0);
ptLeftUp = listview1.PointToScreen(ptLeftUp);
mypopup = new Popup();
double y = e.GetPosition(listview1).Y;
double x = e.GetPosition(listview1).X;
VisualBrush brush = new VisualBrush(border);
Rectangle rect = new Rectangle();
rect.Width = border.ActualWidth;
rect.Height = border.ActualHeight;
rect.Fill = brush;
rect.Opacity = border.Opacity;
border.Opacity = 0.8;
mypopup.Child = rect;
mypopup.AllowsTransparency = true;
mypopup.HorizontalOffset = ptLeftUp.X + x - ((FrameworkElement)ultUE).ActualWidth / 2;
mypopup.VerticalOffset = ptLeftUp.Y + y - ((FrameworkElement)ultUE).ActualHeight / 2;
mypopup.IsOpen = true;
}

private void listview1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var pos = e.GetPosition(listview1);
HitTestResult result = VisualTreeHelper.HitTest(listview1, pos);
OldItem = Utils.FindVisualParent<ListBoxItem>(result.VisualHit);
if(OldItem != null)
{
if (e.Source is Border)
{
ultUE = (Border)e.Source;
ultUE.CaptureMouse();
ultUE.Visibility = Visibility.Collapsed;
CloneVisual(ultUE, e);
}
}
}



private void listview1_MouseMove(object sender, MouseEventArgs e)
{
Point ptLeftUp = new Point(0, 0);
Point ptRightDown = new Point(this.ActualWidth, this.ActualHeight);
ptLeftUp = listview1.PointToScreen(ptLeftUp);
ptRightDown = listview1.PointToScreen(ptRightDown);
double y = e.GetPosition(listview1).Y;
double x = e.GetPosition(listview1).X;
if (mypopup != null)
{
mypopup.HorizontalOffset = ptLeftUp.X + x - ((FrameworkElement)ultUE).ActualWidth / 2;
mypopup.VerticalOffset = ptLeftUp.Y + y - ((FrameworkElement)ultUE).ActualHeight / 2;
}
}

private void listview1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if(mypopup != null)
{
mypopup.IsOpen = false;
mypopup = null;
}
if (OldItem == null) return;
var pos = e.GetPosition(listview1);
HitTestResult result = VisualTreeHelper.HitTest(listview1, pos);
if(result == null) return;
var Newitem = Utils.FindVisualParent<ListBoxItem>(result.VisualHit);
if (Newitem == null) return;
if (OldItem == Newitem) return;
int iold = listview1.Items.IndexOf((LocalMaterail)OldItem.DataContext);
int inew = listview1.Items.IndexOf((LocalMaterail)Newitem.DataContext);
RecipeConfigeViewModel.Materails.Move(iold,inew);
}
}

internal static class Utils
{
//根据子元素查找父元素
public static T FindVisualParent<T>(DependencyObject obj) where T : class
{
while (obj != null)
{
if (obj is T)
return obj as T;

obj = VisualTreeHelper.GetParent(obj);
}
return null;
}
}
}

+ 30
- 169
BPASmartClient.MilkWithTea/ViewModel/LocalConfigureViewModel.cs View File

@@ -1,7 +1,5 @@
using BPASmartClient.MorkTM;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using Model;
using BPASmartClient.MorkMOC;
using CommunityToolkit.Mvvm.Input;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -14,56 +12,34 @@ using System.Windows;

namespace BPASmartClient.MilkWithTea.ViewModel
{
public class LocalConfigureViewModel : ObservableObject

partial class LocalConfigureViewModel : ObservableObject
{
#region 奶茶配方录入
/// <summary>
/// 奶茶配方
/// </summary>
public ObservableCollection<MaterialRecipe> materialRecipes { get => materialRecipes1; set => materialRecipes1 = value; }
/// <summary>
/// 出料集合
/// </summary>
public ObservableCollection<string> MaterailList { get; set; } = new ObservableCollection<string>();
/// <summary>
/// 奶茶名称
/// </summary>
public string LocalGoodName { get { return _localGoodName; } set { _localGoodName = value; OnPropertyChanged(); } }
private string _localGoodName;

private ObservableCollection<MaterialRecipe> materialRecipes1 = new ObservableCollection<MaterialRecipe>();

/// <summary>
/// 添加一条配方
/// </summary>
public RelayCommand AddRecipeCommand { get; set; }
/// <summary>
/// 删除一条配方
/// </summary>
public RelayCommand<object> RemoveRecipeCommand { get; set; }
/// <summary>
/// 取消配方
/// </summary>
public RelayCommand RecipeCancelCommand { get; set; }
/// <summary>
/// 保存配方
/// </summary>
public RelayCommand SaveRecipeCommand { get; set; }

#endregion

#region 本地奶茶配方
/// <summary>
/// 本地奶茶配方列表
/// </summary>
public ObservableCollection<LocalTeaWithMilkConfig> localMaterialRecipes { get; set; } = GLobal.MaterialRecipes;
public ObservableCollection<LocalRecipe> localMaterialRecipes { get; set; } = Json<JsonLocalRecipes>.Data.localRecipes;

/// <summary>
/// 删除配方奶茶
/// </summary>
public RelayCommand<object> DeleteRecipeCommand { get; set; }
[RelayCommand]
private void DeleteRecipe(object o)
{
if (o == null) return;
if(o is string id)
{
var res = localMaterialRecipes.FirstOrDefault(p => p.RecipeID == id);
if (res != null)
{
localMaterialRecipes.Remove(res);
Json<JsonLocalRecipes>.Save();
}
}
}

#endregion

@@ -71,141 +47,26 @@ namespace BPASmartClient.MilkWithTea.ViewModel
/// <summary>
/// 物料位置名称集合
/// </summary>
public ObservableCollection<MaterailNameAndPosion> materailNameAndPosions { get; set; } = new ObservableCollection<MaterailNameAndPosion>();
public List<MaterailNameAndPosion> materail1 { get; set; } = new List<MaterailNameAndPosion>();
public List<MaterailNameAndPosion> materail2 { get; set; } = new List<MaterailNameAndPosion>();
public ObservableCollection<LocalMaterail> localMaterails { get; set; } = Json<JsonLocalRecipes>.Data.localMaterails;
/// <summary>
/// 更新物料位置
/// </summary>
public RelayCommand UpdateMaterialPosionCommand { get; set; }
[RelayCommand]
private void UpdateMaterialPosion()
{
Json<JsonLocalRecipes>.Save();
}
#endregion

public LocalConfigureViewModel()
{
materialRecipes.Add(new MaterialRecipe()
{
MaterialWeight = 10
});




AddRecipeCommand = new RelayCommand(new Action(() =>
{
materialRecipes.Add(new MaterialRecipe()
{
MaterialID = materialRecipes.Count() + 1
});

}));

RemoveRecipeCommand = new RelayCommand<object>((o =>
{
if (o != null && o is int index)
{
materialRecipes.RemoveAt(index);
for (int i = 0; i < materialRecipes.Count; i++)//ID排序
{
materialRecipes[i].MaterialID = i + 1;
}
}

}));

RecipeCancelCommand = new RelayCommand(new Action(() =>
{
materialRecipes.Clear();
LocalGoodName = String.Empty;
}));

SaveRecipeCommand = new RelayCommand(new Action(() =>
{
if (LocalGoodName == "" || LocalGoodName == null) return;
if (materialRecipes.Count == 0) return;

localMaterialRecipes.Insert(0, new LocalTeaWithMilkConfig()
{
GoodNames = LocalGoodName,
materialRecipes = materialRecipes

});

UpdateLocalJosnData<LocalTeaWithMilkConfig>(GLobal.recipePath, localMaterialRecipes);//更新奶茶配方json文件
MessageBox.Show("保存成功");
}));


DeleteRecipeCommand = new RelayCommand<object>((o =>
{
if (o != null && o is int index)
{
localMaterialRecipes.RemoveAt(index);
UpdateLocalJosnData<LocalTeaWithMilkConfig>(GLobal.recipePath, localMaterialRecipes);//更新奶茶配方json文件
}
}));

UpdateMaterialPosionCommand = new RelayCommand(new Action(() =>
{
materailNameAndPosions.Clear();
foreach(var item in materail1)
{
materailNameAndPosions.Add(item);
}
foreach (var item in materail2)
{
materailNameAndPosions.Add(item);
}
UpdateLocalJosnData<MaterailNameAndPosion>(GLobal.posionPath, materailNameAndPosions);//更新物料位置名称
MaterailList.Clear();
foreach (MaterailNameAndPosion m in materailNameAndPosions)
{
if (m.MaterialName != null) MaterailList.Add(m.MaterialName);

}
}));

Init();
}

/// <summary>
/// 界面初始化加载
/// </summary>
private void Init()
{

materailNameAndPosions = GLobal.GetJsonToT<MaterailNameAndPosion>(GLobal.posionPath);
if (materailNameAndPosions.Count == 0)
{
foreach (MaterialPosion item in Enum.GetValues(typeof(MaterialPosion)))
{
materailNameAndPosions.Add(new MaterailNameAndPosion()
{
MaterialPosion = item.ToString()
});
}
}
materail1 = materailNameAndPosions.Take<MaterailNameAndPosion>(14).ToList();
materail2 = materailNameAndPosions.TakeLast<MaterailNameAndPosion>(14).ToList();
foreach (MaterailNameAndPosion m in materailNameAndPosions)
{
if (m.MaterialName != null) MaterailList.Add(m.MaterialName);

}
}

/// <summary>
/// 更新Json文件数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="path"></param>
/// <param name="ts"></param>
private void UpdateLocalJosnData<T>(string path, ObservableCollection<T> ts)
{
if (ts != null) File.WriteAllText(path, JsonConvert.SerializeObject(ts));

}
}
}

+ 37
- 28
BPASmartClient.MilkWithTea/ViewModel/MainControlViewModel.cs View File

@@ -1,29 +1,22 @@
using BPA.Message;
using BPA.Message.Enum;
using BPASmartClient.Device;
using BPASmartClient.EventBus;

global using CommunityToolkit.Mvvm.Input;
using BPASmartClient.Helper;
using BPASmartClient.Model;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using BPASmartClient.Message;

namespace BPASmartClient.MilkWithTea.ViewModel
{
public class MainControlViewModel: ObservableObject
partial class MainControlViewModel: ObservableObject
{

public ObservableCollection<LocalTeaWithMilkConfig> localTeaWithMilks { get; set; } = GLobal.MaterialRecipes;
/// <summary>
/// 本地奶茶列表
/// </summary>
public ObservableCollection<LocalRecipe> localTeaWithMilks { get; set; } = Json<JsonLocalRecipes>.Data.localRecipes;

public ObservableCollection<MaterialRecipe> materialRecipes { get; set; } = new ObservableCollection<MaterialRecipe>();
/// <summary>
/// 奶茶对应的原料列表
/// </summary>
public ObservableCollection<LocalMaterail> materialRecipes { get; set; } = new ObservableCollection<LocalMaterail>();

/// <summary>
/// 订单状态列表
@@ -38,15 +31,16 @@ namespace BPASmartClient.MilkWithTea.ViewModel
/// <summary>
/// 当前正在制作的奶茶
/// </summary>
public string CurrentGood { get { return _currentGood; } set { _currentGood = value; OnPropertyChanged(); } }
[ObservableProperty]
private string _currentGood = "茉莉花茶";
/// <summary>
/// 奶茶制作百分比
/// </summary>
public string MakePercent { get { return _makePercent; } set { _makePercent = value; OnPropertyChanged(); } }
[ObservableProperty]
private string _makePercent = "0";


[ObservableProperty]
private LocalRecipe _selectedRecipe;

/// <summary>
/// 当前正在制作的奶茶
@@ -56,16 +50,31 @@ namespace BPASmartClient.MilkWithTea.ViewModel
/// <summary>
/// 本地奶茶制作
/// </summary>
public RelayCommand MakeGoodCommand { get; set; }
[RelayCommand]
private void MakeGood()
{
if(SelectedRecipe == null) return;
foreach(var item in SelectedRecipe.localMaterails)
{
var res = Json<JsonLocalRecipes>.Data.localMaterails.FirstOrDefault(p => p.MaterialID == item.MaterialID);
if ( res!= null)
{
item.MaterialPosition = res.MaterialPosition;
}
else
{
MessageLog.GetInstance.ShowEx($"配料:{item.MaterialName}不存在,下单失败");
return;
}
}
ActionManage.GetInstance.Send( "MakeGoods",SelectedRecipe);
}




public MainControlViewModel()
{
MakeGoodCommand = new RelayCommand(new Action(() =>
{

}));
Init();
MorkOrderPush morkOrderPush = new MorkOrderPush() { GoodsName = "珍珠奶茶", SortNum = 1 };
MorkOrderPush morkOrderPush1 = new MorkOrderPush() { GoodsName = "茉莉花茶", SortNum = 2 };


+ 16
- 17
BPASmartClient.MilkWithTea/ViewModel/MainWindowVeiwModel.cs View File

@@ -1,7 +1,6 @@
using BPASmartClient.Helper;
global using Microsoft.Toolkit.Mvvm.ComponentModel;
using BPASmartClient.Helper;
using BPASmartClient.Model;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Model;
using System;
using System.Collections.Generic;
using System.IO;
@@ -17,23 +16,23 @@ namespace BPASmartClient.MilkWithTea.ViewModel

public MainWindowVeiwModel()
{
init();
}

private void init()
{
string path = Path.Combine(Environment.CurrentDirectory, "AccessFile", "Recipes");
//判断文件夹是否存在,如果不存在就创建file文件夹
if (!Directory.Exists(path))
Json<JsonLocalRecipes>.Read();
Json<JsonDeviceConfig>.Read();
if (Json<JsonLocalRecipes>.Data.localMaterails.Count<14)
{
Directory.CreateDirectory(path);
Json<JsonLocalRecipes>.Data.localMaterails.Clear();
for (int i = 1; i < 15; i++)
{
Json<JsonLocalRecipes>.Data.localMaterails.Add(new LocalMaterail
{
MaterialID = Guid.NewGuid().ToString(),
MaterialPosition = i
});;
}
}
GLobal.recipePath = Path.Combine(path, "LocalRecipes.json");
GLobal.posionPath = Path.Combine(path, "MaterialPosion.json");

GLobal.MaterialRecipes = GLobal.GetJsonToT<LocalTeaWithMilkConfig>(GLobal.recipePath);
GLobal.deviceConfig = GLobal.GetJsonToT<DeviceConfigModelJson>($"{LocaPath.GetInstance().GetDeviceConfigPath}奶茶味魔方.json");
}


}
}

+ 105
- 86
BPASmartClient.MilkWithTea/ViewModel/PatrameterSettiongViewModel.cs View File

@@ -1,9 +1,7 @@
using BPASmartClient.Helper;
using BPASmartClient.Message;
using BPASmartClient.Model;
using BPASmartClient.MorkTM;
using Microsoft.Toolkit.Mvvm.ComponentModel;
using Microsoft.Toolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Input;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
@@ -15,164 +13,185 @@ using System.Threading.Tasks;

namespace BPASmartClient.MilkWithTea.ViewModel
{
public class PatrameterSettiongViewModel: ObservableObject
partial class PatrameterSettiongViewModel: ObservableObject
{
string FileName => GLobal.deviceConfig.Count > 0 ? GLobal.deviceConfig[0].ShopName : string.Empty;

/// <summary>
/// 物料通道口列表
/// </summary>
public ObservableCollection<MaterialPosion> materialPosions { get; set; } = new ObservableCollection<MaterialPosion>();
/// <summary>
/// 转盘位置列表
/// </summary>
public ObservableCollection<OutMaterialPosion> TurntablePosion { get; set; } = new ObservableCollection<OutMaterialPosion>();
public ObservableCollection<int> materialPosions { get; set; } = new ObservableCollection<int>();

/// <summary>
/// 出料位置ID
/// </summary>
public int MaterialID { get { return _materialID; } set { _materialID = value; OnPropertyChanged(); } }
[ObservableProperty]
private int _materialID = 0;

/// <summary>
/// 出料重量
/// </summary>
public float OutMaterailWeight { get { return _outMaterilWeight; } set { _outMaterilWeight = value; OnPropertyChanged(); } }
private float _outMaterilWeight;
/// <summary>
/// 装盘ID
/// </summary>
public int TurntableID { get { return _turntableID; } set { _turntableID = value; OnPropertyChanged(); } }
private int _turntableID = 0;
[ObservableProperty]
private int _outMaterilWeight;

/// <summary>
/// 矫正的通道号
/// </summary>
public int CorrectPassway { get { return _CorrectPassway; } set { _CorrectPassway = value; OnPropertyChanged(); } }
[ObservableProperty]
private int _CorrectPassway = 0;
/// <summary>
/// 通道是否开启
/// </summary>
public bool PasswayIsOpen { get { return _passwayIsOpen; } set { _passwayIsOpen = value; OnPropertyChanged(); } }
[ObservableProperty]
private bool _passwayIsOpen ;
/// <summary>
/// 矫正重量
/// </summary>
public float CorrectMatetailWeight { get { return _CorrectMatetailWeight; } set { _CorrectMatetailWeight = value; OnPropertyChanged(); } }
private float _CorrectMatetailWeight = 0;
[ObservableProperty]
private int _correctMatetailWeight = 0;
/// <summary>
/// 矫正时间
/// </summary>
public int OutTime { get { return _0utTime; } set { _0utTime = value; OnPropertyChanged(); } }
private int _0utTime = 0;
[ObservableProperty]
private int _outTime = 0;

public bool IsEnable { get { return !GLobal.makeEnable; } set { GLobal.makeEnable = !value; OnPropertyChanged(); } }
/// <summary>
/// 出料动作
/// </summary>
public RelayCommand OutMaterailCommad { get; set; }
/// <summary>
/// 转动转盘
/// </summary>
public RelayCommand TurntableCommad { get; set; }
[RelayCommand]
private void OutMaterial()
{
ActionManage.GetInstance.Send("通道口出料", new object[] { MaterialID, OutMaterilWeight });
}
/// <summary>
/// 开始矫正
/// </summary>
public RelayCommand CheckPasswayCommad { get; set; }
[RelayCommand]
private void CheckPassway()
{

}
/// <summary>
/// 开启通道
/// </summary>
public RelayCommand OpenPasswayCommand { get; set; }
[RelayCommand]
private void OpenPassway()
{

}
/// <summary>
/// 确认重量
/// </summary>
public RelayCommand CheckMaterailWeightCommand { get; set; }
[RelayCommand]
private void CheckMaterailWeight()
{

}
#region 设备配置
/// <summary>
/// 店铺名称
/// </summary>
public string ShopName { get { return _shopName; } set { _shopName = value; OnPropertyChanged(); } }
private string _shopName;
[ObservableProperty]
private string? _shopName = string.Empty;
/// <summary>
/// 店铺ID
/// </summary>
public string ShopID { get { return _shopID; } set { _shopID = value; OnPropertyChanged(); } }
private string _shopID;
[ObservableProperty]
private string? _shopID = string.Empty;
/// <summary>
/// 设备ID
/// </summary>
public string DeviceID { get { return _deviceID; } set { _deviceID = value; OnPropertyChanged(); } }
private string _deviceID;
[ObservableProperty]
private string? _deviceID = string.Empty;
/// <summary>
/// PLC地址
/// </summary>
public string PLCAdress { get { return _pLCAdress; } set { _pLCAdress = value; OnPropertyChanged(); } }
private string _pLCAdress;
[ObservableProperty]
private string? _pLCAdress = string.Empty;

public RelayCommand SaveDevicesCommand { get; set; }
#endregion
[ObservableProperty]
private bool _isPort = true;

public PatrameterSettiongViewModel()
{
OutMaterailCommad = new RelayCommand(new Action(() =>
{
ActionManage.GetInstance.Send("通道口出料", new object[] { MaterialID +1, OutMaterailWeight });
[ObservableProperty]
private Visibility _vsIP = Visibility.Hidden;

}));
[ObservableProperty]
private Visibility _vsPort = Visibility.Visible;

TurntableCommad = new RelayCommand(new Action(() =>
{
ActionManage.GetInstance.Send("转盘转动", new object[] { TurntableID });
}));

OpenPasswayCommand = new RelayCommand(new Action(() =>
{
if(PasswayIsOpen) ActionManage.GetInstance.Send("开启通道", new object[] { CorrectPassway + 1 });
[ObservableProperty]
private string[] _ports;

}));
[ObservableProperty]
private string _prot;

CheckPasswayCommad = new RelayCommand(new Action(() =>
[RelayCommand]
private void SaveDevices()
{
SaveDeviceMessage();
}
[RelayCommand]
private void ChangeCommunation()
{
if(IsPort)
{
ActionManage.GetInstance.Send("开始矫正", new object[] { CorrectPassway + 1,OutTime });
}));

CheckMaterailWeightCommand = new RelayCommand(new Action(() =>
VsPort = Visibility.Visible;
VsIP = Visibility.Hidden;
}
else
{
ActionManage.GetInstance.Send("矫正重量", new object[] { CorrectPassway + 1, CorrectMatetailWeight });
}));

SaveDevicesCommand = new RelayCommand(SaveDeviceMessage);
VsIP = Visibility.Visible;
VsPort = Visibility.Hidden;
}
}
#endregion

public PatrameterSettiongViewModel()
{
Ports = System.IO.Ports.SerialPort.GetPortNames();
init();
}
private void init()
{
foreach (MaterialPosion materialPosion in Enum.GetValues(typeof(MaterialPosion)))
for (int i = 1; i < 14; i++)
{
materialPosions.Add(materialPosion);
materialPosions.Add(i);
}

foreach (OutMaterialPosion outMaterialPosion in Enum.GetValues(typeof(OutMaterialPosion)))
if (GLobal.deviceConfig.Count > 0)
{
TurntablePosion.Add(outMaterialPosion);
ShopName = GLobal.deviceConfig.ElementAtOrDefault(0).ShopName ;
ShopID = GLobal.deviceConfig.ElementAtOrDefault(0).ShopId;
DeviceID = GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAt(0).DeviceId;
PLCAdress = GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAt(0).communicationDevcies.ElementAt(0).communicationPar.IPAddress;
}
ShopName = GLobal.deviceConfig.ElementAt(0).ShopName;
ShopID = GLobal.deviceConfig.ElementAt(0).ShopId;
DeviceID = GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).DeviceId;
PLCAdress = GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).communicationDevcies.ElementAt(0).communicationPar.IPAddress;
}

private void SaveDeviceMessage()
{
if (GLobal.deviceConfig.Count > 0)
{
GLobal.deviceConfig.ElementAt(0).ShopName = ShopName;
GLobal.deviceConfig.ElementAt(0).ShopId = ShopID;
GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).DeviceId = DeviceID;
GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).Id = Guid.NewGuid().ToString();
GLobal.deviceConfig.ElementAt(0).deviceModels.ElementAt(0).communicationDevcies.ElementAt(0).communicationPar.IPAddress = PLCAdress;
File.WriteAllText($"{LocaPath.GetInstance().GetDeviceConfigPath}奶茶味魔方.json", JsonConvert.SerializeObject(GLobal.deviceConfig));
GLobal.deviceConfig.ElementAtOrDefault(0).ShopName = ShopName;
GLobal.deviceConfig.ElementAtOrDefault(0).ShopId = ShopID;
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).DeviceId = DeviceID;
if(IsPort)
{
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.ElementAtOrDefault(0).communicationPar.IsSerialPort = true;
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.ElementAtOrDefault(0).communicationPar.SerialPort = Prot;
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.ElementAtOrDefault(0).communicationPar.BaudRate = 9600;
}
else
{
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.ElementAtOrDefault(0).communicationPar.IsSerialPort = false;
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.ElementAtOrDefault(0).communicationPar.IsNetworkPort = true;
GLobal.deviceConfig.ElementAtOrDefault(0).deviceModels.ElementAtOrDefault(0).communicationDevcies.ElementAtOrDefault(0).communicationPar.IPAddress = PLCAdress;
}
}
File.WriteAllText($"{LocaPath.GetInstance().GetDeviceConfigPath}MOC.json", JsonConvert.SerializeObject(GLobal.deviceConfig));


}

}
}

+ 75
- 0
BPASmartClient.MilkWithTea/ViewModel/RecipeConfigeViewModel.cs View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;

namespace BPASmartClient.MilkWithTea.ViewModel
{
partial class RecipeConfigeViewModel:ObservableObject
{
public static ObservableCollection<LocalMaterail> Materails { get; set; } = new ObservableCollection<LocalMaterail>();

public Dictionary<string,string> materialNames { get; set; } = new Dictionary<string,string>();

[ObservableProperty]
private string _name = String.Empty;


[RelayCommand]
private void AddMaterial()
{
Materails.Add(new LocalMaterail());
}
[RelayCommand]
private void Delete(object o)
{
if (o == null) return;
if(o is ListBoxItem id)
{
Materails.Remove((LocalMaterail)id.DataContext);
}
}
[RelayCommand]
private void Save()
{
if(Name == String.Empty)
{
return;
}
if(Json<JsonLocalRecipes>.Data.localRecipes.FirstOrDefault(p=>p.RecipeName == Name)!= null)
{
return;
}
foreach(var materail in Materails)
{
materail.MaterialName = materialNames[materail.MaterialID];
}
Json<JsonLocalRecipes>.Data.localRecipes.Add(new LocalRecipe
{
RecipeID = Guid.NewGuid().ToString(),
RecipeName = Name,
localMaterails = Materails,
});

Json<JsonLocalRecipes>.Save();
ActionManage.GetInstance.Send("RecipeConfigeViewClose");
}

public RecipeConfigeViewModel()
{
if(Json<JsonLocalRecipes>.Data.localMaterails.Count > 0)
{
foreach(var item in Json<JsonLocalRecipes>.Data.localMaterails)
{
if(item.MaterialID!=null&&item.MaterialName!=null)
{
materialNames.Add(item.MaterialID, item.MaterialName);
}
}
}
Materails.Clear();
}
}
}

+ 4
- 0
BPASmartClient.Model/BPASmartClient.Model.csproj View File

@@ -21,4 +21,8 @@
<PackageReference Include="Microsoft.Toolkit.Mvvm" Version="7.1.2" />
</ItemGroup>

<ItemGroup>
<Folder Include="奶咖一体机\" />
</ItemGroup>

</Project>

+ 78
- 165
BPASmartClient.MorkF/Control_MorkF.cs View File

@@ -35,55 +35,38 @@ namespace BPASmartClient.MorkF
#region 调试代码
public void CommandRegist()
{
#region 设备控制
ActionManage.GetInstance.Register(PLCInite, "InitCommand");
ActionManage.GetInstance.Register(InitialData, "SimultaorOrder");
ActionManage.GetInstance.Register(MaterialOne, "MaterialOne");
ActionManage.GetInstance.Register(MaterialTwo, "MaterialTwo");
ActionManage.GetInstance.Register(MaterialThree, "MaterialThree");
ActionManage.GetInstance.Register(MaterialFour, "MaterialFour");
ActionManage.GetInstance.Register(MaterialFive, "MaterialFive");
ActionManage.GetInstance.Register(ManualOpenExhaust, "OpenExhaust");
ActionManage.GetInstance.Register(CloseExhaust, "CloaseExhaust");
ActionManage.GetInstance.Register(StartQX, "StartQXOne");
ActionManage.GetInstance.Register(StartQX, "StartQXTwo");

#endregion
ActionManage.GetInstance.Register(ShreddCabbage, "ShreddCabbage");
ActionManage.GetInstance.Register(FryPork, "FryPork");
ActionManage.GetInstance.Register(XingBaoGu, "XingBaoGu");

ActionManage.GetInstance.Register(TakePot, "TakePot");
ActionManage.GetInstance.Register(TakePotReset, "TakePotReset");
ActionManage.GetInstance.Register(TakeMaterial, "TakeMaterial");
ActionManage.GetInstance.Register(ManualOutMeal, "OutMeal");
#region 配料控制
ActionManage.GetInstance.Register(OutMaterials, "OutMaterials");
#endregion

#region 炒锅1
ActionManage.GetInstance.Register<Action>(AddOil, "AddOil");
ActionManage.GetInstance.Register(TakeOff, "TakeOff");
ActionManage.GetInstance.Register(OneBlock, "OneBlock");
ActionManage.GetInstance.Register(TwoBlock, "TwoBlock");
ActionManage.GetInstance.Register(ThreeBlock, "ThreeBlock");
ActionManage.GetInstance.Register(OverTurnOff, "OverTurnOff");
ActionManage.GetInstance.Register(OverOneBlock, "OverOneBlock");
ActionManage.GetInstance.Register(OverTwoBlock, "OverTwoBlock");
ActionManage.GetInstance.Register(OverThreeBlock, "OverThreeBlock");
ActionManage.GetInstance.Register(OverGoOn, "OverGoOn");
ActionManage.GetInstance.Register(OverGoDown, "OverGoDown");
ActionManage.GetInstance.Register(AutoModel, "AutoModel");
ActionManage.GetInstance.Register(ManualModel, "ManualModel");

ActionManage.GetInstance.Register<Action>(AddOil, "SecAddOil");
ActionManage.GetInstance.Register(TakeOff, "SecTakeOff");
ActionManage.GetInstance.Register(OneBlock, "SecOneBlock");
ActionManage.GetInstance.Register(TwoBlock, "SecTwoBlock");
ActionManage.GetInstance.Register(ThreeBlock, "SecThreeBlock");
ActionManage.GetInstance.Register(OverTurnOff, "SecOverTurnOff");
ActionManage.GetInstance.Register(OverOneBlock, "SecOverOneBlock");
ActionManage.GetInstance.Register(OverTwoBlock, "SecOverTwoBlock");
ActionManage.GetInstance.Register(OverThreeBlock, "SecOverThreeBlock");
ActionManage.GetInstance.Register(OverGoOn, "SecOverGoOn");
ActionManage.GetInstance.Register(OverGoDown, "SecOverGoDown");
ActionManage.GetInstance.Register(AutoModel, "SecAutoModel");
ActionManage.GetInstance.Register(ManualModel, "SecManualModel");
ActionManage.GetInstance.Register(StartFire, "StartFire");
ActionManage.GetInstance.Register(StopFire, "StopFire");
ActionManage.GetInstance.Register(StartStir, "StartStir");
ActionManage.GetInstance.Register(StopStir, "StopStir");
ActionManage.GetInstance.Register(OutFood, "OutFood");
ActionManage.GetInstance.Register(StirArmGoOrigin, "StirArmGoOrigin");
ActionManage.GetInstance.Register(StirArmGoWork, "StirArmGoWork");
ActionManage.GetInstance.Register(HBOTGoWork, "HBOTGoWork");
ActionManage.GetInstance.Register(OutMeal, "OutMeal");
ActionManage.GetInstance.Register(SetFire, "SetFire");
ActionManage.GetInstance.Register(SetStir, "SetStir");
#endregion

}

/// <summary>
/// 手撕包菜流程
/// </summary>
@@ -161,160 +144,91 @@ namespace BPASmartClient.MorkF
stirFryBom.AddAction(new StirFryAction() { Time = StirFryTime.T6, PotActions = new List<StirFryPotAction>() { StirFryPotAction.搅拌臂下位, StirFryPotAction.快速旋转 }, During = 55 });
stirFryBom.AddAction(new StirFryAction() { Time = StirFryTime.T11, RobotActions = new List<StirFryRobotAction>() { StirFryRobotAction.灶取锅 } });
}
public void StartQX(object obj)
//出配料
public void OutMaterials(object o)
{

if ((int)obj == 1)
WriteData("M1.4", true);
if ((int)obj == 2)
WriteData("M1.7", true);
}
public void ManualOpenExhaust()
{
WriteData("M0.7", true);
}
public void CloseExhaust()
{
WriteData("M0.7", false);
if (o == null) return;
if (o is List<int> ints && ints.Count == 2)
{
WriteControl(morkF.PassWayValue[ints[0]], ints[1]);//写入通道值
Thread.Sleep(500);
WriteControl(morkF.StartPassWay[ints[0]], true);//开启通道
}
}
public void TakeMaterial()

#region 炒锅1
//加热启动
public void StartFire()
{
WriteData("M14.1", true);
WriteControl("M0.1", true);
}
public void ManualOutMeal()
//加热停止
public void StopFire()
{
WriteData("M14.2", true);
WriteControl("M0.1", false);
}
public void MaterialOne()
//搅拌启动
public void StartStir()
{
WriteData("M13.0", true);
WriteControl("M0.2", true);
}
public void MaterialTwo()
//搅拌启停止
public void StopStir()
{
WriteData("M13.1", true);
WriteControl("M0.2", false);
}
public void MaterialThree()
//倒菜
public void OutFood()
{
WriteData("M13.2", true);
WriteControl("M0.3", true);
}
public void MaterialFour()
//搅拌臂去原点位
public void StirArmGoOrigin()
{
WriteData("M13.3", true);
WriteControl("M0.5", true);
}
public void MaterialFive()

//搅拌臂去炒制位
public void StirArmGoWork()
{
WriteData("M13.4", true);
WriteControl("M0.6", true);
}
public void AutoModel(object obj)
//HBOT放盒子到位
public void HBOTGoWork()
{

WriteData("0.3", true);

WriteControl("M0.7", true);
}
public void ManualModel()
//出餐启动
public void OutMeal()
{
WriteData("0.2", true);
WriteControl("M0.4", true);
}
public void AddOil(object obj)
//加热挡位设定
public void SetFire(object o)
{
if ((int)obj == 1)
if(o == null) return;
if(o is List<int> ints&&ints.Count == 1)
{
Task.Run(() => { WriteData("M2.7", true); Task.Delay(4000).Wait(); WriteData("M2.7", false); });
WriteControl("VW228",ints[0]);
}

if ((int)obj == 2)
{
Task.Run(() => { WriteData("M3.1", true); Task.Delay(4000).Wait(); WriteData("M3.1", false); });
}
}
public void TakePot(object obj)
{
WriteData("M14.0", true);
}

public void TakePotReset(object obj)
{
WriteData("M14.0", false);
}
public void TakeOff(object obj)
//搅拌挡位设定
public void SetStir(object o)
{
if ((int)obj == 1)
WriteData("M4.0", new bool[] { false, false, false, false, false, false, false, false });//0000 0000
if ((int)obj == 2)
WriteData("M5.0", new bool[] { false, false, false, false, false, false, false, false });//0000 0000
if (o == null) return;
if (o is List<int> ints && ints.Count == 1)
{
WriteControl("VW230", ints[0]);
}
}

public void OneBlock(object obj)
{
if ((int)obj == 1)
WriteData("M4.0", new bool[] { true, false, false, false, false, false, false, false });//0000 0001
if ((int)obj == 2)
WriteData("M5.0", new bool[] { true, false, false, false, false, false, false, false });//0000 0001

#endregion

}
public void TwoBlock(object obj)
{
if ((int)obj == 1)
WriteData("M4.0", new bool[] { false, true, false, false, false, false, false, false });//0000 0010
if ((int)obj == 2)
WriteData("M5.0", new bool[] { false, true, false, false, false, false, false, false });//0000 0010
}
public void ThreeBlock(object obj)
{
if ((int)obj == 1)
WriteData("M4.0", new bool[] { true, true, false, false, false, false, false, false });//0000 0011
if ((int)obj == 2)
WriteData("M5.0", new bool[] { true, true, false, false, false, false, false, false });//0000 0011
}
public void OverTurnOff(object obj)
{
if ((int)obj == 1)
WriteData("M7.0", true);
if ((int)obj == 2)
WriteData("M7.4", true);
}
public void OverOneBlock(object obj)
{
if ((int)obj == 1)
WriteData("M7.1", true);
if ((int)obj == 2)
WriteData("M7.5", true);
}
public void OverTwoBlock(object obj)
{
if ((int)obj == 1)
WriteData("M7.2", true);
if ((int)obj == 2)
WriteData("M7.6", true);
}
public void OverThreeBlock(object obj)
{
if ((int)obj == 1)
WriteData("M7.3", true);
if ((int)obj == 2)
WriteData("M7.7", true);
}
public void OverGoOn(object obj)
{
if ((int)obj == 1)
WriteData("M8.0", true);
if ((int)obj == 2)
WriteData("M8.4", true);
}

public void OverGoDown(object obj)
{
if ((int)obj == 1)
WriteData("M8.2", true);
if ((int)obj == 2)
WriteData("M8.6", true);
}
public void FlowInite()
{

}
/// <summary>
/// 订单初始化
/// </summary>
@@ -594,7 +508,6 @@ namespace BPASmartClient.MorkF
morkF.TakePlateQueue.Enqueue(new OrderLocInfo()
{
SuborderId = order.MorkOrder.SuborderId,

});
}
//}


+ 38
- 0
BPASmartClient.MorkF/GVL_MorkF.cs View File

@@ -299,6 +299,44 @@ namespace BPASmartClient.MorkF
/// </summary>
public string CurrentOrderId { get; set; }
#endregion


public Dictionary<int,string> StartPassWay { get; set; } = new Dictionary<int, string>()
{
{1,"M3.0" },
{2,"M3.1" },
{3,"M3.2" },
{4,"M3.3" },
{5,"M3.4" },
{6,"M3.5" },
{7,"M3.6" },
{8,"M3.7" },
{9,"M4.0" },
{10,"M4.1" },
{11,"M4.2" },
{12,"M4.3" },
{13,"M4.4" },
{13,"M4.5" },

};

public Dictionary<int, string> PassWayValue { get; set; } = new Dictionary<int, string>()
{
{1,"VW200" },
{2,"VW202" },
{3,"VW204" },
{4,"VW206" },
{5,"VW208" },
{6,"VW210" },
{7,"VW212" },
{8,"VW214" },
{9,"VW216" },
{10,"VW218" },
{11,"VW220" },
{12,"VW222" },
{13,"VW224" },
{13,"VW226" },
};
}
}


+ 38
- 18
BPASmartClient.MorkF/View/DebugView.xaml View File

@@ -47,29 +47,49 @@
</WrapPanel>
</GroupBox>
<StackPanel Orientation="Vertical" Grid.Row="2">
<GroupBox Header="机器人控制" FontSize="15" Foreground="Aqua" VerticalAlignment="Center" Height="95">
<GroupBox Header="配料仓控制" FontSize="15" Foreground="Aqua" VerticalAlignment="Center" Height="95">
<WrapPanel Orientation="Horizontal" Grid.RowSpan="2" VerticalAlignment="Top" Margin="0,5,0,0" >
<Button Content="取锅" Command="{Binding TakePot}" Margin="10,0,10,0"></Button>
<!--<Button Content="取锅复位" Command="{Binding TakePotReset}" Margin="10,0,10,0"></Button>-->
<Button Content="取料" Command="{Binding TakeMaterial}" Margin="10,0,10,0"></Button>
<Button Content="出餐" Command="{Binding OutMeal}" Margin="10,0,10,0"></Button>
<TextBlock Text="通道号" Margin="5,0"/>
<ComboBox ItemsSource="{Binding PassageWays}" Width="120" Margin="5,0"
SelectedIndex="{Binding PassagePosition}"/>
<TextBlock Text="出料量" Margin="5,0"/>
<TextBox Text="{Binding Weight}" Margin="5,0" Width="100"/>
<TextBlock Text="g" Margin="0,0,10,0"/>
<Button Content="出料" Margin="10,0" Command="{Binding OutMaterials}"/>
</WrapPanel>
</GroupBox>

<GroupBox Header="炒锅1" FontSize="15" Foreground="Aqua" VerticalAlignment="Center" Height="140">
<WrapPanel VerticalAlignment="Top" Margin="0,5,0,0">
<Button Content="注油" Command="{Binding AddOil}" Margin="10,0,10,0"></Button>
<Button Content="加热关闭" Command="{Binding TempTurnOff}" Margin="10,0,10,0"></Button>
<Button Content="加热1挡" Command="{Binding OneBlock}" Margin="10,0,10,0"></Button>
<Button Content="加热2挡" Command="{Binding TwoBlock}" Margin="10,0,10,0"></Button>
<Button Content="加热3挡" Command="{Binding ThreeBlock}" Margin="10,0,10,0"></Button>
<Button Content="翻炒机关闭" Command="{Binding OverTurnOff}" Margin="10,0,10,0" Cursor="Hand"></Button>
<Button Content="翻炒机上升" Command="{Binding OverGoOn}" Margin="10,0,15,0" Cursor="Hand"></Button>
<Button Content="翻炒机下降" Command="{Binding OverGoDown}" Margin="10,0,10,0"></Button>
<Button Content="翻炒机1挡" Command="{Binding OverOneBlock}" Margin="10,0,10,0"></Button>
<Button Content="翻炒机2挡" Command="{Binding OverTwoBlock}" Margin="10,0,10,0"></Button>
<Button Content="翻炒机3挡" Command="{Binding OverThreeBlock}" Margin="10,0,10,0"></Button>
</WrapPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<WrapPanel VerticalAlignment="Top" Margin="0,5,0,0">
<Button Content="注油" Command="{Binding AddOil}" Margin="10,0,10,0"></Button>
<Button Content="加热启动" Command="{Binding StartFire}" Margin="10,0,10,0"></Button>
<Button Content="加热停止" Command="{Binding StopFire}" Margin="10,0,10,0"></Button>
<Button Content="搅拌启动" Command="{Binding StartStir}" Margin="10,0,10,0" Cursor="Hand"></Button>
<Button Content="搅拌停止" Command="{Binding StopStir}" Margin="10,0,15,0" Cursor="Hand"></Button>
<Button Content="倒菜启动" Command="{Binding OutFood}" Margin="10,0,15,0" Cursor="Hand"/>
<Button Content="搅拌臂去原点位" Command="{Binding StirArmGoOrigin}" Margin="10,0,10,0"></Button>
<Button Content="搅拌臂去炒制位" Command="{Binding StirArmGoWork}" Margin="10,0,10,0"></Button>
<Button Content="HBOT放盒子到位" Command="{Binding HBOTGoWork}" Margin="10,0,10,0"></Button>
<Button Content="出餐启动" Command="{Binding OutMeal}" Margin="10,0,10,0"></Button>
</WrapPanel>
<WrapPanel Grid.Row="2">
<TextBlock Text="加热挡位:" Margin="10,0,0,0" />
<ComboBox ItemsSource="{Binding lstFire}" Width="80" Margin="10,0,10,0" HorizontalAlignment="Center" VerticalAlignment="Center"
SelectedValue="{Binding FireGear}"/>
<Button Content="设定" Margin="0,0,30,0" Command="{Binding SetFire}"/>
<TextBlock Text="搅拌挡位:" Margin="10,0,0,0" />
<ComboBox ItemsSource="{Binding lstStir}" Width="80" Margin="10,0,10,0" HorizontalAlignment="Center" VerticalAlignment="Center"
SelectedValue="{Binding StirGear}"/>
<Button Content="设定" Margin="0,0,30,0" Command="{Binding SetStir}"/>
</WrapPanel>
</Grid>
</GroupBox>
<GroupBox Header="炒锅2" FontSize="15" Foreground="Aqua" VerticalAlignment="Center" Height="140">
<WrapPanel VerticalAlignment="Top" Margin="0,5,0,0">


+ 83
- 42
BPASmartClient.MorkF/ViewModel/DebugViewModel.cs View File

@@ -13,7 +13,7 @@ namespace BPASmartClient.MorkF.ViewModel
internal class DebugViewModel : ObservableObject
{
public bool SimOrderEnable { get { return General_Config.SimOrderAllow; } set { General_Config.SimOrderAllow = value; OnPropertyChanged(); } }
#region 设备控制
public RelayCommand PlcInite { get; set; }
public RelayCommand SimulateOrder { get; set; }
public RelayCommand MaterialOne { get; set; }
@@ -25,31 +25,64 @@ namespace BPASmartClient.MorkF.ViewModel
public RelayCommand CloaseExhaust { get; set; }
public RelayCommand StartQXOne { get; set; }
public RelayCommand StartQXTwo { get; set; }
#endregion

#region 菜品控制

public RelayCommand ShreddCabbage { get; set; }
public RelayCommand FryPork { get; set; }
public RelayCommand XingBaoGu { get; set; }
#endregion

public RelayCommand TakePot { get; set; }
public RelayCommand TakePotReset { get; set; }
public RelayCommand TakeMaterial { get; set; }
public RelayCommand OutMeal { get; set; }

#region 配料仓控制
public List<string> PassageWays = new List<string>()
{
"通道1",
"通道2",
"通道3",
"通道4",
"通道5",
"通道6",
"通道7",
"通道8",
"通道9",
"通道10",
"通道11",
"通道12",
"通道13",
"通道14",
};
public int PassagePosition { get { return _passagePosition; } set { _passagePosition = value; OnPropertyChanged(); } }
private int _passagePosition;
public int Weight { get { return _weight; } set { _weight = value; OnPropertyChanged(); } }
private int _weight;
public RelayCommand OutMaterials { get; set; }
#endregion

#region 炒锅1
public RelayCommand AddOil { get; set; }
public RelayCommand TempTurnOff { get; set; }
public RelayCommand OneBlock { get; set; }
public RelayCommand TwoBlock { get; set; }
public RelayCommand ThreeBlock { get; set; }
public RelayCommand OverTurnOff { get; set; }
public RelayCommand OverOneBlock { get; set; }
public RelayCommand OverTwoBlock { get; set; }
public RelayCommand OverThreeBlock { get; set; }
public RelayCommand OverGoOn { get; set; }
public RelayCommand OverGoDown { get; set; }
public RelayCommand AutoModel { get; set; }
public RelayCommand ManualModel { get; set; }
public RelayCommand StartFire { get; set; }
public RelayCommand StopFire { get; set; }
public RelayCommand StartStir { get; set; }
public RelayCommand StopStir { get; set; }
public RelayCommand OutFood { get; set; }
public RelayCommand StirArmGoOrigin { get; set; }
public RelayCommand StirArmGoWork { get; set; }
public RelayCommand HBOTGoWork { get; set; }
public RelayCommand OutMeal { get; set; }
public RelayCommand SetFire { get; set; }
public RelayCommand SetStir { get; set; }
public List<int> lstFire { get; set; } = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
public List<int> lstStir { get; set; } = new List<int>() { 1, 2, 3 };
public int FireGear { get { return _fireGear; } set { _fireGear = value; OnPropertyChanged(); } }
private int _fireGear;
public int StirGear { get { return _stirGear; } set { _stirGear = value; OnPropertyChanged(); } }
private int _stirGear;
#endregion


#region 炒锅2
public RelayCommand SecAddOil { get; set; }
public RelayCommand SecTempTurnOff { get; set; }
public RelayCommand SecOneBlock { get; set; }
@@ -63,44 +96,51 @@ namespace BPASmartClient.MorkF.ViewModel
public RelayCommand SecOverGoDown { get; set; }
public RelayCommand SecAutoModel { get; set; }
public RelayCommand SecManualModel { get; set; }
#endregion

public DebugViewModel()
{
#region 设备控制
PlcInite = new RelayCommand(() => { ActionManage.GetInstance.Send("InitCommand"); });

SimulateOrder = new RelayCommand(() => {ActionManage.GetInstance.Send("SimultaorOrder"); });
MaterialOne= new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialOne"); });
SimulateOrder = new RelayCommand(() => { ActionManage.GetInstance.Send("SimultaorOrder"); });
MaterialOne = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialOne"); });
MaterialTwo = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialTwo"); });
MaterialThree = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialThree"); });
MaterialFour = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialFour"); });
MaterialFive = new RelayCommand(() => { ActionManage.GetInstance.Send("MaterialFive"); });
OpenExhaust = new RelayCommand(() => { ActionManage.GetInstance.Send("OpenExhaust"); });
CloaseExhaust = new RelayCommand(() => { ActionManage.GetInstance.Send("CloseExhaust"); });
StartQXOne=new RelayCommand(() => { ActionManage.GetInstance.Send("StartQXOne",1); });
StartQXTwo = new RelayCommand(() => { ActionManage.GetInstance.Send("StartQXTwo",2); });
StartQXOne = new RelayCommand(() => { ActionManage.GetInstance.Send("StartQXOne", 1); });
StartQXTwo = new RelayCommand(() => { ActionManage.GetInstance.Send("StartQXTwo", 2); });
#endregion
ShreddCabbage = new RelayCommand(() => { ActionManage.GetInstance.Send("ShreddCabbage"); });
FryPork = new RelayCommand(() => { ActionManage.GetInstance.Send("FryPork"); });
XingBaoGu = new RelayCommand(() => { ActionManage.GetInstance.Send("XingBaoGu"); });

TakePot = new RelayCommand(() => { ActionManage.GetInstance.Send("TakePot"); });
TakePotReset = new RelayCommand(() => { ActionManage.GetInstance.Send("TakePotReset"); });
TakeMaterial= new RelayCommand(() => { ActionManage.GetInstance.Send("TakeMaterial"); });
OutMeal = new RelayCommand(() => { ActionManage.GetInstance.Send("OutMeal"); });

AddOil = new RelayCommand(() => { ActionManage.GetInstance.Send("AddOil", 1); });
TempTurnOff = new RelayCommand(() => { ActionManage.GetInstance.Send("TakeOff", 1); });
OneBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("OneBlock",1); });
TwoBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("TwoBlock",1); });
ThreeBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("ThreeBlock",1); });
OverTurnOff = new RelayCommand(() => { ActionManage.GetInstance.Send("OverTurnOff",1); });
OverOneBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("OverOneBlock",1); });
OverTwoBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("OverTwoBlock",1); });
OverThreeBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("OverThreeBlock",1); });
OverGoOn = new RelayCommand(() => { ActionManage.GetInstance.Send("OverGoOn",1); });
OverGoDown = new RelayCommand(() => { ActionManage.GetInstance.Send("OverGoDown",1); });
AutoModel = new RelayCommand(()=>{ActionManage.GetInstance.Send("AutoModel",1); });
ManualModel = new RelayCommand(() => { ActionManage.GetInstance.Send("ManualModel",1); });

#region 配料仓控制
OutMaterials = new RelayCommand(() => { ActionManage.GetInstance.Send("OutMaterials" ,new List<int> { PassagePosition,Weight } ); });
#endregion


#region 炒锅1
AddOil = new RelayCommand(() => { ActionManage.GetInstance.Send("AddOil", 1); });//加油
StartFire = new RelayCommand(() => { ActionManage.GetInstance.Send("StartFire"); });//加热启动
StopFire = new RelayCommand(() => { ActionManage.GetInstance.Send("StopFire"); });//加热停止
StartStir = new RelayCommand(() => { ActionManage.GetInstance.Send("StartStir"); });//搅拌启动
StopStir = new RelayCommand(() => { ActionManage.GetInstance.Send("StopStir"); });//搅拌停止
OutFood = new RelayCommand(() => { ActionManage.GetInstance.Send("OutFood"); });//倒菜启动
StirArmGoOrigin = new RelayCommand(() => { ActionManage.GetInstance.Send("StirArmGoOrigin"); });//搅拌臂去原点位
StirArmGoWork = new RelayCommand(() => { ActionManage.GetInstance.Send("StirArmGoWork"); });//搅拌臂去炒制位
HBOTGoWork = new RelayCommand(() => { ActionManage.GetInstance.Send("HBOTGoWork"); });//放盒子到位
OutMeal = new RelayCommand(() => { ActionManage.GetInstance.Send("OutMeal"); });//出餐启动
SetFire = new RelayCommand(() => { ActionManage.GetInstance.Send("SetFire", new List<int> { FireGear }); });//加热挡位设定
SetStir = new RelayCommand(() => { ActionManage.GetInstance.Send("SetStir", new List<int> { StirGear }); });//搅拌挡位设定
#endregion



#region 炒锅2
SecAddOil = new RelayCommand(() => { ActionManage.GetInstance.Send("AddOil", 2); });
SecTempTurnOff = new RelayCommand(() => { ActionManage.GetInstance.Send("TakeOff", 2); });
SecOneBlock = new RelayCommand(() => { ActionManage.GetInstance.Send("OneBlock", 2); });
@@ -114,7 +154,8 @@ namespace BPASmartClient.MorkF.ViewModel
SecOverGoDown = new RelayCommand(() => { ActionManage.GetInstance.Send("OverGoDown", 2); });
SecAutoModel = new RelayCommand(() => { ActionManage.GetInstance.Send("AutoModel", 2); });
SecManualModel = new RelayCommand(() => { ActionManage.GetInstance.Send("ManualModel", 2); });
#endregion
}
}
}

+ 6
- 1
BPASmartClient.MorkMOC/BPASmartClient.MorkMOC.csproj View File

@@ -1,11 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Library</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BPASmartClient.Device\BPASmartClient.Device.csproj" />
</ItemGroup>


+ 23
- 4
BPASmartClient.MorkMOC/Control_MorkMOC.cs View File

@@ -1,6 +1,7 @@
using BPA.Message.Enum;
using BPASmartClient.Device;
using BPASmartClient.EventBus;
using BPASmartClient.Helper;
using BPASmartClient.Model;
using System;
using System.Collections.Generic;
@@ -13,15 +14,15 @@ namespace BPASmartClient.MorkMOC
{
public class Control_MorkMOC : BaseDevice
{
public override global::BPA.Message.Enum.DeviceClientType DeviceType { get { return BPA.Message.Enum.DeviceClientType.TMC_MT; } }

GVL_MorkMOC morkMoc = new GVL_MorkMOC();

PolymerBatching polymerBatching = new PolymerBatching();

//放大倍数
const int expand = 10;

public override DeviceClientType DeviceType => throw new NotImplementedException();

public override void DoMain()
{
ServerInit();
@@ -178,7 +179,25 @@ namespace BPASmartClient.MorkMOC

public override void SimOrder()
{
throw new NotImplementedException();
ActionManage.GetInstance.Register(new Action<object>((o) =>
{
if (o == null) return;
if(o is LocalRecipe recipe)
{
Dictionary<int, int> OrderPushes = new Dictionary<int, int>();
foreach(var item in recipe.localMaterails)
{
OrderPushes.Add(Convert.ToInt32(item.MaterialPosition), Convert.ToInt32(item.MaterialWeight));
}
morkMoc.morkOrderPushes.Enqueue(new OrderLocInfo()
{
GoodName = recipe.RecipeName,
SuborderId = Guid.NewGuid().ToString(),
GoodPushes = OrderPushes
});
}
}),"MakeGoods");
}

public override void Stop()


+ 55
- 0
BPASmartClient.MorkMOC/Model/LocalMaterail.cs View File

@@ -0,0 +1,55 @@
using Microsoft.Toolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BPASmartClient.MorkMOC
{
public partial class LocalMaterail:ObservableObject
{
/// <summary>
/// 物料ID
/// </summary>
[ObservableProperty]
private string? _materialID;
/// <summary>
/// 物料本地名称
/// </summary>
[ObservableProperty]
private string? _materialName;
/// <summary>
/// 物料位置
/// </summary>
[ObservableProperty]
private int? _materialPosition;
/// <summary>
/// 物料重量
/// </summary>
[ObservableProperty]
private string? _materialWeight;


}

public partial class LocalRecipe:ObservableObject
{
/// <summary>
/// 配方ID
/// </summary>
[ObservableProperty]
private string? _recipeID;
/// <summary>
/// 配方名称
/// </summary>
[ObservableProperty]
private string? _recipeName;
/// <summary>
/// 原料集合
/// </summary>
public ObservableCollection<LocalMaterail> localMaterails { get; set; } = new ObservableCollection<LocalMaterail>();
}
}

+ 3
- 0
BPASmartClient.MorkMOC/OrderLocInfo.cs View File

@@ -10,6 +10,9 @@ namespace BPASmartClient.MorkMOC
public string SuborderId { get; set; }
public ushort RecipeNumber { get; set; }
public string GoodName { get; set; }
/// <summary>
/// 物料位置,物料重量
/// </summary>
public Dictionary<int, int> GoodPushes { get; set; }
}



+ 2
- 0
BPASmartClient.MorkS/Control_Morks.cs View File

@@ -271,9 +271,11 @@ namespace BPASmartClient.MorkS
{
mORKS.doOrderEvents.Add(order);
if (order.MorkOrder.GoodBatchings == null) return;
if (mORKS.HistorySuborderId.Contains(order.MorkOrder.SuborderId)) return;
OrderCount++;
OrderChange(order.MorkOrder.SuborderId, ORDER_STATUS.WAIT);
DeviceProcessLogShow($"接收到{OrderCount}次订单,订单ID:{order.MorkOrder.SuborderId}");
mORKS.HistorySuborderId.Add(order.MorkOrder.SuborderId);
foreach (var item in order.MorkOrder.GoodBatchings)
{
var res = orderMaterialDelivery?.BatchingInfo?.FirstOrDefault(p => p.BatchingId == item.BatchingId);


+ 1
- 0
BPASmartClient.MorkS/GVL_MORKS.cs View File

@@ -12,6 +12,7 @@ namespace BPASmartClient.MorkS
{
public class GVL_MORKS : IStatus
{
public List<string> HistorySuborderId { get; set; } = new List<string>();
/// <summary>
/// 机器人取面
/// PLC -> M0.3


+ 4
- 0
BPASmartClient.MorkTM/Model/LocalTeaWithMilkConfig.cs View File

@@ -29,6 +29,10 @@ namespace Model
public int MaterialID { get { return _materialID; } set { _materialID = value; OnPropertyChanged(); } }
private int _materialID =1;
/// <summary>
/// 物料本地名称
/// </summary>
public string MaterialName;
/// <summary>
/// 物料位置
/// </summary>
public string Material { get { return _material; } set { _material = value; OnPropertyChanged(); } }


+ 9
- 10
BPASmartClient/App.config View File

@@ -6,20 +6,19 @@
<!--<add key="ClientId" value="43"/>-->
<add key="IsEnableTest" value="false"/>

<!--测试环境--><!--
<add key="apollouri" value="http://10.2.1.21:28080/"/>
<add key="AppId" value="test1_HostComputer"/>
<add key ="Namespaces" value="DEV.test1.Config"/>-->

<!--测试环境-->
<!--<add key="apollouri" value="http://10.2.1.21:28080/"/>
<add key="AppId" value="test1_HostComputer"/>
<add key ="Namespaces" value="DEV.test1.Config"/>-->
<!--开发环境-->
<!--<add key="apollouri" value="http://47.108.65.220:28080/"/>
<add key="AppId" value="HostComputer"/>
<add key ="Namespaces" value="DEV.Config"/>-->
<add key="apollouri" value="http://10.2.1.21:28080/"/>
<add key="AppId" value="HostComputer"/>
<add key ="Namespaces" value="DEV.Config"/>

<!--正式环境-->
<add key="apollouri" value="http://47.108.65.220:28080/"/>
<!--<add key="apollouri" value="http://47.108.65.220:28080/"/>
<add key="appid" value="hostcomputer"/>
<add key ="namespaces" value="test1.config"/>
<add key ="namespaces" value="test1.config"/>-->

<!--阿里云上报启动方式:API 或者 LOCAL-->
<!--API :通过客户端ID,调用接口查询“设备连接信息”-->


Loading…
Cancel
Save