TextBox样式 - 绑定到文本宽度

时间:2017-07-07 15:52:00

标签: c# wpf xaml

我有一个textBox样式。我在其中更改了带有附加矩形的textBox控件模板。我希望矩形的宽度绑定到已键入的文本的宽度。

这是当前的风格

<Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TextBoxBase}">
                <Border Name="Border"
                        Padding="2"             
                        Background="{DynamicResource White#}">

                    <StackPanel VerticalAlignment="Center">
                        <ScrollViewer Margin="0" x:Name="PART_ContentHost" />
                        <Rectangle x:Name="Rect1" Width="{Binding ActualWidth, ElementName=PART_ContentHost}" Height="2" Fill="{TemplateBinding Foreground}" Opacity="0.8">
                            <Rectangle.LayoutTransform>
                                <ScaleTransform ScaleX="0" />
                            </Rectangle.LayoutTransform>
                        </Rectangle>
                    </StackPanel>
                </Border>
           </ControlTemplate>

        </Setter.Value>
    </Setter>

这个xaml栏延伸我希望它只是与文本

一样宽

我需要在控件模板的setter中添加什么以及绑定必须是什么?

2 个答案:

答案 0 :(得分:2)

你非常接近。

首先,我将ScrollViewer添加到ScaleTransform,以防止它扩展到其父级的全宽。

其次,我删除了将Rectangle缩小到零水平大小的<StackPanel VerticalAlignment="Center" > <ScrollViewer Margin="0" x:Name="PART_ContentHost" HorizontalAlignment="Left" /> <Rectangle x:Name="Rect1" Width="{Binding ActualWidth, ElementName=PART_ContentHost}" Height="2" Fill="{TemplateBinding Foreground}" Opacity="0.8" HorizontalAlignment="Left" > </Rectangle> </StackPanel>

ScrollViewer

现在你还有另外一个问题:用户必须在using System.ComponentModel; using System.Windows; using System.Windows.Input; namespace MyRandomNamespace { public static class Extensions { #region Extensions.MouseDownFocusRecipient Attached Property // Attached property. See XAML example below for usage. // On mouse down, sets focus on bound target control. public static UIElement GetMouseDownFocusRecipient(UIElement obj) { return (UIElement)obj.GetValue(MouseDownFocusRecipientProperty); } public static void SetMouseDownFocusRecipient(UIElement obj, UIElement value) { obj.SetValue(MouseDownFocusRecipientProperty, value); } public static readonly DependencyProperty MouseDownFocusRecipientProperty = DependencyProperty.RegisterAttached("MouseDownFocusRecipient", typeof(UIElement), typeof(Extensions), new PropertyMetadata(null, MouseDownFocusRecipient_PropertyChanged)); private static void MouseDownFocusRecipient_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var target = d as UIElement; // Target must have some kind of background color or it will ignore mouse events. // We can't do this object-orientedly because multiple Background dependency // properties are defined in multiple control classes. var bkgDepProp = DependencyPropertyDescriptor.FromName("Background", target.GetType(), target.GetType(), true); if (bkgDepProp != null && bkgDepProp.GetValue(target) == null) { bkgDepProp.SetValue(target, System.Windows.Media.Brushes.Transparent); } //target.IsHitTestVisible = true; target.PreviewMouseDown -= Target_PreviewMouseDown; target.PreviewMouseDown += Target_PreviewMouseDown; } private static void Target_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e) { var target = (UIElement)sender; var otherControl = GetMouseDownFocusRecipient(target); if (otherControl != null) { Keyboard.Focus(otherControl); } } #endregion Extensions.MouseDownFocusRecipient Attached Property } } 内点击以使其获得焦点,这样他才能开始输入,而滚动查看器则是一个挤在控件左侧的小东西。我正在寻找一些方法来做到这一点;等待更新。

更新

如何处理mousedown而不对MVVM提出任何错误:

<ControlTemplate TargetType="{x:Type TextBoxBase}" x:Key="TextBoxTemplate">
    <Border 
        Name="Border"
        Padding="2"             
        Background="{DynamicResource White#}"
        local:Extensions.MouseDownFocusRecipient="{Binding ElementName=PART_ContentHost}"
        >
        <StackPanel 
            VerticalAlignment="Center" 
            MouseDown="StackPanel_MouseDown"
            >
            <ScrollViewer 
                Margin="0" 
                x:Name="PART_ContentHost" 
                HorizontalAlignment="Left" 
                />
            <Rectangle 
                x:Name="Rect1" 
                Width="{Binding ActualWidth, ElementName=PART_ContentHost}" 
                Height="8" 
                Fill="{TemplateBinding Foreground}" Opacity="0.8"
                IsHitTestVisible="False"
                HorizontalAlignment="Left"
                />
        </StackPanel>
    </Border>
</ControlTemplate>

XAML:

target

答案 1 :(得分:1)

所以Ed更好。我甚至没有考虑只处理焦点并让ScrollViewer的ActualWidth提供值。我想更多地沉浸在实际测量ScrollViewer中的Text Element作为逻辑子元素,这在我看来会更加复杂。除了他的方式工作。然而,我也遇到了一个问题,因为严格的要求只允许XAML而没有代码隐藏来完成同样的事情。除了它是一个单实例表单输入,允许这个快速黑客。

我会亲自与Ed一起去,但提交作为一个快速的替代方案,你可以做这样的事情,并只是背负值,以使ActualWidth脱离另一个元素。它不优雅,但很简单......

enter image description here

PoC xaml;

Grid VerticalAlignment="Center" HorizontalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

            <TextBlock x:Name="theText" 
                       Text="{Binding Text, ElementName=theBox, UpdateSourceTrigger=PropertyChanged}" 
                       HorizontalAlignment="Left" Opacity="0"/>
            <TextBox   x:Name="theBox" 
                       Height="30" Width="250" MaxLength="50"/>
            <Rectangle Grid.Row="1" Fill="Green" 
                       Width="{Binding ActualWidth, ElementName=theText}" 
                       HorizontalAlignment="Left" Height="25"/>
    </Grid>

干杯!