【问题标题】:Different Format for TextBox when Focused Using MultiBinding Won't Update Source使用 MultiBinding 聚焦时文本框的不同格式不会更新源
【发布时间】:2012-07-10 05:18:23
【问题描述】:

我想做的很简单,当 TextBox 有焦点时显示一种格式,而当它没有焦点时显示另一种格式。在我的情况下,我在不集中时将一个数字四舍五入为 3 位数字,但在集中于编辑时显示实际的整数。

我有一个使用多重绑定的相当简单的解决方案,我觉得我快到了。一切都按预期工作,即时窗口中没有错误,但绑定不会更新源代码。

我正在使用这种样式来传递我的绑定以及 TextBox 是否将焦点传递给转换器。

<Style x:Key="RoundedTextBox" TargetType="{x:Type ContentControl}">
    <Setter Property="Focusable" Value="False"/>
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBox x:Name="TB" TextAlignment="Right" DataContext="{TemplateBinding Content}">
                    <TextBox.Text>
                        <MultiBinding Converter="{StaticResource DecRounder}" UpdateSourceTrigger="PropertyChanged">
                            <MultiBinding.Bindings>
                                <Binding ElementName="TB" Path="DataContext" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged" BindsDirectlyToSource="True" />
                                <Binding ElementName="TB" Path="IsFocused" Mode="OneWay" />
                            </MultiBinding.Bindings>
                        </MultiBinding>
                    </TextBox.Text>
                </TextBox>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

示例用法:

<ContentControl Style="{StaticResource RoundedTextBox}"
                Content="{Binding Path=Model.SomeNumber}" />

多值转换器就在这里。

public class DecimalRoundingConverter : IMultiValueConverter
{

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {

        if (values.Length != 2)
            throw new Exception("Invalid number of values for DecimalRoundingConverter!");

        if (values[0] is string)
            return values[0];

        if (values[0] != null && !(values[0] is decimal))
            throw new Exception("Invalid type for first value used with DecimalRoundingConverter!");
        if (!(values[1] is bool))
            throw new Exception("Invalid type for second value used with DecimalRoundingConverter!");
        if (targetType != typeof(string))
            throw new Exception("Invalid target type used with DecimalRoundingConverter!");

        if (values[0] == null)
            return null;

        decimal number = (decimal)values[0];

        bool isFocused;
        if (values[1] == null)
            isFocused = true;
        else if (values[1] is bool)
            isFocused = (bool)values[1];
        else
            if (!bool.TryParse((string)values[1], out isFocused))
                throw new Exception("Invalid converter parameter used with DecimalRoundingConverter!");

        return string.Format(isFocused ? "{0:.#############################}" : "{0:.###}", number);

    }

    public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
    {

        decimal d;
        var ret = new object[2];

        if (value == null)
            ret[0] = null;
        else if (decimal.TryParse((string)value, out d))
            ret[0] = d;
        else
            ret[0] = value;

        ret[1] = Binding.DoNothing;

        return ret;

    }

}

【问题讨论】:

    标签: textbox focus string-formatting multibinding imultivalueconverter


    【解决方案1】:

    对于它的价值,我从这个CodeProject article 得出了一个解决方案。关键是使用样式中的触发器来切换内容模板。提供的示例并不完美,但它是一次很好的学习体验。

    这种方法的唯一缺点是必须在 UserControl 中定义 ContentTemplates 和 Style,因为 ContentTemplates 直接引用 TextBox 事件处理程序。这是因为对 TextBox 的引用必须传递给后面的代码。当您尝试覆盖样式时,您将失去切换 ContentTemplate 的触发器。

    这个缺点对我来说很好,因为我绑定到重要属性的应用程序设置,例如 ContentStringFormat。

    编辑

    这是完整 XAML 中的一种更好的方法。我写了一个corresponding article on my blog。

    <ControlTemplate x:Key="EditableDecimalTemplate" TargetType="{x:Type ContentControl}">
        <ContentPresenter Name="contentHolder" 
                                VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                RecognizesAccessKey="True" 
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
            <ContentPresenter.Content>
                <Grid Margin="0">
                    <Border Name="nonFocusedBorder"
                            Grid.ZIndex="3" IsHitTestVisible="False"
                            BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                            Background="{TemplateBinding Background}" 
                            />
                    <TextBox Name="editTextBox"
                                Grid.ZIndex="1" Opacity="0"
                                Margin="0" Padding="{TemplateBinding Padding}"
                                HorizontalAlignment="Stretch" VerticalAlignment="Center"
                                TextAlignment="Right"
                                Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content, Mode=TwoWay}"
                                BorderThickness="{TemplateBinding BorderThickness}" 
                                />
                    <Border BorderBrush="{x:Null}" Height="{Binding ElementName=editTextBox, Path=ActualHeight}" Margin="0,0,3,0"
                            Padding="{TemplateBinding BorderThickness}">
                        <TextBlock Name="displayTextBlock" 
                                    Grid.ZIndex="2" IsHitTestVisible="False"
                                    VerticalAlignment="Center" HorizontalAlignment="Stretch" 
                                    Margin="{TemplateBinding Padding}"
                                    TextAlignment="Right"
                                    Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content, StringFormat={}{0:#.###;-#.###;0}, Mode=OneWay}"
                                    />
                    </Border>
                    <Border/>
                </Grid>
            </ContentPresenter.Content>
        </ContentPresenter>
        <ControlTemplate.Triggers>
            <Trigger SourceName="editTextBox" Property="IsKeyboardFocused" Value="True">
                <Setter TargetName="displayTextBlock" Property="Opacity" Value="0" />
                <Setter TargetName="editTextBox" Property="Opacity" Value="1" />
                <Setter TargetName="nonFocusedBorder" Property="Visibility" Value="Collapsed"/>
            </Trigger>
            <Trigger Property="BorderThickness" Value="0">
                <Setter TargetName="editTextBox" Property="BorderThickness" Value="1" />
                <Setter TargetName="nonFocusedBorder" Property="BorderThickness" Value="1" />
                <Setter TargetName="nonFocusedBorder" Property="BorderBrush" Value="Transparent" />
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    
    <Style x:Key="EditableDecimalLabel" TargetType="{x:Type Label}">
        <Setter Property="Template" Value="{StaticResource EditableDecimalTemplate}" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        <Setter Property="VerticalContentAlignment" Value="Stretch"/>
        <Setter Property="Padding" Value="4" />
        <Setter Property="FontFamily" Value="Consolas, Lucida Console, Courier New"/>
        <Setter Property="TextElement.FontSize" Value="13" />
        <Setter Property="SnapsToDevicePixels" Value="True"/>
        <Setter Property="BorderThickness" Value="1" />
        <Style.Triggers>
            <Trigger Property="IsMouseOver" Value="True">
                <Setter Property="BorderBrush" Value="#B5CFFF"/>
            </Trigger>
        </Style.Triggers>
    </Style>
    

    及示例用法:

    <Label Name="TestControl"
           Width="120"
           Content="{Binding Path=MyNumber, Mode=TwoWay}"
           Style="{StaticResource EditableDecimalLabel}"
           />
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-15
      相关资源
      最近更新 更多