动态调整WPF TextBlock大小时的性能不佳

时间:2022-09-17 21:34:10

I'm currently working out the layout of a WPF Application and seem to have it a bit of a snag in the layout of one of my controls. This control is a dynamically sizing, so it should fit the size of the viewport it's a part of. The problem I'm running into is a very visual problem, so I'll do my best to describe it. Here's what it looks like at the moment:

我目前正在研究WPF应用程序的布局,并且似乎在我的一个控件的布局中有一些障碍。此控件是动态调整大小的,因此它应该适合它所属视口的大小。我遇到的问题是一个非常直观的问题,所以我会尽力描述它。这就是目前的样子:

alt text http://gallery.me.com/theplatz/100006/Capture/web.png?ver=12472534170001

替代文字http://gallery.me.com/theplatz/100006/Capture/web.png?ver=12472534170001

The area underneath each of the "Col N Row X" headers is a TextBlock where text of varying length will be placed. To make the TextBlock actually wrap, I found a solution here on * that said to bind the width of the textblock to that of the column. Here's a snippet of the Grid definition along with the definition for the first column:

每个“Col N Row X”标题下面的区域是一个TextBlock,其中将放置不同长度的文本。为了使TextBlock实际换行,我在*上找到了一个解决方案,它说将textblock的宽度绑定到列的宽度。这是Grid定义的片段以及第一列的定义:

<!-- Change Detail Contents Grid -->
<Grid Grid.Row="1">
    <Grid.ColumnDefinitions>
    <ColumnDefinition MinWidth="270" Width="2*" />
    <ColumnDefinition MinWidth="160" Width="*" />
    <ColumnDefinition MinWidth="160" Width="*" />
    <ColumnDefinition MinWidth="160" Width="*" />
    </Grid.ColumnDefinitions>

    <!-- 
    We bind the width of the textblock to the width of this border to make sure things resize correctly.
    It's important that the margin be set to 1 larger than the margin of the textblock or else you'll end
    up in an infinate loop 
    -->
    <Border Grid.Column="0" Margin="6" Name="FirstBorder" />
    <Border Grid.Column="0" BorderThickness="0,0,1,0" BorderBrush="{DynamicResource   ColumnBorderBrush}">
    <Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>

    <StackPanel Grid.Row="0">
        <Border Style="{DynamicResource DetailHeadingBorder}">
                <TextBlock Text="Col 1 Row 1" Style="{DynamicResource DetailHeadingText}" />
            </Border>
                <TextBlock Text="{Binding IsReason, ElementName=ChangeDetailRoot}" Style="{DynamicResource DetailText}" Width="{Binding ActualWidth, ElementName=FirstBorder}" />
            </StackPanel>

    <StackPanel Grid.Row="1">
            <Border Style="{DynamicResource DetailHeadingBorder}">
            <TextBlock Text="Col 1 Row 2" Style="{DynamicResource DetailHeadingText}" />
            </Border>
        <TextBlock Text="{Binding WasReason, ElementName=ChangeDetailRoot}" Style="{DynamicResource DetailText}" Width="{Binding ActualWidth, ElementName=FirstBorder}" />
    </StackPanel>   
    </Grid>
    </Border>
</Grid>

Everything resizes fine when the window/viewport width is increasing. The problem become apparent when the width is decreased. If you suddenly go from maximized to the original size, all of the columns "dance" back to their specified size. What I mean by this is that you can watch each column reduce in size, as it's proportionally resized back to its smaller size. What I've found is that this is directly caused by

当窗口/视口宽度增加时,所有内容都会调整大小。当宽度减小时,问题变得明显。如果您突然从最大化变为原始大小,则所有列都“跳”回到指定的大小。我的意思是你可以看到每个列的大小减小,因为它按比例调整回原来缩小尺寸。我发现这是由直接引起的

Width="{Binding ActualWidth, ElementName=FirstBorder}"

on each of the TextBlocks. The problem also become noticeably worse the more of these controls are on the screen at one time. But, without that line, the text inside each of the TextBlocks will continue to grow to the right the more text is added instead of wrapping down in the column.

在每个TextBlocks上。这些控件一次出现在屏幕上的问题也越来越严重。但是,如果没有该行,每个TextBlocks内的文本将继续向右增长,添加的文本越多,而不是在列中包装。

Is there a better way to accomplish what I'm trying to accomplish? Using HTML/CSS, this would be a fairly simple thing to accomplish. I've spent hours Googling and looking through * for an answer to this question.

有没有更好的方法来完成我想要完成的任务?使用HTML / CSS,这将是一件非常简单的事情。我花了几个小时谷歌搜索并查看*来回答这个问题。

I come from a heavy background of HTML/CSS, so if this isn't something that WPF should be good at, please let me know.

我来自HTML / CSS的大背景,所以如果这不是WPF应该擅长的,请告诉我。

3 个解决方案

#1


