Unify WPF numeric textbox editing behavior

This commit is contained in:
tian 2026-04-11 09:04:03 +08:00
parent a252dad46a
commit 18b530ef5f
10 changed files with 269 additions and 36 deletions

View File

@ -307,6 +307,7 @@
<Compile Include="src\UI\WPF\Converters\BoolToOpacityConverter.cs" /> <Compile Include="src\UI\WPF\Converters\BoolToOpacityConverter.cs" />
<Compile Include="src\UI\WPF\Converters\IndexConverter.cs" /> <Compile Include="src\UI\WPF\Converters\IndexConverter.cs" />
<Compile Include="src\UI\WPF\Converters\CountToVisibilityConverter.cs" /> <Compile Include="src\UI\WPF\Converters\CountToVisibilityConverter.cs" />
<Compile Include="src\UI\WPF\Converters\EditableNumberConverter.cs" />
<Compile Include="src\UI\WPF\Converters\PathTypeConverter.cs" /> <Compile Include="src\UI\WPF\Converters\PathTypeConverter.cs" />
<Compile Include="src\UI\WPF\Converters\BatchQueueStatusConverter.cs" /> <Compile Include="src\UI\WPF\Converters\BatchQueueStatusConverter.cs" />
<Compile Include="src\UI\WPF\Converters\BatchQueueStatusHelper.cs" /> <Compile Include="src\UI\WPF\Converters\BatchQueueStatusHelper.cs" />

View File

@ -0,0 +1,127 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace NavisworksTransport.UI.WPF.Converters
{
/// <summary>
/// Keeps numeric TextBox editing humane: incomplete text is allowed while editing,
/// and only complete numeric values are written back to the bound source.
/// </summary>
public class EditableNumberConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return string.Empty;
}
string format = parameter as string;
if (string.IsNullOrWhiteSpace(format))
{
return System.Convert.ToString(value, culture);
}
if (value is IFormattable formattable)
{
return formattable.ToString(format, culture);
}
return System.Convert.ToString(value, culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string text = value as string;
if (IsIntermediateText(text))
{
throw new FormatException("请输入有效的数字。");
}
text = text.Trim();
Type actualTargetType = Nullable.GetUnderlyingType(targetType) ?? targetType;
if (TryParseNumber(text, culture, actualTargetType, out object parsedValue))
{
return parsedValue;
}
throw new FormatException("请输入有效的数字。");
}
public static bool IsIntermediateText(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
return true;
}
text = text.Trim();
return text == "-" ||
text == "+" ||
text == "." ||
text == "-." ||
text == "+.";
}
public static bool TryParseNumber(string text, CultureInfo culture, Type targetType, out object parsedValue)
{
NumberStyles styles = NumberStyles.Float | NumberStyles.AllowThousands;
if (targetType == typeof(double))
{
if (TryParseDouble(text, styles, culture, out double doubleValue))
{
parsedValue = doubleValue;
return true;
}
}
else if (targetType == typeof(float))
{
if (TryParseDouble(text, styles, culture, out double doubleValue))
{
parsedValue = (float)doubleValue;
return true;
}
}
else if (targetType == typeof(decimal))
{
if (decimal.TryParse(text, styles, culture, out decimal decimalValue) ||
decimal.TryParse(text, styles, CultureInfo.InvariantCulture, out decimalValue))
{
parsedValue = decimalValue;
return true;
}
}
else if (targetType == typeof(int))
{
if (int.TryParse(text, NumberStyles.Integer, culture, out int intValue) ||
int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out intValue))
{
parsedValue = intValue;
return true;
}
}
else if (targetType == typeof(long))
{
if (long.TryParse(text, NumberStyles.Integer, culture, out long longValue) ||
long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out longValue))
{
parsedValue = longValue;
return true;
}
}
parsedValue = null;
return false;
}
private static bool TryParseDouble(string text, NumberStyles styles, CultureInfo culture, out double value)
{
return double.TryParse(text, styles, culture, out value) ||
double.TryParse(text, styles, CultureInfo.InvariantCulture, out value);
}
}
}

