在组合框中滑动文本 [英] Sliding text in combobox

查看:61
本文介绍了在组合框中滑动文本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果所选项目的长度大于组合框的宽度,我想在组合框中滑动文本(选取框文本)。它可以是自动的,也可以在用户将鼠标放在组合框上时使用。问题是我完全不知道该怎么做。可能可以通过渲染转换(内部文本框的先前定义)来做到这一点?还是带有情节提要?

I would like to slide the text (marquee text) of the selected item in a combobox, if it's lenght is bigger than the width of the combobox. It can be either automatical or when the user put the mouse over the combobox. The problem is that i have absolutely no idea on how to do that. It's maybe possible to do that with a render transform (previous definition of a textblock inside it)? or with a storyboard?

这是我需要修改的xaml

Here is the xaml that i need to modify

<DataGrid.ColumnHeaderStyle>
     <Style TargetType="{x:Type DataGridColumnHeader}">
          <Setter Property="ContentTemplate" >
              <Setter.Value>
                  <DataTemplate DataType="DataGridColumnHeader"  >
                      <ComboBox ItemContainerStyle="{StaticResource SingleSelectionComboBoxItem}" DisplayMemberPath="Oggetto" Width="100" Height="20" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}},Path=DataContext.Selezione, UpdateSourceTrigger=LostFocus}"  SelectionChanged="SingleSelectionComboBox_SelectionChanged"/>
                  </DataTemplate>
              </Setter.Value>
          </Setter>
      </Style>
</DataGrid.ColumnHeaderStyle>

编辑:问题是我不知道我应该在情节提要中定位哪些属性

the problem is that i don't know which properties should i target in the storyboard

编辑2:我采用了组合框的模板,并修改了文本框部分,如下所示:

i took the template of the combobox and modified the text box section like this :

<Style x:Key="ComboBoxEditableTextBox" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <EventTrigger RoutedEvent="MouseEnter">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation From="0" To="100" Duration="00:00:10" Storyboard.TargetProperty="X" Storyboard.TargetName="transferCurreny" RepeatBehavior="Forever"  />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Style.Triggers>
            <Setter Property="RenderTransform">
                <Setter.Value>
                    <TranslateTransform x:Name="transferCurreny" X="0"/>
                </Setter.Value>
            </Setter>

问题是这似乎没有效果

编辑3:我意识到我必须使用具有上述样式的模板

EDIT 3: i realized that i had to use the template that use the style i mentioned above

            <ControlTemplate x:Key="ComboBoxEditableTemplate" TargetType="{x:Type ComboBox}">
            <Grid x:Name="Placement" SnapsToDevicePixels="true">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="Auto" />
                </Grid.ColumnDefinitions>
                <Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2"
               IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
               PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}"
               Placement="Bottom">
                    <Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent"
                                           MaxHeight="{TemplateBinding MaxDropDownHeight}"
                                           MinWidth="{Binding ActualWidth, ElementName=Placement}">
                        <Border x:Name="DropDownBorder"
                        BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}"
                        BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
                            <ScrollViewer x:Name="DropDownScrollViewer">
                                <Grid RenderOptions.ClearTypeHint="Enabled">
                                    <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                        <Rectangle x:Name="OpaqueRect"
                                           Fill="{Binding Background, ElementName=DropDownBorder}"
                                           Height="{Binding ActualHeight, ElementName=DropDownBorder}"
                                           Width="{Binding ActualWidth, ElementName=DropDownBorder}" />
                                    </Canvas>
                                    <ItemsPresenter x:Name="ItemsPresenter"
                                            KeyboardNavigation.DirectionalNavigation="Contained"
                                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                                </Grid>
                            </ScrollViewer>
                        </Border>
                    </Themes:SystemDropShadowChrome>
                </Popup>
                <Themes:ListBoxChrome x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}"
                              BorderThickness="{TemplateBinding BorderThickness}"
                              Background="{TemplateBinding Background}" Grid.ColumnSpan="2"
                              RenderMouseOver="{TemplateBinding IsMouseOver}"
                              RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" />
            <TextBox x:Name="PART_EditableTextBox"
                 HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                 IsReadOnly="{Binding IsReadOnly, RelativeSource={RelativeSource TemplatedParent}}"
                 Margin="{TemplateBinding Padding}" Style="{StaticResource ComboBoxEditableTextBox}"
                 VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" >
            </TextBox>
                <ToggleButton Grid.Column="1"
                      IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                      Style="{StaticResource ComboBoxToggleButton}" />
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsKeyboardFocusWithin" Value="true">
                    <Setter Property="Foreground" Value="Black" />
                </Trigger>
                <Trigger Property="IsDropDownOpen" Value="true">
                    <Setter Property="RenderFocused" TargetName="Border" Value="true" />
                </Trigger>
                <Trigger Property="HasItems" Value="false">
                    <Setter Property="Height" TargetName="DropDownBorder" Value="95" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                    <Setter Property="Background" Value="#FFF4F4F4" />
                </Trigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsGrouping" Value="true" />
                        <Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="false" />
                    </MultiTrigger.Conditions>
                    <Setter Property="ScrollViewer.CanContentScroll" Value="false" />
                </MultiTrigger>
                <Trigger Property="HasDropShadow" SourceName="PART_Popup" Value="true">
                    <Setter Property="Margin" TargetName="Shdw" Value="0,0,5,5" />
                    <Setter Property="Color" TargetName="Shdw" Value="#71000000" />
                </Trigger>
                <Trigger Property="ScrollViewer.CanContentScroll" SourceName="DropDownScrollViewer" Value="false">
                    <Setter Property="Canvas.Top" TargetName="OpaqueRect"
                    Value="{Binding VerticalOffset, ElementName=DropDownScrollViewer}" />
                    <Setter Property="Canvas.Left" TargetName="OpaqueRect"
                    Value="{Binding HorizontalOffset, ElementName=DropDownScrollViewer}" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

