【问题标题】:WPF Layout of user control as a run用户控件的 WPF 布局作为运行
【发布时间】:2009-11-16 19:58:55
【问题描述】:

在 WPF 中,我想创建一个如下所示的窗口:

Application with user controls http://www.freeimagehosting.net/uploads/86209e1a87.png

屏幕上有四个用户控件,#1、2、3、4。如您所见,用户控件 2 不应呈现为框,而是内联。

如果这是一个 WPF 流文档:

  • 1、3、4 将是一个段落(装箱)
  • 2 次运行(内联)

原因是2可以用在另一种形式上而不用拆分为3。

你知道如何以适当的方式做到这一点吗?

已经想到了一些想法:

  • 2是和普通用户控制 (拳击)。放在橱窗里时, 2、3、4 被放置在画布中,使用 有 Z-Order 和保证金吨控制 它们是如何呈现的
  • 2 有一个网格已经格式化,因此它可以接受其中的 3 和 4 作为 ContentControl,我们通过 Xaml 或后面的代码注入它们
  • 2 将主 Grid 公开为一个属性,并通过 Attached Property 优点,我们添加了 3 和 4 的数据
  • 我们创建自己的布局控件并实现 Arrange 和 Measure 方法来创建一个类似于 Run 的布局

还有一些不那么干净的……

有什么想法吗?

谢谢,

帕特里克

