wpf之Popup弹出自定义输入"键盘"

时间:2024-04-04 20:53:39

    在很多工厂的信息化MES系统中,车间的采集数据的机器是触摸屏电脑(工厂环境所限,用外接鼠标键盘反而不方便)。

由于没有外接键盘,所以用户无法像坐在办公室一样,用鼠标键盘进行录入信息。

这时我们可以用wpf的Popup控件,当点击一个"文本框"时,弹出一个自定义的键盘(UserControl),实现如下图效果:

wpf之Popup弹出自定义输入"键盘"

 

自定义用户控件(UserControl),"键盘":

Xaml:

wpf之Popup弹出自定义输入"键盘"wpf之Popup弹出自定义输入"键盘"
<UserControl x:Class="PopupDemo.NumericKeyboard"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d">
    <UserControl.Resources>
        <Style x:Key="btnNum" TargetType="{x:Type Button}">
            <!--<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>-->
            <!--<Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush EndPoint="0,1" StartPoint="0,0">
                        <GradientStop Color="#F3F3F3" Offset="0"/>
                        <GradientStop Color="#EBEBEB" Offset="0.5"/>
                        <GradientStop Color="#DDDDDD" Offset="0.5"/>
                        <GradientStop Color="#CDCDCD" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>-->
            <!--<Setter Property="BorderBrush" Value="#FF707070"/>-->
            <!--<Setter Property="BorderThickness" Value="1"/>-->
            <!--<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>-->
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <!--<Setter Property="Height" Value="64" />
            <Setter Property="Width" Value="104" />-->
            <!--<Setter Property="Padding" Value="10"/>-->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="border" BorderBrush="#FF474747" BorderThickness="1" CornerRadius="6">
                            <!--<Border.Effect>
                                <DropShadowEffect BlurRadius="1" ShadowDepth="1" Opacity="0.27"/>
                            </Border.Effect>-->
                            <Border.Background>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFCCCCCC"/>
                                    <GradientStop Color="WhiteSmoke" Offset="1"/>
                                </LinearGradientBrush>
                            </Border.Background>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="#FF565656"  TextElement.FontSize="24" />
                            <!--<TextBlock TextWrapping="Wrap" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="21.333" Foreground="#FF565656"/>-->
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Background" TargetName="border">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FFFF7500"/>
                                            <GradientStop Color="#FFFFC547" Offset="1"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="btnFunc" TargetType="{x:Type Button}">
            <!--<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>-->
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <!--<Setter Property="Padding" Value="1"/>-->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="border" BorderBrush="#FF565656" BorderThickness="1" CornerRadius="6">
                            <Border.Background>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFFFC547" Offset="1"/>
                                    <GradientStop Color="#FFF77202"/>
                                </LinearGradientBrush>
                            </Border.Background>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White" TextElement.FontSize="24"/>
                            <!--<TextBlock TextWrapping="Wrap" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="21.333"/>-->
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Background" TargetName="border">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="Gray" Offset="1"/>
                                            <GradientStop Color="#FF2D2D2D" Offset="0"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style TargetType="{x:Type ToggleButton}">
            <!--<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
            <Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>-->
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <!--<Setter Property="Padding" Value="1"/>-->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Border x:Name="border" BorderBrush="#FF565656" BorderThickness="1" CornerRadius="6">
                            <Border.Background>
                                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                    <GradientStop Color="#FFFFC547" Offset="1"/>
                                    <GradientStop Color="#FFF77202"/>
                                </LinearGradientBrush>
                            </Border.Background>
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White" TextElement.FontSize="24"/>
                            <!--<TextBlock TextWrapping="Wrap" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontSize="21.333"/>-->
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="False">
                                <Setter Property="Background" TargetName="border">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="Gray" Offset="1"/>
                                            <GradientStop Color="#FF2D2D2D" Offset="0"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Button Margin="2" Grid.Column="0" Grid.Row="0" Content="1" x:Name="button1" Click="button1_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="1" Grid.Row="0" Content="2" x:Name="button2" Click="button2_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="2" Grid.Row="0" Content="3" x:Name="button3" Click="button3_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="0" Grid.Row="1" Content="4" x:Name="button4" Click="button4_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="1" Grid.Row="1" Content="5" x:Name="button5" Click="button5_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="2" Grid.Row="1" Content="6" x:Name="button6" Click="button6_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="0" Grid.Row="2" Content="7" x:Name="button7" Click="button7_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="1" Grid.Row="2" Content="8" x:Name="button8" Click="button8_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="2" Grid.Row="2" Content="9" x:Name="button9" Click="button9_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="1" Grid.Row="3" Content="0" x:Name="button0" Click="button0_Click" Style="{StaticResource btnNum}"/>
        <Button Margin="2" Grid.Column="0" Grid.Row="3" Content="清零" x:Name="btnMin" Click="btnMin_Click" Style="{StaticResource btnFunc}" />
        <Button Margin="2" Grid.Column="2" Grid.Row="3" Content="确认" x:Name="btnClose" Click="btnClose_Click"  Style="{StaticResource btnFunc}" />
    </Grid>