View File

@ -27,6 +27,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
<!-- 转换器资源 --> <!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<converters:EditableNumberConverter x:Key="EditableNumberConverter"/>
<!-- 动画控制页面特有的样式 --> <!-- 动画控制页面特有的样式 -->
<Style x:Key="ProgressBarStyle" TargetType="ProgressBar"> <Style x:Key="ProgressBarStyle" TargetType="ProgressBar">
@ -72,7 +73,7 @@ NavisworksTransport 检测动画页签视图 - 采用与类别设置和分层管
Content="持续时间:" Content="持续时间:"
Style="{StaticResource ParameterLabelStyle}"/> Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Column="4" <TextBox Grid.Column="4"
Text="{Binding AnimationDuration, StringFormat=0.0###}" Text="{Binding AnimationDuration, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Grid.Column="5" Content="秒" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Column="5" Content="秒" Style="{StaticResource UnitLabelStyle}"/>
</Grid> </Grid>

View File

@ -1,6 +1,7 @@
<Window x:Class="NavisworksTransport.UI.WPF.Views.EditCoordinatesWindow" <Window x:Class="NavisworksTransport.UI.WPF.Views.EditCoordinatesWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:NavisworksTransport.UI.WPF.Converters"
Title="编辑路径点坐标" Height="380" Width="400" Title="编辑路径点坐标" Height="380" Width="400"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
ResizeMode="NoResize" ResizeMode="NoResize"
@ -12,6 +13,7 @@
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/TransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/> <ResourceDictionary Source="pack://application:,,,/TransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<converters:EditableNumberConverter x:Key="EditableNumberConverter"/>
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
@ -63,7 +65,8 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Text="X 坐标:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/> <TextBlock Text="X 坐标:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/>
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
Text="{Binding X, StringFormat=0.000, UpdateSourceTrigger=PropertyChanged}" x:Name="XTextBox"
Text="{Binding X, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.000, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Padding="8,0" Padding="8,0"
@ -80,7 +83,8 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Text="Y 坐标:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/> <TextBlock Text="Y 坐标:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/>
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
Text="{Binding Y, StringFormat=0.000, UpdateSourceTrigger=PropertyChanged}" x:Name="YTextBox"
Text="{Binding Y, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.000, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Padding="8,0" Padding="8,0"
@ -97,7 +101,8 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock Text="Z 坐标:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/> <TextBlock Text="Z 坐标:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/>
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
Text="{Binding Z, StringFormat=0.000, UpdateSourceTrigger=PropertyChanged}" x:Name="ZTextBox"
Text="{Binding Z, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.000, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Padding="8,0" Padding="8,0"

View File