【问题讨论】:

    标签: c# wpf .net-3.5 layout user-controls


    【解决方案1】:

    IMO,我认为您的表单分解不正确。

    区域 2 不应包含您所描述的要“内联”的底部部分。

    它应该分开(就布局而言),并且可能适合与区域 3 和区域 4 一起包含 2 列和 2 行的网格。区域 3 需要具有 2 的行跨度。

    在这种情况下,如果这样做,XAML 实际上会非常干净。

    它可能看起来像这样:

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
    
        <uC:Area1 Grid.Row="0"><!-- Area Control here --></uC:Area1>
        <uC:Area2 Grid.Row="1"><!-- Area Control here --></uC:Area2>
    
        <Grid Grid.Row="2">
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
    
            <uC:AreaDuree Grid.Row="0" Grid.Column="0">
                <!-- Area Control here -->
            </uC:AreaDuree>
    
            <uC:Area4 Grid.Row="1" Grid.Column="0">
                <!-- Area Control here -->
            </uC:Area4>
    
            <uC:Area3 Grid.RowSpan="2" Grid.Column="1">
                <!-- Area Control here -->
            </uC:Area3>                        
    
        </Grid>
    
    </Grid>
    

    【讨论】:

    • 是的,那太好了。我编辑了问题,指出 #2 可以在其他地方使用。
    • @PBelanger 很好,但这只是意味着您的用户控件应该被进一步封装,以便您可以更改它们各自的布局。将 Area2 的底部作为自己的控件,您可以将其放置在任意数量的布局方案中的任何位置。
    【解决方案2】:

    我建议您将 Control #2 拆分为 3 或 4 个更具体的 UserControl。然后在 WrapPanel 中加载#2、#3、#4。检查此link: Layout of UserControl 以实现智能包装面板排列和测量策略。

    【讨论】:

      【解决方案3】:

      对我来说,为了简化你的设计师的生活,我建议你使用 ContentControl 的解决方案。

      这样,您的设计师可以轻松地添加他们的控件,并且为您确保您的 Usercontrol #2 足够智能,以便以正确的方式呈现您的布局。

      【讨论】:

        【解决方案4】:

        我很惊讶还没有人建议使用实际的 FlowDocument 来布置你的 UI。

        我之前用过FlowDocument来实现复杂的安排。除了阻止某些属性继承(例如TextElement.FontSize)外,它工作得很好。这并不难解决。

        在您的情况下,只需将 #2 分解为每个部分的单独 UserControl,然后在您的 FlowDocument 中,使用 InlineUIContainer 包装每个部分。

        <Window>
          <DockPanel>
            ... toolbars, etc ...
        
            <FlowDocumentScrollViewer ...>
              <FlowDocument>
                ...
                 <InlineUIContainer>
                   <my:PartialNumberTwo DataContext="{Binding ...}" />
                 </InlineUIContainer>
                ...
        

        当然,FlowDocument 可以做的事情是有限制的,因此它可能不适用于您的场景。

        一个非常灵活的选项是创建一个自定义面板,它以 WrapPanel 样式布置其子级,但通过拟合矩形来实现,并且在开始之前它将与面板自身的兄弟级重叠的任何区域标记为不可用。

        这样的面板会这样使用:

        <Grid ...>
          ... RowDefinitions, ColumnDefinitions ...
        
          <panels:WrapIntoRemainingSpacePanel RowSpan="4" ColumnSpan="3"> <!-- fill whole grid -->
            <my:Control2Part1 />
            <my:Control2Part2 />
            <my:Control2Part3 />
            <my:Control2Part4 />
         </panels:WrapIntoRemainingSpacePanel>
        
         <my:Control1 Grid.Row="0" Grid.ColumnSpan="3" />
         <my:Control3 Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" />
         <my:Control4 Grid.Row="3" Grid.RowSpan="2" />
        

        这个面板的实现如下:

        1. 在 ArrangeOverride 中,安排一个 Dispatcher.BeginInvoke 回调来进行实际安排并报告使用的完整尺寸
        2. 在回调中,获取代表我父母坐标空间中所有兄弟姐妹边界框的矩形。
        3. 对放置的所有矩形的 Y 坐标(顶部和底部)进行排序
        4. 通过在排序列表中找到第一个 Y 坐标来放置每个子项,在该位置处有内容的水平空间,并将其放在尽可能左的位置
        5. 监控兄弟姐妹的 VisualTransform 的变化,如果有调用 InvalidateArrange()

        【讨论】:

          【解决方案5】:

          我认为这是一个简单的网格,“诀窍”是让一个控件覆盖另一个控件非常好 - WPF 将始终以相同的顺序呈现它们:

          我对所有网格行都使用了 Height="Auto",这取决于用户控件的设置方式,您可能需要指定一个实际高度才能使它们正确排列。

          <Grid>
              <Grid.RowDefinitions>
                  <RowDefinition Height="Auto"/>
                  <RowDefinition Height="Auto"/>
                  <RowDefinition Height="Auto"/>
                  <RowDefinition Height="Auto"/>
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="*"/>
                  <ColumnDefinition Width="Auto"/>
              </Grid.ColumnDefinitions>
              <uc:UserControl1 Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"/>
              <uc:UserControl2 Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Grid.RowSpan="2"/>
              <uc:UserControl3 Grid.Row="2" Grid.Column="1" Grid.RowSpan="2"/>
              <uc:UserControl4 Grid.Row="3" Grid.Column="0"/>
          <Grid>
          

          【讨论】:

            【解决方案6】:

            这是 1 个大网格,有 3 行 2 列。 该网格的每个区域都包含一个能够接收用户控件的网格。所以网格 number3 只需要将其上边距设置为 -75。如果将其放在 xaml 中,它将与网格编号 2 重叠。然后你只需要根据你希望它如何反应来锁定你的列和行。

            <Grid x:Name="LayoutRoot">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.55*"/>
                    <ColumnDefinition Width="0.45*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition Height="0.363*"/>
                    <RowDefinition Height="0.369*"/>
                    <RowDefinition Height="0.268*"/>
                </Grid.RowDefinitions>
                <Grid Grid.ColumnSpan="2" Background="#FF48C5D0"/>
                <Grid Margin="1,0,0,0" Grid.ColumnSpan="2" Grid.Row="1" Background="#FFD2A268"/>
                <Grid Margin="1,0,0,0" Grid.Row="2" Background="#FFB7F075"/>
                <Grid Grid.Column="1" Grid.Row="2" Background="#FFB129EC" Margin="0,-75,0,0"/>
            </Grid>
            

            马丁·拉蒙塔尼

            【讨论】:

              【解决方案7】:

              可以考虑将#3 和#4 作为用户控件#2 的一部分,这样布局会更简单。顶层网格布局 #1 和 #2

              参见第二个用户控件布局。并且所有网格都带有 * 大小,以便根据窗口大小调整大小。

              alt text http://img5.imageshack.us/img5/4419/40506576.jpg

              【讨论】:

              • 如果他问这个问题可能是因为他需要单独使用 UserControl。问题是:“如何在运行时根据上下文自动移动/调整 UserControl/Panel 的大小?”,而不是如何以另一种方式实现。
              • 我不知道你为什么反对这个?该解决方案与 @Joseph 添加 XAML 的目的完全相同。我的只是相同的视觉表示
              猜你喜欢
              • 1970-01-01
              • 2018-08-17
              • 1970-01-01
              • 1970-01-01
              • 2013-08-24
              • 2016-10-09
              • 2010-12-14
              • 2021-02-04
              • 1970-01-01
              相关资源
              最近更新 更多