I hate to answer my own question, but it appears that I may have found out what I was doing incorrectly. Since it's been so long since the original question was asked, I cannot remember every step I attempted to take, but this is what I do know. The style on each textblock was set as such:

我讨厌回答我自己的问题,但似乎我可能已经发现我做错了什么。既然原问题已经问了很长时间,我就不记得我试图采取的每一步,但这就是我所知道的。每个文本块的样式设置如下:

<Style x:Key="DetailText" TargetType="TextBlock">
    <Setter Property="HorizontalAlignment" Value="Center" /> 
    <Setter Property="TextWrapping" Value="Wrap" /> 
    <Setter Property="TextAlignment" Value="Center" />
    <Setter Property="Margin" Value="5,5,5,5" />
</Style>

At that time, I'm assuming that did not produce the desired results and therefore I had to bind the width of the textblock to that of the column. In playing around today, I changed the style to the following (note the different HorizontalAlignment) and removed the bindings and found out that my problem had been resolved:

那时,我假设没有产生预期的结果,因此我不得不将文本块的宽度绑定到列的宽度。在今天的游戏中,我将样式更改为以下(注意不同的Horizo​​ntalAlignment)并删除绑定并发现我的问题已解决:

<Style x:Key="DetailText" TargetType="TextBlock">
    <Setter Property="HorizontalAlignment" Value="Stretch" />
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="TextAlignment" Value="Center" />
    <Setter Property="Margin" Value="5,5,5,5" />
</Style>

#2


I apologize if you've tried this, but does setting TextBlock.TextWrapping to "Wrap" not accomplish your goal?

如果你已经尝试过,我道歉,但是将TextBlock.TextWrapping设置为“Wrap”不能实现你的目标吗?

I'm guessing that will get rid of the need for the bind-to-width stuff you're doing, as the Grid will take care of the resizing. (That is probably what is happening now: The Grid is laying out the controls as it shrinks, and the binding to width is changing the size slightly, causing the dancing.)

我猜这将消除你正在做的绑定到宽度的需要,因为Grid将负责调整大小。 (这可能就是现在正在发生的事情:网格在收缩时布置控件,并且绑定到宽度会稍微改变大小,导致跳舞。)

[Update]

I tried to duplicate the behavior you're seeing, but it works fine for me. I made a simple style for the TextBlocks like so:

我试图复制你看到的行为,但它对我来说很好。我为TextBlocks做了一个简单的样式,如下所示:

<Style x:Key="DetailText" TargetType="{x:Type TextBlock}">
    <Setter Property="TextBlock.TextWrapping" Value="Wrap"/>                
</Style>

And I didn't have any of your other dynamic resources (DetailHeadingBorder, DetailHeadingText, or ColumnBorderBrush), so everything was black and white (fine).

而且我没有你的任何其他动态资源(DetailHeadingBorder,DetailHeadingText或ColumnBorderBrush),所以一切都是黑白的(很好)。

Maybe you just have a really old graphics card and it's rendering things in software? Or it has to do with your styles.

也许你只是有一个非常古老的显卡,它在软件中呈现东西?或者它与你的风格有关。

#3


I hope I didn't misinterpret your question, but I don't see the need for binding TextBlock.Width?

我希望我没有误解你的问题,但我不认为需要绑定TextBlock.Width?

This xaml seems to work correctly:

这个xaml似乎正常工作:

  <Grid>
     <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="270"
                          Width="2*" />
        <ColumnDefinition MinWidth="160"
                          Width="*" />
        <ColumnDefinition MinWidth="160"
                          Width="*" />
        <ColumnDefinition MinWidth="160"
                          Width="*" />
     </Grid.ColumnDefinitions>
     <!--     We bind the width of the textblock to the width of this border to make sure things resize correctly.    
           It's important that the margin be set to 1 larger than the margin of the textblock or else you'll end  
             up in an infinate loop     -->
     <Border Grid.Column="0"
             BorderThickness="0,0,1,0">
        <Grid>
           <Grid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="*" />
           </Grid.RowDefinitions>
           <StackPanel Grid.Row="0">
              <Border>
                 <TextBlock Text="Col 1 Row 1" />
              </Border>
              <TextBlock TextWrapping="Wrap"
                         Text="gfege dfh lh dfl dhliöslghklj h lglsdg fklghglfg flg lgheh" />
           </StackPanel>
           <StackPanel Grid.Row="1">
              <Border>
                 <TextBlock Text="Col 1 Row 2" />
              </Border>
              <TextBlock Text="Massor av text som blir en wrappning i slutändan hoppas jag"
                         TextWrapping="Wrap" />
           </StackPanel>
        </Grid>
     </Border>
  </Grid>

I just removed the width bindings, added TextWrapping (which you probably had in a style), and removed the border named "FirstBorder" as well.

我刚刚删除了宽度绑定,添加了TextWrapping(你可能在一个样式中),并删除了名为“FirstBorder”的边框。

#1