</UserControl>
View Code

 

C#:

wpf之Popup弹出自定义输入"键盘"wpf之Popup弹出自定义输入"键盘"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace PopupDemo
{
    /// <summary>
    /// NumericKeyboard.xaml 的交互逻辑
    /// </summary>
    public partial class NumericKeyboard : UserControl
    {
        public NumericKeyboard()
        {
            InitializeComponent();
        }
        public bool HasMaxValue
        {
            get { return (bool)GetValue(HasMaxValueProperty); }
            set { SetValue(HasMaxValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HasMaxValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HasMaxValueProperty =
            DependencyProperty.Register("HasMaxValue", typeof(bool), typeof(NumericKeyboard), new UIPropertyMetadata(true));



        public int MaxValue
        {
            get { return (int)GetValue(MaxValueProperty); }
            set { SetValue(MaxValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxValueProperty =
            DependencyProperty.Register("MaxValue", typeof(int), typeof(NumericKeyboard), new UIPropertyMetadata(0));



        public int Value
        {
            get { return (int)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Value.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(int), typeof(NumericKeyboard), new UIPropertyMetadata(0));



        public bool IsChecked
        {
            get { return (bool)GetValue(IsCheckedProperty); }
            set { SetValue(IsCheckedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsChecked.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsCheckedProperty =
            DependencyProperty.Register("IsChecked", typeof(bool), typeof(NumericKeyboard), new UIPropertyMetadata(false));


        private void btnMin_Click(object sender, RoutedEventArgs e)
        {
            //if (Item != null && Item.Quantity1 > 0)
            //{
            //    Item.Quantity2 = Item.Quantity1;
            //}
            Value = 0;
        }

        private void AddNumber(int num)
        {
            //if (Item != null)
            //{
            //    int cnt = Item.Quantity2 * 10 + num;
            //    if (Item.Quantity1 > 0 && cnt > Item.Quantity1)
            //    {
            //        Item.Quantity2 = Item.Quantity1;
            //    }
            //    else
            //    {
            //        Item.Quantity2 = cnt;
            //    }
            //}
            if (HasMaxValue)
            {
                Value = Math.Min(MaxValue, Value * 10 + num);
            }
            else
            {
                Value = Value * 10 + num;
            }
        }


        private void button2_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(2);
        }

        private void button3_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(3);
        }

        private void button4_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(4);
        }

        private void button5_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(5);
        }

        private void button6_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(6);
        }

        private void button7_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(7);
        }

        private void button8_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(8);
        }

        private void button9_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(9);
        }

        private void button0_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(0);
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            AddNumber(1);
        }

        private void btnClose_Click(object sender, RoutedEventArgs e)
        {
            IsChecked = false;
        }

    }
}
View Code

 

主窗体:

Xaml:

wpf之Popup弹出自定义输入"键盘"wpf之Popup弹出自定义输入"键盘"
<Window x:Class="PopupDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:local="clr-namespace:PopupDemo"
        Title="MainWindow" Width="700" Height="600" WindowStartupLocation="CenterScreen"  DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Window.Resources>
        <Style TargetType="{x:Type Button}" x:Key="rightButton">
            <Setter Property="Margin" Value="5" />
            <Setter Property="Padding" Value="10" />
            <!--<Setter Property="FontSize" Value="20" />
            <Setter Property="Foreground" Value="White" />-->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" CornerRadius="3,13,3,13" Padding="{TemplateBinding Padding}">
                            <Border.Background>
                                <SolidColorBrush Color="#FF6C6C6C" />
                            </Border.Background>
                            <ContentPresenter x:Name="content" HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.FontSize="20" TextElement.Foreground="White" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="border" Property="Background" Value="#FF518CB1" />
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter TargetName="content" Property="TextElement.Foreground" Value="Gray" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="RadioButtonStyle" TargetType="{x:Type RadioButton}">
            <!--<Setter Property="Margin" Value="5" />-->
            <!--<Setter Property="FontSize" Value="20" />-->
            <!--<Setter Property="Foreground" Value="White" />-->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type RadioButton}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" CornerRadius="4" Background="Transparent"  Padding="10,2" x:Name="PART_Background">
                            <ContentPresenter x:Name="PART_Content" VerticalAlignment="Center" TextElement.Foreground="Black" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter TargetName="PART_Background" Property="Background">
                                    <Setter.Value>
                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                                            <GradientStop Color="#FFFFC547" Offset="1"/>
                                            <GradientStop Color="#FFF77202"/>
                                        </LinearGradientBrush>
                                    </Setter.Value>
                                </Setter>
                                <Setter TargetName="PART_Content" Property="TextElement.Foreground" Value="White" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <DockPanel DockPanel.Dock="Right" Margin="0,40,0,0" Width="120" LastChildFill="False">
            <Button x:Name="btnShow" Content="Show" DockPanel.Dock="Top" Margin="0,40,0,0" Click="btnShow_Click"  Style="{StaticResource ResourceKey=rightButton}" />
            <RadioButton x:Name="btnTerminalNo" DockPanel.Dock="Top" Margin="0,40,0,0"  Style="{StaticResource RadioButtonStyle}">
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="终端编号" FontSize="20" TextAlignment="Center"/>
                    <Popup StaysOpen="False" DockPanel.Dock="Bottom" IsOpen="{Binding Path=IsChecked, RelativeSource={RelativeSource FindAncestor, AncestorType=RadioButton, AncestorLevel=1}}" PopupAnimation="Scroll"  AllowsTransparency="True">
                        <Border Background="White" BorderBrush="Black" BorderThickness="1" Padding="4" Width="360" Height="280">
                            <local:NumericKeyboard HasMaxValue="True" MaxValue="9999" IsChecked="{Binding Path=IsChecked, RelativeSource={RelativeSource FindAncestor, AncestorType=RadioButton, AncestorLevel=1}, Mode=TwoWay}" Value="{Binding Path=TerminalNo, Mode=TwoWay}" />
                        </Border>
                    </Popup>
                    <Border Background="Gray"  CornerRadius="5" BorderBrush="Black" BorderThickness="2" Padding="5" Margin="0,0,0,5" HorizontalAlignment="Stretch">
                        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" FontWeight="Bold" FontSize="32" Text="{Binding Path=TerminalNo}" />
                    </Border>
                </StackPanel>
            </RadioButton>
        </DockPanel>
    </Grid>