@ -1,8 +1,10 @@
using System; using System;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using NavisworksTransport.UI.WPF.Converters;
namespace NavisworksTransport.UI.WPF.Views namespace NavisworksTransport.UI.WPF.Views
@ -36,6 +38,11 @@ namespace NavisworksTransport.UI.WPF.Views
private void OnSaveClick(object sender, RoutedEventArgs e) private void OnSaveClick(object sender, RoutedEventArgs e)
{ {
if (!TryCommitInputValues())
{
return;
}
DialogResult = true; DialogResult = true;
Close(); Close();
} }
@ -72,14 +79,14 @@ namespace NavisworksTransport.UI.WPF.Views
string text = Clipboard.GetText().Trim(); string text = Clipboard.GetText().Trim();
string[] parts = text.Split(new[] { ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); string[] parts = text.Split(new[] { ',', ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 3 && if (parts.Length >= 3 &&
double.TryParse(parts[0], out double x) && EditableNumberConverter.TryParseNumber(parts[0], System.Globalization.CultureInfo.CurrentCulture, typeof(double), out object xValue) &&
double.TryParse(parts[1], out double y) && EditableNumberConverter.TryParseNumber(parts[1], System.Globalization.CultureInfo.CurrentCulture, typeof(double), out object yValue) &&
double.TryParse(parts[2], out double z)) EditableNumberConverter.TryParseNumber(parts[2], System.Globalization.CultureInfo.CurrentCulture, typeof(double), out object zValue))
{ {
X = x; X = (double)xValue;
Y = y; Y = (double)yValue;
Z = z; Z = (double)zValue;
// 刷新绑定 // 刷新绑定
DataContext = null; DataContext = null;
DataContext = this; DataContext = this;
@ -128,5 +135,41 @@ namespace NavisworksTransport.UI.WPF.Views
}; };
timer.Start(); timer.Start();
} }
private bool TryCommitInputValues()
{
return TryUpdateNumberTextBox(XTextBox, "请输入有效的 X 坐标。") &&
TryUpdateNumberTextBox(YTextBox, "请输入有效的 Y 坐标。") &&
TryUpdateNumberTextBox(ZTextBox, "请输入有效的 Z 坐标。");
}
private static bool TryUpdateNumberTextBox(TextBox textBox, string message)
{
BindingExpression binding = textBox.GetBindingExpression(TextBox.TextProperty);
if (EditableNumberConverter.IsIntermediateText(textBox.Text) ||
!EditableNumberConverter.TryParseNumber(textBox.Text.Trim(), System.Globalization.CultureInfo.CurrentCulture, typeof(double), out _))
{
ShowInputError(message, textBox);
return false;
}
binding?.UpdateSource();
if (Validation.GetHasError(textBox))
{
ShowInputError(message, textBox);
return false;
}
return true;
}
private static void ShowInputError(string message, TextBox textBox)
{
MessageBox.Show(message, "输入错误", MessageBoxButton.OK, MessageBoxImage.Warning);
textBox.Focus();
textBox.SelectAll();
}
} }
} }

View File

@ -1,6 +1,7 @@
<Window x:Class="NavisworksTransport.UI.WPF.Views.EditRotationWindow" <Window x:Class="NavisworksTransport.UI.WPF.Views.EditRotationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:NavisworksTransport.UI.WPF.Converters"
Title="调整物体" Height="430" Width="400" Title="调整物体" Height="430" Width="400"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
ResizeMode="NoResize" ResizeMode="NoResize"
@ -12,6 +13,7 @@
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/TransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/> <ResourceDictionary Source="pack://application:,,,/TransportPlugin;component/src/UI/WPF/Resources/NavisworksStyles.xaml"/>
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<converters:EditableNumberConverter x:Key="EditableNumberConverter"/>
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
@ -44,7 +46,7 @@
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
x:Name="XAxisTextBox" x:Name="XAxisTextBox"
GotFocus="OnAxisTextBoxGotFocus" GotFocus="OnAxisTextBoxGotFocus"
Text="{Binding RotationXDegrees, StringFormat=0.0, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding RotationXDegrees, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Padding="8,0" Padding="8,0"
@ -65,7 +67,7 @@
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
x:Name="YAxisTextBox" x:Name="YAxisTextBox"
GotFocus="OnAxisTextBoxGotFocus" GotFocus="OnAxisTextBoxGotFocus"
Text="{Binding RotationYDegrees, StringFormat=0.0, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding RotationYDegrees, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Padding="8,0" Padding="8,0"
@ -86,7 +88,7 @@
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
x:Name="ZAxisTextBox" x:Name="ZAxisTextBox"
GotFocus="OnAxisTextBoxGotFocus" GotFocus="OnAxisTextBoxGotFocus"
Text="{Binding RotationZDegrees, StringFormat=0.0, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding RotationZDegrees, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"
Padding="8,0" Padding="8,0"
@ -105,7 +107,7 @@
<TextBlock Text="提升高度:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/> <TextBlock Text="提升高度:" VerticalAlignment="Center" FontSize="11" Foreground="#FF333333"/>
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
x:Name="GroundLiftTextBox" x:Name="GroundLiftTextBox"
Text="{Binding GroundPathLiftHeightInMeters, StringFormat=0.###, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding GroundPathLiftHeightInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
IsEnabled="{Binding IsGroundLiftEnabled}" IsEnabled="{Binding IsGroundLiftEnabled}"
Height="28" Height="28"
VerticalContentAlignment="Center" VerticalContentAlignment="Center"