文本框部分是使用样式的部分。但是,当我在组合框中执行 Template = {StaticResource ComboBoxEditableTemplate} 时,即使它不为空,我也看不到所选项目

the textbox section is the one that use the style. However when i do Template="{StaticResource ComboBoxEditableTemplate}" in the combobox, i cannot see the selected item anymore, even if it's not null

推荐答案

更新08/02

基本上是为了避免动画您面临的问题-您需要将 ScrollViewer 作为包装器添加到内容站点或选择框 TextBlock 。您可以通过为 ComboBox 使用自定义模板选择器(如以下定义)来执行此操作,或者通过 ScollViewer

Basically in order to avoid the animation issues you are facing - you will need to add a ScrollViewer as a wrapper to the content-site or selection-box TextBlock. You can either do that by using a custom template selector for your ComboBox so as defined below, or provide a custom item-template with ScollViewer.

第二,您可以在C#中创建自定义 ComboBox 控件以绑定上述模板-selector / item-template并在 MouseEnterEvent 上应用幻灯片动画;

Secondly, you can either create a custom ComboBox control in C# to bind the above template-selector/item-template and apply slide-animation on MouseEnterEvent; or implement the same in XAML itself.

在此示例中-已在C#中实现了控件,并在XAML中提供了
示例用法。

For this example - have implemented the control in C#, and provided a sample usage in XAML.

public class SlidingComboBox : ComboBox
{
    public static readonly DependencyProperty SlideForeverProperty = DependencyProperty.Register("SlideForever", typeof(bool), typeof(SlidingComboBox), new FrameworkPropertyMetadata(false));
    public bool SlideForever
    {
        get { return (bool)GetValue(SlideForeverProperty); }
        set { SetValue(SlideForeverProperty, value); }
    }

    protected ContentPresenter _parent;
    protected DoubleAnimation _animation;
    protected TranslateTransform _translate;
    protected Storyboard _storyBoard;

    public SlidingComboBox()
    {
        Loaded += ExComboBox_Loaded;
        ClipToBounds = true;

        //assign template selector - just to re-template ContentSite / selection box 
        //uncomment this code - if you want to default-template for popup-items
        //ItemTemplateSelector = new SlidingComboBoxItemTemplateSelector();        
    }

    private void ExComboBox_Loaded(object sender, RoutedEventArgs e)
    {
        Loaded -= ExComboBox_Loaded;

        //get content-site holder/parent
        _parent = this.GetChildOfType<ContentPresenter>();

        //setup slide animation
        _animation = new DoubleAnimation()
        {
            From = 0,
            RepeatBehavior = SlideForever ? RepeatBehavior.Forever : new RepeatBehavior(1), //repeat only if slide-forever is true
            AutoReverse = SlideForever
        };

        //create storyboard
        _storyBoard = new Storyboard();
        _storyBoard.Children.Add(_animation);
        Storyboard.SetTargetProperty(_animation, new PropertyPath("RenderTransform.(TranslateTransform.X)"));
    }

