我的任务是创建一个转换器,它将更改TextBox
中的现有表达式。它应该像:
正如您所看到的,我想评估一个数字表达式,而不对混合表达式执行任何操作。
目前,只要TextBox
发生任何变化,我的转换器就会自动运行。
我的转换器:
using System;
using System.Data;
using System.Windows.Data;
using System.Globalization;
using System.Windows;
namespace TextBoxCalc
{
public class EvaluateTextBox : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string exp = "";
bool allow = true;
foreach (char i in value.ToString())
{
if (Int32.TryParse(i.ToString(), out int result) || i == '+' || i == '-' || i == '*' || i == '/' || i == '(' || i == ')')
{
exp += i;
}
else
{
exp += i;
allow = false;
continue;
}
}
if(exp != null && exp.Length != 0)
if (exp[0] == '+' || exp[0] == '-' || exp[0] == '*' || exp[0] == '/')
{
allow = false;
}
if (exp != null && exp.Length != 0)
if (exp[exp.Length - 1] == '+' || exp[exp.Length - 1] == '-' || exp[exp.Length - 1] == '*' || exp[exp.Length - 1] == '/')
{
allow = false;
}
DataTable dt = new DataTable();
if (allow)
{
var v = dt.Compute(exp, "");
return v.ToString();
}
return exp;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("ConvertBack should never be called");
}
}
}
我的XAML:
<Window x:Class="TextBoxCalc.MainWindow"
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:TextBoxCalc"
xmlns:conv="clr-namespace:TextBoxCalc"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<conv:EvaluateTextBox x:Key="EvaluateTextBox"/>
</Window.Resources>
<Grid>
<StackPanel>
<TextBox x:Name="textBox" Height="50" Width="200" Text="{Binding ElementName=textBox, Path=Text, Converter={StaticResource EvaluateTextBox}, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
</Window>
答案 0 :(得分:0)
在绑定表达式中,将UpdateSourceTrigger
更改为显式。
然后在按键事件中,检查您的状况,并添加以下行。
BindingExpression binding = textBox.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
执行此操作意味着只有在按Enter键时才会更新数据绑定源。由于每当更新绑定时都会应用转换器,因此只有在单击按钮时才会执行转换。
另一种方法是添加一个IsDefault
属性设置为true的按钮,并在按钮的Click
事件处理程序中使用逻辑。只要按下回车键,该按钮就会被“点击”。
答案 1 :(得分:0)
将AcceptsReturn值设置为true:
<TextBox x:Name="textBox" AcceptsReturn="True" Text="{Binding ElementName=textBox, Path=Text, Converter={StaticResource EvaluateTextBox}, Mode=OneWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"></TextBox>
更改转换器以检查换行符:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (((string)value).EndsWith(Environment.NewLine))
{
string exp = "";
bool allow = true;
foreach (char i in value.ToString().TrimEnd(Environment.NewLine.ToCharArray()))
{
if (Int32.TryParse(i.ToString(), out int result) || i == '+' || i == '-' || i == '*' || i == '/' || i == '(' || i == ')')
{
exp += i;
}
else
{
exp += i;
allow = false;
continue;
}
}
if (exp != null && exp.Length != 0)
if (exp[0] == '+' || exp[0] == '-' || exp[0] == '*' || exp[0] == '/')
{
allow = false;
}
if (exp != null && exp.Length != 0)
if (exp[exp.Length - 1] == '+' || exp[exp.Length - 1] == '-' || exp[exp.Length - 1] == '*' || exp[exp.Length - 1] == '/')
{
allow = false;
}
DataTable dt = new DataTable();
if (allow)
{
var v = dt.Compute(exp, "");
return v.ToString();
}
return exp;
}
else
{
return value;
}
}
答案 2 :(得分:0)
正如CKII所说,UpdateSourceTrigger=PropertyChanged
与你想要的相反。
首先,我们将计算代码移动到静态辅助方法中。我不确定你的验证是做什么的所以我写了一个快速的测试。如果您对转换器逻辑感到满意,只需将其粘贴即可。
public static class Helpers
{
public static String Calculate(object value)
{
return new DataTable().Compute($"{value}", "").ToString();
}
}
我们将摆脱您在Binding上设置的大多数属性。 UpdateSourceTrigger=Explicit
表示&#34;只有在我以编程方式调用UpdateSource()
时才会执行此操作&#34;。我将使用{RelativeSource Self}
因为它使XAML更容易复制和粘贴;我使用ElementName=textbox
对其进行了测试,其中x:Name
属性仍然存在,并且它的工作方式相同。
<TextBox
KeyDown="textBox_KeyDown"
Text="{Binding Text, RelativeSource={RelativeSource Self}, Converter={StaticResource Eval}, UpdateSourceTrigger=Explicit}"
/>
我们的keydown事件处理程序将显式更新仅返回的绑定,这将导致转换器启动。
private void textBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
(sender as TextBox)?.GetBindingExpression(TextBox.TextProperty)?.UpdateSource();
}
}
最后,您希望ConvertBack中的转换能够正常工作。我已将转换器重命名为EvaluateExpression,因为它没有以任何方式绑定到TextBoxes。
public class EvaluateExpression : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return Helpers.Calculate(value);
}
catch
{
return value;
}
}
}
我使用viewmodel属性测试了相同的场景,它的工作方式相同:
<TextBox
KeyDown="textBox_KeyDown"
Text="{Binding InputText, Converter={StaticResource EvaluateExpression}, UpdateSourceTrigger=Explicit}"
/>
您可以轻松编写一个附加属性来设置update-source-on-return keydown事件。如果您只执行一次,那就太过分了,但如果您的应用程序周围散布了多个文本框,只需要在返回时进行更新,那么这值得做。