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

时间:2023-03-08 15:37:52
wpf之Popup弹出自定义输入"键盘"

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

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

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

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

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

Xaml:

<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=""/>
<GradientStop Color="#EBEBEB" Offset="0.5"/>
<GradientStop Color="#DDDDDD" Offset="0.5"/>
<GradientStop Color="#CDCDCD" Offset=""/>
</LinearGradientBrush>
</Setter.Value>
</Setter>-->
<!--<Setter Property="BorderBrush" Value="#FF707070"/>-->
<!--<Setter Property="BorderThickness" Value=""/>-->
<!--<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>-->
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<!--<Setter Property="Height" Value="" />
<Setter Property="Width" Value="" />-->
<!--<Setter Property="Padding" Value=""/>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" BorderBrush="#FF474747" BorderThickness="" CornerRadius="">
<!--<Border.Effect>
<DropShadowEffect BlurRadius="" ShadowDepth="" Opacity="0.27"/>
</Border.Effect>-->
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFCCCCCC"/>
<GradientStop Color="WhiteSmoke" Offset=""/>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="#FF565656" TextElement.FontSize="" />
<!--<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=""/>
</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=""/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>-->
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<!--<Setter Property="Padding" Value=""/>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" BorderBrush="#FF565656" BorderThickness="" CornerRadius="">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFC547" Offset=""/>
<GradientStop Color="#FFF77202"/>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White" TextElement.FontSize=""/>
<!--<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=""/>
<GradientStop Color="#FF2D2D2D" Offset=""/>
</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=""/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>-->
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<!--<Setter Property="Padding" Value=""/>-->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="border" BorderBrush="#FF565656" BorderThickness="" CornerRadius="">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFC547" Offset=""/>
<GradientStop Color="#FFF77202"/>
</LinearGradientBrush>
</Border.Background>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="White" TextElement.FontSize=""/>
<!--<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=""/>
<GradientStop Color="#FF2D2D2D" Offset=""/>
</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="" Grid.Column="" Grid.Row="" Content="" x:Name="button1" Click="button1_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button2" Click="button2_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button3" Click="button3_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button4" Click="button4_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button5" Click="button5_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button6" Click="button6_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button7" Click="button7_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button8" Click="button8_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button9" Click="button9_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="" x:Name="button0" Click="button0_Click" Style="{StaticResource btnNum}"/>
<Button Margin="" Grid.Column="" Grid.Row="" Content="清零" x:Name="btnMin" Click="btnMin_Click" Style="{StaticResource btnFunc}" />
<Button Margin="" Grid.Column="" Grid.Row="" Content="确认" x:Name="btnClose" Click="btnClose_Click" Style="{StaticResource btnFunc}" />
</Grid>
</UserControl>

C#:

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()); 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()); 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 = ;
} 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 * + num);
}
else
{
Value = Value * + num;
}
} private void button2_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button3_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button4_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button5_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button6_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button7_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button8_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button9_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button0_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void button1_Click(object sender, RoutedEventArgs e)
{
AddNumber();
} private void btnClose_Click(object sender, RoutedEventArgs e)
{
IsChecked = false;
} }
}

主窗体:

Xaml:

<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>

C#:

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));
}
}
}

验证输入后,绑定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弹出自定义输入"键盘"