【问题标题】:XAML how to make a textblock/text box edit toggle?XAML 如何进行文本块/文本框编辑切换?
【发布时间】:2012-12-10 13:21:37
【问题描述】:

我可能完全搞错了,如果您有其他建议,请告诉我。

我正在为 Windows RT 制作一个应用程序,它将向用户显示一堆文本块,例如字符统计信息。 用户将看到:

力量:10 缺点:10 敏捷:10

等等。

我希望他们能够填写这些,然后根据结果计算选择视图值。

我的想法是点击顶部的“编辑”按钮并在每个可编辑文本块上切换一些文本框。

当尝试使用“Blend for Visual Studio”进行设置时,我似乎无法制作小于 49x34(比我的文本块大得多)的文本框。

我打算找到一种方法,在单击按钮时为每个文本块(使用其尺寸)生成一个文本框,但由于它们总是相同的,而且会有很多我试图制作它们通过混合静态。

我对 XAML 很陌生,我似乎找不到一个很好的例子来设置这样的可编辑字段,那么我应该如何让一堆静态字段具有可编辑的文本框?

【问题讨论】:

    标签: xaml winrt-xaml


    【解决方案1】:

    您可能希望为 TextBox 使用一种样式,该样式会根据“IsReadOnly”属性是否为真而改变。

    当 IsReadOnly 为 true 时,您可以将 BorderBrush 和 Background 设置为透明,从而使其看起来像一个普通的文本块。

    这样,你就不必叠加TextBlocks和TextBoxes了;只需单独使用 TextBox 控件,并在单击“编辑”按钮时切换“IsReadOnly”属性。

    在您的资源中:

    <Style x:Key="MyEditableField" TargetType={x:Type TextBox}>
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsReadOnly, RelativeSource={RelativeSource Self}}" Value="True">
                <Setter Property="BorderBrush" Value="Transparent" />
                <Setter Property="Background" Value="Transparent" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
    

    这是您的可编辑字段之一:

    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Str: " />
        <TextBox Style="{StaticResource MyEditableField}"
                 Text="{Binding Strength}"
                 IsReadOnly="{Binding IsEditingDisabled}" />
    </StackPanel>
    

    【讨论】:

    • 那么,如果我的理解是正确的,数据触发意味着如果我将其设置为只读,BorderBrush 和 Background 将触发并关闭?
    • 我似乎在 TargetType={x:Type TextBox} 上遇到错误,它不喜欢它作为有效名称。 和 Datatrigger 似乎也抛出错误。我从根本上误解了它的工作原理,还是我需要包含一些库? (今天早上在网上搜索的结果不多)
    • 哦,天哪,经过进一步调查,Windows 8 XAML 不再支持 Style.Triggers。看起来您现在应该使用 VisualStateManager 。这个答案需要更多的研究,因为结合使用 VisualStateManager + Attahced 行为进行手动转换听起来有点过分满足您的需求。我可能会发布一个全新的答案来帮助您使用以前的方法。
    • 谢谢!我一直在努力想弄清楚为什么我的 winRT 项目不喜欢它。教程和文档似乎比 XNA 缺乏很多,所以我遇到了困难(作为教程学习者)。我很快就会玩弄你的新答案:)
    • 第二个答案有帮助吗?
    【解决方案2】:

    我会在 XAML 中创建 TextBox 和 TextBlock 叠加层,并将它们直接放在一个网格中,使用水平和垂直对齐到“中心”以确保文本始终完全对齐。我还会使用静态宽度来确保列对齐。

    从那里,您可以直接将 Visibility 绑定到某个布尔“IsEditing”属性,以确保一次只显示一个控件。

    <StackPanel Orientation="Horizontal">
        <TextBlock Text="Str: " Width="40" VerticalAlignment="Center" />
        <Grid Width="40" VerticalAlignment="Center">
            <TextBlock Text="{Binding Strength}" 
                Visibility="{Binding IsEditing, Converter={StaticResource BooleanToInvisibilityConverter}}"
                VerticalAlignment="Center" 
                HorizontalAlignment="Center" />
            <TextBox Text="{Binding Strength}" 
                Visibility="{Binding IsEditing, Converter={StaticResource BooleanToVisibilityConverter}}"
                VerticalAlignment="Center" 
                HorizontalContentAlignment="Center" />
        </Grid>
    </StackPanel>
    

    在此过程中,您必须定义“BooleanToVisibility”和“BooleanToInvisiblity”转换器资源。我喜欢this implementation by Diedrik Krols。它既漂亮又简单,带有反转选项。

    【讨论】:

    • 这看起来正是我所需要的。我只需要设置它。谢谢!
    • 从头开始,我只是在我的项目中设置它,当我尝试添加类似“" 为什么这个 XAML 如此不同?似乎应该有一个简单的方法来做到这一点。
    • 我在答案的最后提到:你必须实现一个 IValueConverter。按照链接获取示例实现。
    • 我实现了第一个位(他在 mvvm 命名空间中,但我把它放在我自己的命名空间中)。感谢您指出这一点,因为它让我回过头来看看并意识到我忘记输入告诉我的 XAML 命名空间存在的位!回到破解它:)
    • 我不确定这里的礼仪,所以如果这个回复不应该是评论,请告诉我。在我的 App.xaml 文件中添加 'xmlns:Pathfinder="using:MyNameSpace"' 后,我仍然收到错误消息。我想我误解了如何将它添加到 App.xaml 文件中。将其移出(已声明的)“”标签时出现不同的错误。无论我把它放在哪里,我总是收到错误“BooleanToVisibilityConverter 在命名空间'using:MyNameSpace'中不存在”我想我可能只是从根本上误解了这里的一些东西。
    【解决方案3】:

    使用属性在视图和视图模型之间切换编辑模式是一种糟糕的设计方法,您应该使用事件和命令绑定来传达视图和视图模型之间的这种状态变化。

    这是一篇以符合 MVVM 的方式描述原理的文章: http://www.codeproject.com/Articles/802385/A-WPF-MVVM-In-Place-Edit-TextBox-Control

    请看看并告诉我你的想法。

    【讨论】:

      【解决方案4】:

      迟到的答案,但谁想要也可以创建一个自定义的可编辑文本框,实际上很容易这里是代码(显然你可以根据自己的需要修改它)

       public class EditableTextBox : TextBox
      {
          public EditableTextBox()
          {
              this.BorderBrush = new SolidColorBrush(Colors.Black);
          }
          protected override void OnTapped(TappedRoutedEventArgs e)
          {
              this.IsReadOnly = false;
              SetEditingStyle();
              base.OnTapped(e);
          }
      
          protected override void OnDoubleTapped(DoubleTappedRoutedEventArgs e)
          {
              this.IsReadOnly = false;
              SetEditingStyle();
              base.OnDoubleTapped(e);
          }
      
          protected override void OnLostFocus(RoutedEventArgs e)
          {
              this.IsReadOnly = true;
              SetReadonlyStyle();
              base.OnLostFocus(e);
          }
      
          public void SetReadonlyStyle()
          {
              this.BorderBrush.Opacity = 0;
              this.Background.Opacity = 0;
          }
      
          public void SetEditingStyle()
          {
              this.BorderBrush.Opacity = 1;
              this.Background.Opacity = 1;
          }
      }
      

      示例:

      教程:Full tutorial url

      【讨论】:

        【解决方案5】:

        这建立在 BTownTKD 的解决方案之上,但由于我确实更喜欢尽可能多的 WPF 解决方案,因此这里进行了一些修改,在我的情况下,我正在尝试修改选项卡控件的名称。

        我的视图模型有以下代码:

            private bool _isEditingName = false;
        
            public bool IsEditingName
            {
                get
                {
                    return _isEditingName;
                }
                set
                {
                    _isEditingName = value;
                    OnPropertyChanged();
                }
            }
        
            public ICommand StartEditing
            {
                get
                {
                    return new DelegateCommand(() =>
                    {
                        IsEditingName = true;
                    });
                }
            }
        
            public ICommand EndEditing
            {
                get
                {
                    return new DelegateCommand(() =>
                    {
                        IsEditingName = false;
                    });
                }
            }
        

        接下来是我的视图,其中包含选项卡的数据模板(不仅仅是选项卡的内容):

        <TabControl ItemsSource="{Binding Items}" SelectedItem="{Binding ActiveItem}">
            <TabControl.ItemTemplate>
                <DataTemplate>
                    <Grid VerticalAlignment="Center">
                        <TextBlock x:Name="TabName" Text="{Binding Name}" Visibility="{Binding IsEditingName, Converter={StaticResource InvertedBoolToVisConverter}}" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextAlignment="Left">
                            <TextBlock.InputBindings>
                                <MouseBinding MouseAction="LeftDoubleClick" Command="{Binding StartEditing}" />
                            </TextBlock.InputBindings>
                        </TextBlock>
                        <TextBox Text="{Binding Name}" Visibility="{Binding IsEditingName, Converter={StaticResource BoolToVisConverter}}" VerticalAlignment="Center" HorizontalContentAlignment="Stretch" TextAlignment="Left" IsVisibleChanged="TextBox_IsVisibleChanged">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="LostFocus">
                                    <i:InvokeCommandAction Command="{Binding EndEditing}" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                            <TextBox.InputBindings>
                                <KeyBinding  Key="Enter" Command="{Binding EndEditing}" />
                            </TextBox.InputBindings>
                        </TextBox>
                    </Grid>                 
                </DataTemplate>
            </TabControl.ItemTemplate>  
        </TabControl>
        

        最后但并非最不重要的一点是,我想要双击以使我进入编辑模式,并自动关注文本框并选择所有内容以便立即输入。没有一个 xaml 解决方案像背后的简单代码一样干净,所以我最终决定将其添加到可见性更改处理程序的文本框中:

            private void TextBox_IsVisibleChanged(object sender, System.Windows.DependencyPropertyChangedEventArgs e)
            {
                var box = sender as TextBox;
                if (box != null)
                {
                    if ((bool)e.NewValue)
                    {
                        box.Focus();
                        box.SelectAll();
                    }
                }
            }
        

        在我找到的所有解决方案中,这是我最喜欢的。谢谢大家的帖子!!帮助我找到了一个非常好的整体解决方案!

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-03-09
          • 1970-01-01
          • 1970-01-01
          • 2012-01-09
          相关资源
          最近更新 更多