I hate to answer my own question, but it appears that I may have found out what I was doing incorrectly. Since it's been so long since the original question was asked, I cannot remember every step I attempted to take, but this is what I do know. The style on each textblock was set as such:

我讨厌回答我自己的问题,但似乎我可能已经发现我做错了什么。既然原问题已经问了很长时间,我就不记得我试图采取的每一步,但这就是我所知道的。每个文本块的样式设置如下:

<Style x:Key="DetailText" TargetType="TextBlock">
    <Setter Property="HorizontalAlignment" Value="Center" /> 
    <Setter Property="TextWrapping" Value="Wrap" /> 
    <Setter Property="TextAlignment" Value="Center" />
    <Setter Property="Margin" Value="5,5,5,5" />
</Style>

At that time, I'm assuming that did not produce the desired results and therefore I had to bind the width of the textblock to that of the column. In playing around today, I changed the style to the following (note the different HorizontalAlignment) and removed the bindings and found out that my problem had been resolved:

那时,我假设没有产生预期的结果,因此我不得不将文本块的宽度绑定到列的宽度。在今天的游戏中,我将样式更改为以下(注意不同的Horizo​​ntalAlignment)并删除绑定并发现我的问题已解决:

<Style x:Key="DetailText" TargetType="TextBlock">
    <Setter Property="HorizontalAlignment" Value="Stretch" />
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="TextAlignment" Value="Center" />
    <Setter Property="Margin" Value="5,5,5,5" />
</Style>

#2


I apologize if you've tried this, but does setting TextBlock.TextWrapping to "Wrap" not accomplish your goal?

如果你已经尝试过,我道歉,但是将TextBlock.TextWrapping设置为“Wrap”不能实现你的目标吗?

I'm guessing that will get rid of the need for the bind-to-width stuff you're doing, as the Grid will take care of the resizing. (That is probably what is happening now: The Grid is laying out the controls as it shrinks, and the binding to width is changing the size slightly, causing the dancing.)

我猜这将消除你正在做的绑定到宽度的需要,因为Grid将负责调整大小。 (这可能就是现在正在发生的事情:网格在收缩时布置控件,并且绑定到宽度会稍微改变大小,导致跳舞。)

[Update]

I tried to duplicate the behavior you're seeing, but it works fine for me. I made a simple style for the TextBlocks like so:

我试图复制你看到的行为,但它对我来说很好。我为TextBlocks做了一个简单的样式,如下所示:

<Style x:Key="DetailText" TargetType="{x:Type TextBlock}">
    <Setter Property="TextBlock.TextWrapping" Value="Wrap"/>                
</Style>

And I didn't have any of your other dynamic resources (DetailHeadingBorder, DetailHeadingText, or ColumnBorderBrush), so everything was black and white (fine).

而且我没有你的任何其他动态资源(DetailHeadingBorder,DetailHeadingText或ColumnBorderBrush),所以一切都是黑白的(很好)。

Maybe you just have a really old graphics card and it's rendering things in software? Or it has to do with your styles.

也许你只是有一个非常古老的显卡,它在软件中呈现东西?或者它与你的风格有关。

#3


I hope I didn't misinterpret your question, but I don't see the need for binding TextBlock.Width?

我希望我没有误解你的问题,但我不认为需要绑定TextBlock.Width?

This xaml seems to work correctly:

这个xaml似乎正常工作:

  <Grid>
     <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="270"
                          Width="2*" />
        <ColumnDefinition MinWidth="160"
                          Width="*" />
        <ColumnDefinition MinWidth="160"
                          Width="*" />
        <ColumnDefinition MinWidth="160"
                          Width="*" />
     </Grid.ColumnDefinitions>
     <!--     We bind the width of the textblock to the width of this border to make sure things resize correctly.    
           It's important that the margin be set to 1 larger than the margin of the textblock or else you'll end  
             up in an infinate loop     -->
     <Border Grid.Column="0"
             BorderThickness="0,0,1,0">
        <Grid>
           <Grid.RowDefinitions>
              <RowDefinition Height="*" />
              <RowDefinition Height="*" />
           </Grid.RowDefinitions>
           <StackPanel Grid.Row="0">
              <Border>
                 <TextBlock Text="Col 1 Row 1" />
              </Border>
              <TextBlock TextWrapping="Wrap"
                         Text="gfege dfh lh dfl dhliöslghklj h lglsdg fklghglfg flg lgheh" />
           </StackPanel>
           <StackPanel Grid.Row="1">
              <Border>
                 <TextBlock Text="Col 1 Row 2" />
              </Border>
              <TextBlock Text="Massor av text som blir en wrappning i slutändan hoppas jag"
                         TextWrapping="Wrap" />
           </StackPanel>
        </Grid>
     </Border>
  </Grid>

I just removed the width bindings, added TextWrapping (which you probably had in a style), and removed the border named "FirstBorder" as well.

我刚刚删除了宽度绑定,添加了TextWrapping(你可能在一个样式中),并删除了名为“FirstBorder”的边框。