View File

@ -3,6 +3,8 @@ using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Data;
using NavisworksTransport.UI.WPF.Converters;
using NavisworksTransport.Utils.CoordinateSystem; using NavisworksTransport.Utils.CoordinateSystem;
namespace NavisworksTransport.UI.WPF.Views namespace NavisworksTransport.UI.WPF.Views
@ -171,7 +173,7 @@ namespace NavisworksTransport.UI.WPF.Views
private void OnConfirmClick(object sender, RoutedEventArgs e) private void OnConfirmClick(object sender, RoutedEventArgs e)
{ {
if (!ValidateGroundLiftHeight()) if (!TryCommitInputValues())
{ {
return; return;
} }
@ -183,7 +185,7 @@ namespace NavisworksTransport.UI.WPF.Views
private void OnTranslateClick(object sender, RoutedEventArgs e) private void OnTranslateClick(object sender, RoutedEventArgs e)
{ {
if (!ValidateGroundLiftHeight()) if (!TryCommitInputValues())
{ {
return; return;
} }
@ -223,16 +225,64 @@ namespace NavisworksTransport.UI.WPF.Views
} }
} }
private bool ValidateGroundLiftHeight() private bool TryCommitInputValues()
{ {
if (!TryUpdateNumberTextBox(XAxisTextBox, "请输入有效的 X 轴角度。"))
{
return false;
}
if (!TryUpdateNumberTextBox(YAxisTextBox, "请输入有效的 Y 轴角度。"))
{
return false;
}
if (!TryUpdateNumberTextBox(ZAxisTextBox, "请输入有效的 Z 轴角度。"))
{
return false;
}
if (!TryUpdateNumberTextBox(GroundLiftTextBox, "请输入有效的提升高度。"))
{
return false;
}
if (GroundPathLiftHeightInMeters < 0.0) if (GroundPathLiftHeightInMeters < 0.0)
{ {
MessageBox.Show("提升高度必须大于或等于 0。", "输入错误", MessageBoxButton.OK, MessageBoxImage.Warning); ShowInputError("提升高度必须大于或等于 0。", GroundLiftTextBox);
GroundLiftTextBox.Focus();
return false; return false;
} }
return true; return true;
} }
private static bool TryUpdateNumberTextBox(TextBox textBox, string message)
{
BindingExpression binding = textBox.GetBindingExpression(TextBox.TextProperty);
if (EditableNumberConverter.IsIntermediateText(textBox.Text) ||
!EditableNumberConverter.TryParseNumber(textBox.Text.Trim(), System.Globalization.CultureInfo.CurrentCulture, typeof(double), out _))
{
ShowInputError(message, textBox);
return false;
}
binding?.UpdateSource();
if (Validation.GetHasError(textBox))
{
ShowInputError(message, textBox);
return false;
}
return true;
}
private static void ShowInputError(string message, TextBox textBox)
{
MessageBox.Show(message, "输入错误", MessageBoxButton.OK, MessageBoxImage.Warning);
textBox.Focus();
textBox.SelectAll();
}
} }
} }

View File

