【问题标题】:TextBox Style - Binding to width of text文本框样式 - 绑定到文本宽度
【发布时间】:2017-07-07 15:52:00
【问题描述】:

我有一个文本框的样式。我在其中对带有附加矩形的 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 条可以延伸,我希望它与文本一样宽

我必须在控件模板的设置器中放入什么以及绑定必须是什么?

【问题讨论】:

  • 试试实际宽度。
  • @EdPlunkett 瞄准什么对象。定位滚动查看器会捕获文本框的宽度而不是我输入的文本?
  • 我为您提供了您提供的信息所能达到的详细程度。我不会对您的模板中的内容进行猜谜游戏。
  • @EdPlunkett 我已经对帖子进行了更详细的编辑。请您考虑更改
  • 您无法仅在 XAML 中将其作为可重用的 ControlTemplate 来完成。你需要编写转换器来考虑诸如 FontSize、FontFamily、CultureInfo 等我个人知道我没有时间去免费计算的东西。但是,如果这是一个小的用途,例如您只需要一个实例,那么我可以在纯 xaml 中向您展示一个非常快速的解决方法来实现您的目标,如果您愿意,您可以变成说一个 ContentControl 以供重用。不过,我强调快速解决方法。

标签: c# wpf xaml


【解决方案1】:

你们很亲密。

首先,我将HorizontalAlignment="Left" 添加到ScrollViewer,以防止它拉伸到其父级的整个宽度。

其次,我删除了ScaleTransform,它将矩形缩小到水平大小为零。

<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 内单击以使其获得焦点,这样他才能开始输入,而滚动查看器是挤在控件左侧的一个小东西。我正在寻找一些方法来做到这一点;等待更新。

更新

如何在不对 MVVM 犯任何罪的情况下处理鼠标按下的焦点:

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
    }
}

XAML:

<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>

【讨论】:

  • 我什至没有想到仍然使用滚动查看器的实际宽度并且只是传递焦点。 +1伙计。 :)
【解决方案2】:

所以 Ed 的更好。我什至没有想过只处理焦点并让 ScrollViewer 的 ActualWidth 提供值。我正在考虑更深入地实际测量 ScrollViewer 中的文本元素作为逻辑子元素,这在我看来会更多地参与。除了他的方式行得通。但是,不久前我也遇到了一个问题,严格要求只允许 XAML 而没有代码隐藏来完成同样的事情。除了它是单实例表单输入并且允许这种快速破解。

我会亲自选择 Ed,但提交只是作为一个快速的替代方案,你可以做这样的事情,然后背负这些值以从另一个元素中获取 ActualWidth。它不优雅,但很简单......

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>

干杯!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-22
    • 1970-01-01
    • 2012-01-02
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多