wndong 2020-05-20
近期库房想在出库存放区划分货位存放不同客户拣货后的商品数据。
同时需要在货位摆放屏幕以便显示当前货位被那个客户拣货占用,及商品信息、拣货状态等
由于独立项目,数据来源于api接口,所以只是一个客户端轮播即可。故拿wpf来试试demo
设计为:
1、一个主界面为控制台控制第2,3,....屏显示不同客户(货位)的信息去请求不同的数据
2、第2、3...屏的轮播数据展示
实现:
1、创建项目net下都一致,略过
2、控制不同屏幕轮播不同信息,只需要相关配置即可,这里略过
3、显示轮播信息这里使用一个按钮跳转来完成
<Button Grid.Column="2" Content="滚动" Name="btn_scroll" Width="100" Click="btn_Scroll_Click"/>
跳转到次屏
private void btn_Scroll_Click(object sender, RoutedEventArgs e)
{
ScrollWindow w = new ScrollWindow();
MultipScreenManager.ShowInScreen(w);
}这里使用到一个主次屏管理,引用了某一位博主(当前忘记了是哪一位,有知道的通知我补登)的MultipScreenManager
public static class MultipScreenManager
{
#region Property
internal static Screen[] AllScreens
{
get
{
return Screen.AllScreens;
}
}
internal static Screen PrimaryScreen
{
get
{
return Screen.PrimaryScreen;
}
}
internal static IEnumerable<Screen> MinorScreens
{
get
{
return Screen.AllScreens.Where(o => o.Primary == false);
}
}
internal static Screen FirstMinorScreen
{
get
{
return MinorScreens.FirstOrDefault();
}
}
#endregion Property
#region Method
public static void ShowInScreen(this System.Windows.Window win)
{
SetScreen(win);
win.Show();
}
public static void ShowDialogInScreen(this System.Windows.Window win)
{
SetScreen(win);
win.ShowDialog();
}
private static void SetScreen(System.Windows.Window win)
{
var attr = win.GetType().GetCustomAttributes(typeof(MultipScreenAttribute), false).FirstOrDefault(o => o is MultipScreenAttribute);
int index = 0;
bool ingoreOperation = false;
WindowStartupLocationInScreen inScreen = WindowStartupLocationInScreen.CenterScreen;
if (attr != null)
{
var temp = (attr as MultipScreenAttribute);
index = temp.Index;
inScreen = temp.InScreen;
ingoreOperation = temp.IngoreMinorScreenError;
}
Screen screen = PrimaryScreen;
if (index == 1 && FirstMinorScreen != null)
{
screen = FirstMinorScreen;
}
else if (index > 1 && index < MinorScreens.Count())
{
screen = MinorScreens.ElementAt(index);
}
else if (index > 0 && index >= MinorScreens.Count() && ingoreOperation)
{
return;
}
switch (inScreen)
{
case WindowStartupLocationInScreen.CenterScreen:
SetWindowInScreenCenter(win, screen);
break;
case WindowStartupLocationInScreen.Manual:
SetWindowInScreenManual(win, screen);
break;
}
}
private static void SetWindowInScreenCenter(System.Windows.Window win, Screen screen)
{
win.Top = screen.WorkingArea.Y + (screen.WorkingArea.Height - win.Height) / 2;
win.Left = screen.WorkingArea.X + (screen.WorkingArea.Width - win.Width) / 2;
}
private static void SetWindowInScreenManual(System.Windows.Window win, Screen screen)
{
win.Top = screen.WorkingArea.Y;
win.Left = screen.WorkingArea.X;
}
#endregion Method
}
[AttributeUsage(AttributeTargets.Class)]
public class MultipScreenAttribute:Attribute
{
public MultipScreenAttribute(ScreenType type = ScreenType.Primary, WindowStartupLocationInScreen inScreen = WindowStartupLocationInScreen.CenterScreen)
: this((int)type, inScreen)
{
}
public MultipScreenAttribute(int index = 0, WindowStartupLocationInScreen inScreen = WindowStartupLocationInScreen.CenterScreen)
{
Index = index;
InScreen = inScreen;
}
/// <summary>
/// 在窗体初始化显示的位置
/// </summary>
public WindowStartupLocationInScreen InScreen { get; private set; }
/// <summary>
/// 屏幕索引, 0为主屏,1+为次屏
/// </summary>
public int Index { get; private set; }
/// <summary>
/// 当任何指定次屏没有找到时,如果该值为TRUE,则忽略这个页面的显示,否则将显示在主屏
/// </summary>
public bool IngoreMinorScreenError { get; private set; }
}
public enum ScreenType
{
/// <summary>
/// 主屏
/// </summary>
Primary = 0,
/// <summary>
/// 次屏
/// </summary>
Minor = 1,
}
public enum WindowStartupLocationInScreen
{
Manual = 0,
CenterScreen = 1,
}次屏ui:
<Window x:Class="WpfApp1.ScrollWindow"
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:WpfApp1"
mc:Ignorable="d"
Title="ScrollWindow"
Loaded="ScrollWindow_Loaded" >
<!--MouseEnter="ScrollWindow_MouseEnter" MouseLeave="ScrollWindow_MouseLeave" MouseMove="ScrollWindow_MouseMove"-->
<Window.Resources>
<Storyboard x:Key="storyboard">
<DoubleAnimation Duration="0:0:1" From="300" To="0" Storyboard.TargetName="stackPanel" Storyboard.TargetProperty="RenderTransform.Y"/>
</Storyboard>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="170"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.RowSpan="2" Grid.Column="0" x:Name="txtHHName" Content="张三" FontWeight="Bold" FontSize="50" VerticalAlignment="Center" HorizontalAlignment="Center" />
<Label Grid.Row="0" Grid.Column="1" x:Name="txtContract" Content="1003175664863" FontSize="30"></Label>
<Label Grid.Row="1" Grid.Column="1" x:Name="txtAddress" Content="北京市大兴区旧宫镇 住总万科广场C座11层" FontSize="30"></Label>
</Grid>
<ScrollViewer Grid.Row="1" Name="scrollViewer" HorizontalScrollBarVisibility="Hidden"
HorizontalContentAlignment="Stretch"
VerticalScrollBarVisibility="Hidden"
VerticalContentAlignment="Stretch">
<Border>
<StackPanel x:Name="stackPanel" Margin="5 5 5 5" >
<StackPanel.RenderTransform>
<TranslateTransform />
</StackPanel.RenderTransform>
<!--<Label x:Name="lab_text" FontSize="20"></Label>-->
<DataGrid x:Name="orderItem_list" ItemsSource="{Binding Results,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"
IsReadOnly="True" AutoGenerateColumns="False" GridLinesVisibility="None"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch"
BorderThickness="0" FontSize="25" EnableRowVirtualization="false" EnableColumnVirtualization="False"
CanUserAddRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False" AlternationCount="2" HeadersVisibility="None">
<DataGrid.RowHeaderStyle>
<Style TargetType="DataGridRowHeader">
<Setter Property="FontSize" Value="30"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</DataGrid.RowHeaderStyle>
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="White"></Setter>
</Trigger>
<Trigger Property="ItemsControl.AlternationIndex" Value="1">
<Setter Property="Background" Value="WhiteSmoke"></Setter>
</Trigger>
</Style.Triggers>
<Setter Property="Height" Value="40"></Setter>
</Style>
</DataGrid.RowStyle>
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding StatusName}" Value="未拣货">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusName}" Value="已拣货">
<Setter Property="Foreground" Value="SlateBlue" />
</DataTrigger>
<DataTrigger Binding="{Binding StatusName}" Value="已复核">
<Setter Property="Foreground" Value="LightGreen" />
</DataTrigger>
</Style.Triggers>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Sku" Binding="{Binding SkuNo}" Width="160"></DataGridTextColumn>
<DataGridTextColumn Header="名称" Binding="{Binding SkuName}" Width="300"></DataGridTextColumn>
<DataGridTextColumn Header="数量" Binding="{Binding Amount}" Width="100"></DataGridTextColumn>
<DataGridTextColumn Header="状态" Binding="{Binding StatusName}" Width="120"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Border>
</ScrollViewer>
</Grid>
</Window>次屏逻辑交互:
/// <summary>
/// ScrollWindow.xaml 的交互逻辑
/// </summary>
[MultipScreen(1, WindowStartupLocationInScreen.CenterScreen)]
public partial class ScrollWindow : Window
{
private System.Timers.Timer _timer;
private ScrollWindowDataContextModel _data;
private int _index;
private int PageSize = 21;
private double Interval = 5000;
private int pageCount;
private Storyboard _storyboard;
private int typeBatch = 1;
public ScrollWindow()
{
AutoScreen();//需要设置高度、宽度才会遵循MultipScreen的指定显示屏显示
//this.Width = 800;
//this.Height = 500;
InitializeComponent();
this.KeyDown += ScrollWindow_KeyDown;
_data = GetAllData();
txtHHName.Content = $"{_data.HHName}";
txtContract.Content = $"合同号:{_data.ContractCode}";
txtAddress.Content = $"地址:{_data.Address}";
}
private void ScrollWindow_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)//Esc键
{
this.Close();
}
}
private void ScrollWindow_Loaded(object sender, RoutedEventArgs e)
{
//AutoScreen();
if (_timer == null)
{
_storyboard = (Storyboard)this.FindResource("storyboard");
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
pageCount = (_data.Results.Count() + PageSize - 1) / PageSize;
_index= 1;
Dispatcher.BeginInvoke(new Action(() =>
{
stackPanel.RenderTransform = new TranslateTransform(0, 0);
}));
ShowData();
});
_timer = new System.Timers.Timer();
_timer.Interval = Interval;
_timer.Elapsed += Action;
_timer.Start();
}
}
private void AutoScreen()
{
this.WindowState = System.Windows.WindowState.Normal;
this.WindowStyle = System.Windows.WindowStyle.None;
this.ResizeMode = System.Windows.ResizeMode.NoResize;
//this.Topmost = true;
if (System.Windows.Forms.Screen.AllScreens.Where(o => o.Primary == false).Count() == 0)
{
this.Left = 0.0;
this.Top = 0.0;
this.Width = System.Windows.SystemParameters.WorkArea.Width;//.PrimaryScreenWidth;
this.Height = System.Windows.SystemParameters.WorkArea.Height;//.PrimaryScreenHeight;
}
else
{
var minorScreen = System.Windows.Forms.Screen.AllScreens.Where(o => o.Primary == false).First();
this.Left = 0.0;
this.Top = 0.0;
var name = minorScreen.DeviceName;
this.Width = minorScreen.WorkingArea.Width;
this.Height = minorScreen.WorkingArea.Height;
}
}
private ScrollWindowDataContextModel GetAllData(int type=0)
{
ScrollWindowDataContextModel allData = new ScrollWindowDataContextModel();
allData.HHName = "赵四";
allData.ContractCode = "1003175664863";
allData.Address = "北京市大兴区旧宫镇 住总万科广场C座11层";
List<WindowScrollResultModel> rList = new List<WindowScrollResultModel>();
for (int i = 0; i <= 100; i++)
{
WindowScrollResultModel r = new WindowScrollResultModel()
{
SkuNo = $"sku{i.ToString()}-{type}",
SkuName = $"sku{i.ToString()}-{type}",
Amount = i,
StatusName = i.ToString().Contains("3") ? "未拣货" : i % 2 == 0 ? "已拣货" : "已复核",
};
rList.Add(r);
}
allData.Results = new ObservableCollection<WindowScrollResultModel>(rList);
return allData;
}
private void Action(object sender, ElapsedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() =>
{
stackPanel.RenderTransform = new TranslateTransform(0, 0);
_storyboard.Begin();
}));
_index++;
if (_index > pageCount)
{
// 可以在这循环完一轮后重新加载数据
_data = GetAllData(typeBatch);
typeBatch++;
_index = 1;
}
ShowData();
}
private void ShowData()
{
Dispatcher.BeginInvoke(new Action(() =>
{
List<WindowScrollResultModel> dataList = GetPageData(_index);
StringBuilder sbMsg = new StringBuilder();
dataList.ForEach(x=> {
sbMsg.Append($"{x.SkuNo} {x.SkuName} {x.Amount} {x.StatusName} \r\n");
});
//lab_text.Content = sbMsg.ToString() ;
orderItem_list.ItemsSource = dataList;
}));
}
private List<WindowScrollResultModel> GetPageData(int pageIndex)
{
if (_data != null)
{
return _data.Results.Skip((pageIndex - 1) * PageSize).Take(PageSize).ToList();
}
return null;
}
private void ScrollWindow_MouseEnter(object sender, MouseEventArgs e)
{
_timer.Stop();
}
private void ScrollWindow_MouseLeave(object sender, MouseEventArgs e)
{
_timer.Start();
}
private void ScrollWindow_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
this.DragMove();
//AutoScreen();
}
}
}
public class ScrollWindowDataContextModel : NotificationObject
{
public string _HHName;
public string HHName
{
get => _HHName; set { _HHName = value; RaisePropertyChanged("HHName"); }
}
public string _ContractCode;
public string ContractCode
{
get => _ContractCode; set { _ContractCode = value; RaisePropertyChanged("ContractCode"); }
}
public string _Address;
public string Address
{
get => _Address; set { _Address = value; RaisePropertyChanged("Address"); }
}
public ObservableCollection<WindowScrollResultModel> results;
public ObservableCollection<WindowScrollResultModel> Results
{
get => results; set { results = value; RaisePropertyChanged("Results"); }
}
}
public class WindowScrollResultModel
{
public string SkuNo { get; set; }
public string SkuName { get; set; }
public int Amount { get; set; }
public string StatusName { get; set; }
}注意点:
让次屏全屏显示时让width、height=获取到的屏幕大小
开启timer设置间隔时间轮播,默认从第一页开始,设定每屏幕可轮播的行数,到最后一页后重新从第一页轮播
也可以开启鼠标经过轮播体时暂停,离开时继续:MouseEnter="ScrollWindow_MouseEnter" MouseLeave="ScrollWindow_MouseLeave"
Storyboard的DoubleAnimation设置属性控制进入轮播的进入效果及位置等
需要ui好看点,可以引入皮肤库,这这里使用了:MaterialDesign
只需要在app.xaml中增加配置:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml"></ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" ></ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml"></ResourceDictionary>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml"></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>然后在使用页面引入:xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"