    protected override void OnMouseEnter(MouseEventArgs e)
    {
        //get actual textblock that renders the selected value
        var textBlock = _parent.GetChildOfType<TextBlock>();
        //and translate-transform for animation
        textBlock.RenderTransform = _translate = new TranslateTransform();

        //start animation only if text-block width is greater than parent
        if (_parent.ActualWidth < textBlock.ActualWidth)
        {
            _animation.Duration = TimeSpan.FromMilliseconds(((int)textBlock.Text?.Length * 100));
            _animation.To = _parent.ActualWidth - textBlock.ActualWidth;
            _storyBoard.Begin(textBlock);
        }

        base.OnMouseEnter(e);
    }

    protected override void OnMouseLeave(MouseEventArgs e)
    {
        //stop animation once mouse pointer is off the control
        _storyBoard.Stop();

        //reset render state
        var textBlock = _parent.GetChildOfType<TextBlock>();
        textBlock.RenderTransform = _translate = new TranslateTransform();

        base.OnMouseLeave(e);
    }

}

public class SlidingComboBoxItemTemplateSelector : DataTemplateSelector
{
    DataTemplate _selectedItemTemplate;

    public SlidingComboBoxItemTemplateSelector()
    {
        //create datatemplate with ScrollViewer and TextBlock as child
        var textBlock = new FrameworkElementFactory(typeof(TextBlock));
        textBlock.SetValue(TextBlock.TextWrappingProperty, TextWrapping.NoWrap);
        textBlock.SetBinding(TextBlock.TextProperty, new Binding("SelectedValue")
        {
            RelativeSource = new RelativeSource { Mode = RelativeSourceMode.FindAncestor, AncestorType = typeof(ComboBox) }
        });
        var scrollViewer = new FrameworkElementFactory(typeof(ScrollViewer));
        scrollViewer.SetValue(ScrollViewer.CanContentScrollProperty, true);
        scrollViewer.SetValue(ScrollViewer.HorizontalScrollBarVisibilityProperty, ScrollBarVisibility.Hidden);
        scrollViewer.SetValue(ScrollViewer.VerticalScrollBarVisibilityProperty, ScrollBarVisibility.Disabled);
        scrollViewer.AppendChild(textBlock);

        _selectedItemTemplate = new DataTemplate
        {
            VisualTree = scrollViewer
        };
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        ComboBoxItem comboBoxItem = container.GetVisualParent<ComboBoxItem>();
        if (comboBoxItem == null)
        {
            //send back only if template requested for ContentSite, and not for combo-box item(s)
            return _selectedItemTemplate;
        }
        return null;
    }
}

/// <summary>
/// VisualTree helper
/// </summary>
public static class HelperExtensions
{
    public static T GetChildOfType<T>(this DependencyObject depObj) where T : DependencyObject
    {
        if (depObj == null) return null;

        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            var child = VisualTreeHelper.GetChild(depObj, i);

            var result = (child as T) ?? GetChildOfType<T>(child);
            if (result != null) return result;
        }
        return null;
    }

    public static T GetVisualParent<T>(this DependencyObject child) where T : Visual
    {
        while ((child != null) && !(child is T))
        {
            child = VisualTreeHelper.GetParent(child);
        }
        return child as T;
    }
}



示例用法:



Sample usage:

<Window x:Class="MarqueeSample.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:MarqueeSample"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:col="clr-namespace:System.Collections;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="400">
    <Grid Margin="20">
        <DataGrid AutoGenerateColumns="False" IsReadOnly="True" Width="225" VerticalAlignment="Center">
            <DataGrid.ItemsSource>
                <col:Hashtable>
                    <col:ArrayList x:Key="TestData1">
                        <sys:String>Tiny</sys:String>
                        <sys:String>Keep calm and love programming</sys:String>
                    </col:ArrayList>
                    <col:ArrayList x:Key="TestData2">
                        <sys:String>Sample string</sys:String>
                        <sys:String>Another string to test</sys:String>
                    </col:ArrayList>
                </col:Hashtable>
            </DataGrid.ItemsSource>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Width="100" Binding="{Binding Key}" />
                <DataGridTemplateColumn Header="Value" Width="100">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <local:SlidingComboBox ItemsSource="{Binding Value}">
                                <local:SlidingComboBox.ItemTemplate>
                                    <DataTemplate>
                                        <ScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled">
                                            <TextBlock Text="{Binding}" />
                                        </ScrollViewer>
                                    </DataTemplate>
                                </local:SlidingComboBox.ItemTemplate>
                            </local:SlidingComboBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

您还可以使用SlideForever属性来操纵RepeatBehaviour。

You can also use SlideForever property to manipulate RepeatBehaviour.

<local:SlidingComboBox ItemsSource="{Binding Value}" SlideForever="True" />

这篇关于在组合框中滑动文本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