@ -28,6 +28,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
<!-- 转换器资源 --> <!-- 转换器资源 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<converters:IndexConverter x:Key="IndexConverter"/> <converters:IndexConverter x:Key="IndexConverter"/>
<converters:EditableNumberConverter x:Key="EditableNumberConverter"/>
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
@ -115,14 +116,14 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
<Label Grid.Column="0" Content="限宽:" Style="{StaticResource ParameterLabelStyle}"/> <Label Grid.Column="0" Content="限宽:" Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
Text="{Binding WidthLimit, StringFormat=0.0###}" Text="{Binding WidthLimit, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}" Style="{StaticResource ParameterInputStyle}"
ToolTip="通行宽度限制(米)"/> ToolTip="通行宽度限制(米)"/>
<Label Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/>
<Label Grid.Column="3" Content="限高:" VerticalAlignment="Center" Margin="15,0,0,0"/> <Label Grid.Column="3" Content="限高:" VerticalAlignment="Center" Margin="15,0,0,0"/>
<TextBox Grid.Column="4" <TextBox Grid.Column="4"
Text="{Binding HeightLimit, StringFormat=0.0###}" Text="{Binding HeightLimit, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}" Style="{StaticResource ParameterInputStyle}"
ToolTip="通行高度限制(米)"/> ToolTip="通行高度限制(米)"/>
<Label Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/>
@ -139,7 +140,7 @@ NavisworksTransport 类别设置页签视图 - 参考分层管理页签的设计
<Label Grid.Column="0" Content="限速:" Style="{StaticResource ParameterLabelStyle}"/> <Label Grid.Column="0" Content="限速:" Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Column="1" <TextBox Grid.Column="1"
Text="{Binding SpeedLimit, StringFormat=0.0###}" Text="{Binding SpeedLimit, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}" Style="{StaticResource ParameterInputStyle}"
ToolTip="速度限制(米/秒)"/> ToolTip="速度限制(米/秒)"/>
<Label Grid.Column="2" Content="米/秒" Style="{StaticResource UnitLabelStyle}" Width="40"/> <Label Grid.Column="2" Content="米/秒" Style="{StaticResource UnitLabelStyle}" Width="40"/>

View File

