惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

A
About on SuperTechFans
Y
Y Combinator Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
aimingoo的专栏
aimingoo的专栏
I
InfoQ
C
Check Point Blog
IT之家
IT之家
MyScale Blog
MyScale Blog
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
Last Week in AI
Last Week in AI
GbyAI
GbyAI
P
Proofpoint News Feed
量子位
Stack Overflow Blog
Stack Overflow Blog
Microsoft Azure Blog
Microsoft Azure Blog
月光博客
月光博客
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
B
Blog
T
The Blog of Author Tim Ferriss
H
Help Net Security
云风的 BLOG
云风的 BLOG

博客园 - 曾伟

不干胶、热敏打印 net core quartz调度 warp打包 nssm部署到windowsservice c# webapi 过滤器token、sign认证、访问日志 c# NPOI文件操作 c# ini文件操作 WCF多种调用方式兼容 网页打印javascript:window.print() window.showModalDialog弹出对话框刷新问题 ASP.NET] 选择文件夹的对话框 常用SQL语句书写技巧 控制同一exe程序打开多次 - 曾伟 - 博客园 IIS6 MMC检测到此管理单元发生一个错误,建议您关闭并重新启动mmc 在上传文件时限制上传文件的大小,并捕捉超过文件大小限制的 - 曾伟 - 博客园 Lucene的例子 javascript 获取标签具体位置 - 曾伟 - 博客园 JavaScript实现类,有多种方法。 Javascript实现截图功能(代码) 终端服务器超出了最大允许连接数 DBCC CHECKDB 数据库或表修复
wpf 滚屏数据显示
曾伟 · 2020-05-20 · via 博客园 - 曾伟

近期库房想在出库存放区划分货位存放不同客户拣货后的商品数据。
同时需要在货位摆放屏幕以便显示当前货位被那个客户拣货占用,及商品信息、拣货状态等

由于独立项目,数据来源于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"

MaterialDesign