</Window>
View Code

 

C#:

wpf之Popup弹出自定义输入"键盘"wpf之Popup弹出自定义输入"键盘"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace PopupDemo
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window,INotifyPropertyChanged
    {
        private int terminalNo;

        public int TerminalNo
        {
            get { return terminalNo; }
            set 
            {
                if(value!=terminalNo)
                {
                    terminalNo = value;
                    OnPropertyChanged("TerminalNo");
                }
            }
        }
        

        public MainWindow()
        {
            InitializeComponent();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private void btnShow_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(string.Format("终端编号的值为{0}", TerminalNo));
        }
    }
}
View Code

 

验证输入后,绑定TextBlock的Text属性上值是否真的变化了:

wpf之Popup弹出自定义输入"键盘"

 

总结:

1.Popup控件永远不会自动显示,为了显示Popup控件必须设置IsOpen属性。

2.默认情况下,Popup.StaysOen属性被设置为True,并且Popup控件会一直显示,直到显式地将IsOpen属性设置为False;

  如果将Popup.StaysOpen属性设置为False,当用户在其他地方单击鼠标时,Popup效果关闭。

如果Popup控件的IsOpen属性设置为True时,通过Popup控件的PopupAnimation属性(同时必须要设置属性 AllowsTransparency="True")

可以设置Popup控件的显示方式:

wpf之Popup弹出自定义输入"键盘"