通过使用样式修改TextBox文本绑定的参数 [英] Modifying the Parameters of a TextBox's Text Binding through the use of a Style
问题描述
我想要一个 TextBox
,显示货币格式的数字(通过将 StringFormat = c
设置为绑定)。当选择 TextBox
(当 IsKeyboardFocused == true
)时,我希望格式化消失,直到专注于 TextBox
丢失。
I would like to have a TextBox
that displays a number in currency format (by setting StringFormat=c
on the binding). When the TextBox
is selected (when IsKeyboardFocused==true
), I would like the formatting to go away, until the focus on the TextBox
is lost.
我发现了一种方法,可以在下面粘贴代码。我的问题是,绑定在 Style
中指定 - 这意味着我必须为每个 TextBox
我想这样做。理想的我想把风格放在某个中央位置,并为每个 TextBox
重新使用它,每个都有一个不同的绑定目标。
I found a way to do this, code pasted below. My problem with this is that the binding is specified inside the Style
- this means I have to retype the style for every TextBox
I want to do this for. Idealy I would like to put the style somewhere central, and reuse it for every TextBox
, with a different binding target for each.
使用 Style
可以在现有绑定上设置一个参数,例如 Text.Binding.StringFormat =
? (而不是将文本的整个值设置为新定义的绑定)
Is there a way for me, using a Style
, to set a parameter on the existing binding, something like Text.Binding.StringFormat=""
? (As opposed to setting the entire value of Text to a newly defined Binding)
其他建议可以实现这一点也不胜感激。
Other suggestions to accomplish this would also be appreciated.
代码(这个功能很简单):
Code (this works, it's just inconvenient):
<TextBox x:Name="ContractAmountTextBox">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsKeyboardFocused, ElementName=ContractAmountTextBox}" Value="False">
<Setter Property="Text" Value="{Binding Path=ContractAmount, UpdateSourceTrigger=LostFocus, StringFormat=c}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsKeyboardFocused, ElementName=ContractAmountTextBox}" Value="True">
<Setter Property="Text" Value="{Binding Path=ContractAmount, UpdateSourceTrigger=LostFocus}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
推荐答案
附加属性是可行的,但这意味着您必须完全替换绑定,然后将其放回来。
It is feasible with an attached property, but it means you have to replace the binding entirely, then put it back.
这是一个快速而肮脏的实现:
Here's a quick and dirty implementation:
public static class TextBoxBehavior
{
#region StringFormat
public static string GetStringFormat(TextBox obj)
{
return (string)obj.GetValue(StringFormatProperty);
}
public static void SetStringFormat(TextBox obj, string value)
{
obj.SetValue(StringFormatProperty, value);
}
public static readonly DependencyProperty StringFormatProperty =
DependencyProperty.RegisterAttached(
"StringFormat",
typeof(string),
typeof(TextBoxBehavior),
new UIPropertyMetadata(
null,
StringFormatChanged));
// Used to store the original format
private static readonly DependencyPropertyKey OriginalBindingPropertyKey =
DependencyProperty.RegisterAttachedReadOnly(
"OriginalBinding",
typeof(BindingBase),
typeof(TextBoxBehavior),
new UIPropertyMetadata(null));
private static void StringFormatChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
TextBox textBox = o as TextBox;
if (textBox == null)
return;
string oldValue = (string)e.OldValue;
string newValue = (string)e.NewValue;
if (!string.IsNullOrEmpty(oldValue) && string.IsNullOrEmpty(newValue))
{
// Update target for current binding
UpdateTextBindingSource(textBox);
// Restore original binding
var originalBinding = (BindingBase)textBox.GetValue(OriginalBindingPropertyKey.DependencyProperty);
if (originalBinding != null)
BindingOperations.SetBinding(textBox, TextBox.TextProperty, originalBinding);
textBox.SetValue(OriginalBindingPropertyKey, null);
}
else if (!string.IsNullOrEmpty(newValue) && string.IsNullOrEmpty(oldValue))
{
// Get current binding
var originalBinding = BindingOperations.GetBinding(textBox, TextBox.TextProperty);
if (originalBinding != null)
{
// Update target for current binding
UpdateTextBindingSource(textBox);
// Create new binding
var newBinding = CloneBinding(originalBinding);
newBinding.StringFormat = newValue;
// Assign new binding
BindingOperations.SetBinding(textBox, TextBox.TextProperty, newBinding);
// Store original binding
textBox.SetValue(OriginalBindingPropertyKey, originalBinding);
}
}
}
private static void UpdateTextBindingSource(TextBox textBox)
{
var expr = textBox.GetBindingExpression(TextBox.TextProperty);
if (expr != null &&
expr.ParentBinding != null &&
(expr.ParentBinding.Mode == BindingMode.Default // Text binds two-way by default
|| expr.ParentBinding.Mode == BindingMode.TwoWay
|| expr.ParentBinding.Mode == BindingMode.OneWayToSource))
{
expr.UpdateSource();
}
}
private static Binding CloneBinding(Binding original)
{
var copy = new Binding
{
Path = original.Path,
XPath = original.XPath,
Mode = original.Mode,
Converter = original.Converter,
ConverterCulture = original.ConverterCulture,
ConverterParameter = original.ConverterParameter,
FallbackValue = original.FallbackValue,
TargetNullValue = original.TargetNullValue,
NotifyOnSourceUpdated = original.NotifyOnSourceUpdated,
NotifyOnTargetUpdated = original.NotifyOnTargetUpdated,
NotifyOnValidationError = original.NotifyOnValidationError,
UpdateSourceExceptionFilter = original.UpdateSourceExceptionFilter,
UpdateSourceTrigger = original.UpdateSourceTrigger,
ValidatesOnDataErrors = original.ValidatesOnDataErrors,
ValidatesOnExceptions = original.ValidatesOnExceptions,
BindingGroupName = original.BindingGroupName,
BindsDirectlyToSource = original.BindsDirectlyToSource,
AsyncState = original.AsyncState,
IsAsync = original.IsAsync,
StringFormat = original.StringFormat
};
if (original.Source != null)
copy.Source = original.Source;
if (original.RelativeSource != null)
copy.RelativeSource = original.RelativeSource;
if (original.ElementName != null)
copy.ElementName = original.ElementName;
foreach (var rule in original.ValidationRules)
{
copy.ValidationRules.Add(rule);
}
return copy;
}
#endregion
}
使用方法:
<TextBox x:Name="ContractAmountTextBox"
Text="{Binding Path=ContractAmount, UpdateSourceTrigger=LostFocus, StringFormat=c}">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="local:TextBoxBehavior.StringFormat" Value="N"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
使用此功能,您还可以重复使用不同TextBox的样式
Using this, you can also reuse the style for different TextBoxes
这篇关于通过使用样式修改TextBox文本绑定的参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!