@ -29,6 +29,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<converters:PathTypeConverter x:Key="PathTypeConverter"/> <converters:PathTypeConverter x:Key="PathTypeConverter"/>
<converters:BoolToBrushConverter x:Key="BoolToBrushConverter"/> <converters:BoolToBrushConverter x:Key="BoolToBrushConverter"/>
<converters:BoolToOpacityConverter x:Key="BoolToOpacityConverter"/> <converters:BoolToOpacityConverter x:Key="BoolToOpacityConverter"/>
<converters:EditableNumberConverter x:Key="EditableNumberConverter"/>
<!-- 多层吊装转换器 --> <!-- 多层吊装转换器 -->
<converters:IndexPlusOneConverter x:Key="IndexPlusOneConverter"/> <converters:IndexPlusOneConverter x:Key="IndexPlusOneConverter"/>
@ -89,28 +90,28 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<!-- 物体长度 --> <!-- 物体长度 -->
<Label Grid.Row="0" Grid.Column="0" Content="物体长度:" Style="{StaticResource ParameterLabelStyle}"/> <Label Grid.Row="0" Grid.Column="0" Content="物体长度:" Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Row="0" Grid.Column="1" <TextBox Grid.Row="0" Grid.Column="1"
Text="{Binding ObjectLength, StringFormat=0.0###}" Text="{Binding ObjectLength, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Grid.Row="0" Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Row="0" Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/>
<!-- 物体宽度 --> <!-- 物体宽度 -->
<Label Grid.Row="0" Grid.Column="3" Content="物体宽度:" Style="{StaticResource ParameterLabelStyle}"/> <Label Grid.Row="0" Grid.Column="3" Content="物体宽度:" Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Row="0" Grid.Column="4" <TextBox Grid.Row="0" Grid.Column="4"
Text="{Binding ObjectWidth, StringFormat=0.0###}" Text="{Binding ObjectWidth, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Grid.Row="0" Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Row="0" Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/>
<!-- 物体高度 --> <!-- 物体高度 -->
<Label Grid.Row="1" Grid.Column="0" Content="物体高度:" Style="{StaticResource ParameterLabelStyle}"/> <Label Grid.Row="1" Grid.Column="0" Content="物体高度:" Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Row="1" Grid.Column="1" <TextBox Grid.Row="1" Grid.Column="1"
Text="{Binding ObjectHeight, StringFormat=0.0###}" Text="{Binding ObjectHeight, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Grid.Row="1" Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Row="1" Grid.Column="2" Content="米" Style="{StaticResource UnitLabelStyle}"/>
<!-- 安全间隙 --> <!-- 安全间隙 -->
<Label Grid.Row="1" Grid.Column="3" Content="安全间隙:" Style="{StaticResource ParameterLabelStyle}"/> <Label Grid.Row="1" Grid.Column="3" Content="安全间隙:" Style="{StaticResource ParameterLabelStyle}"/>
<TextBox Grid.Row="1" Grid.Column="4" <TextBox Grid.Row="1" Grid.Column="4"
Text="{Binding SafetyMargin, StringFormat=0.00###}" Text="{Binding SafetyMargin, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.00###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Grid.Row="1" Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Grid.Row="1" Grid.Column="5" Content="米" Style="{StaticResource UnitLabelStyle}"/>
</Grid> </Grid>
@ -404,7 +405,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<GridViewColumn Header="高度(米)" Width="88"> <GridViewColumn Header="高度(米)" Width="88">
<GridViewColumn.CellTemplate> <GridViewColumn.CellTemplate>
<DataTemplate> <DataTemplate>
<TextBox Text="{Binding HeightInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus, StringFormat=0.0###}" <TextBox Text="{Binding HeightInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
</DataTemplate> </DataTemplate>
@ -466,7 +467,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
Margin="6,0,0,0" Margin="6,0,0,0"
VerticalAlignment="Center"> VerticalAlignment="Center">
<TextBox Width="72" <TextBox Width="72"
Text="{Binding AssemblyAnchorVerticalOffsetInMeters, StringFormat=0.0###}" Text="{Binding AssemblyAnchorVerticalOffsetInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Content="米" Style="{StaticResource UnitLabelStyle}"/> <Label Content="米" Style="{StaticResource UnitLabelStyle}"/>
</StackPanel> </StackPanel>
@ -513,15 +514,15 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
Margin="6,0,0,0" Margin="6,0,0,0"
VerticalAlignment="Center"> VerticalAlignment="Center">
<TextBox Width="56" <TextBox Width="56"
Text="{Binding AssemblySphereCenterX, StringFormat=0.0###}" Text="{Binding AssemblySphereCenterX, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Content="X" Style="{StaticResource UnitLabelStyle}"/> <Label Content="X" Style="{StaticResource UnitLabelStyle}"/>
<TextBox Width="56" <TextBox Width="56"
Text="{Binding AssemblySphereCenterY, StringFormat=0.0###}" Text="{Binding AssemblySphereCenterY, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Content="Y" Style="{StaticResource UnitLabelStyle}"/> <Label Content="Y" Style="{StaticResource UnitLabelStyle}"/>
<TextBox Width="56" <TextBox Width="56"
Text="{Binding AssemblySphereCenterZ, StringFormat=0.0###}" Text="{Binding AssemblySphereCenterZ, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Label Content="Z" Style="{StaticResource UnitLabelStyle}"/> <Label Content="Z" Style="{StaticResource UnitLabelStyle}"/>
</StackPanel> </StackPanel>
@ -661,7 +662,7 @@ NavisworksTransport 路径编辑页签视图 - 采用与动画控制和分层管
<TextBox Width="84" <TextBox Width="84"
Margin="6,0" Margin="6,0"
HorizontalContentAlignment="Center" HorizontalContentAlignment="Center"
Text="{Binding SelectedRailNormalOffsetInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus, StringFormat=0.0###}" Text="{Binding SelectedRailNormalOffsetInMeters, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=0.0###, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Style="{StaticResource ParameterInputStyle}"/> Style="{StaticResource ParameterInputStyle}"/>
<Button Content="+" <Button Content="+"
Width="24" Width="24"

View File

@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NavisworksTransport.UI.WPF.Views" xmlns:local="clr-namespace:NavisworksTransport.UI.WPF.Views"
xmlns:controls="clr-namespace:NavisworksTransport.UI.WPF.Controls" xmlns:controls="clr-namespace:NavisworksTransport.UI.WPF.Controls"
xmlns:converters="clr-namespace:NavisworksTransport.UI.WPF.Converters"
Title="时标设置" Title="时标设置"
Height="750" Width="1100" Height="750" Width="1100"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
@ -17,6 +18,7 @@
<!-- 转换器 --> <!-- 转换器 -->
<BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/> <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<local:InverseBooleanToVisibilityConverter x:Key="InverseBoolToVisibilityConverter"/> <local:InverseBooleanToVisibilityConverter x:Key="InverseBoolToVisibilityConverter"/>
<converters:EditableNumberConverter x:Key="EditableNumberConverter"/>
</ResourceDictionary> </ResourceDictionary>
</Window.Resources> </Window.Resources>
@ -173,7 +175,7 @@
Visibility="{Binding IsSelectedDistanceEditable, Converter={StaticResource BoolToVisibilityConverter}}" Visibility="{Binding IsSelectedDistanceEditable, Converter={StaticResource BoolToVisibilityConverter}}"
PreviewMouseLeftButtonDown="DistanceSlider_PreviewMouseLeftButtonDown" PreviewMouseLeftButtonDown="DistanceSlider_PreviewMouseLeftButtonDown"
PreviewMouseLeftButtonUp="DistanceSlider_PreviewMouseLeftButtonUp"/> PreviewMouseLeftButtonUp="DistanceSlider_PreviewMouseLeftButtonUp"/>
<TextBox Text="{Binding SelectedDistance, StringFormat=F2, Mode=TwoWay}" <TextBox Text="{Binding SelectedDistance, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=F2, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Margin="0,0,0,15" HorizontalAlignment="Right" Width="80" Margin="0,0,0,15" HorizontalAlignment="Right" Width="80"
Visibility="{Binding IsSelectedDistanceEditable, Converter={StaticResource BoolToVisibilityConverter}}"/> Visibility="{Binding IsSelectedDistanceEditable, Converter={StaticResource BoolToVisibilityConverter}}"/>
<!-- 距离不可编辑时显示只读文本 --> <!-- 距离不可编辑时显示只读文本 -->
@ -185,14 +187,14 @@
<Slider Minimum="0" Maximum="60" <Slider Minimum="0" Maximum="60"
Value="{Binding SelectedWaitTime, Mode=TwoWay}" Value="{Binding SelectedWaitTime, Mode=TwoWay}"
TickFrequency="1" IsSnapToTickEnabled="True"/> TickFrequency="1" IsSnapToTickEnabled="True"/>
<TextBox Text="{Binding SelectedWaitTime, StringFormat=F1, Mode=TwoWay}" <TextBox Text="{Binding SelectedWaitTime, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=F1, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Margin="0,0,0,15" HorizontalAlignment="Right" Width="80"/> Margin="0,0,0,15" HorizontalAlignment="Right" Width="80"/>
<TextBlock Text="动作时间 (秒):" FontWeight="SemiBold" Margin="0,0,0,3"/> <TextBlock Text="动作时间 (秒):" FontWeight="SemiBold" Margin="0,0,0,3"/>
<Slider Minimum="0" Maximum="60" <Slider Minimum="0" Maximum="60"
Value="{Binding SelectedActionTime, Mode=TwoWay}" Value="{Binding SelectedActionTime, Mode=TwoWay}"
TickFrequency="1" IsSnapToTickEnabled="True"/> TickFrequency="1" IsSnapToTickEnabled="True"/>
<TextBox Text="{Binding SelectedActionTime, StringFormat=F1, Mode=TwoWay}" <TextBox Text="{Binding SelectedActionTime, Mode=TwoWay, UpdateSourceTrigger=LostFocus, Converter={StaticResource EditableNumberConverter}, ConverterParameter=F1, ValidatesOnExceptions=True, NotifyOnValidationError=True}"
Margin="0,0,0,15" HorizontalAlignment="Right" Width="80"/> Margin="0,0,0,15" HorizontalAlignment="Right" Width="80"/>
<Separator Margin="0,10"/> <Separator Margin="0,10"/>