【问题标题】:WPF - get all children from codeWPF - 从代码中获取所有孩子
【发布时间】:2018-02-10 13:06:45
【问题描述】:

这是我的问题:我用 Fluent 功能区创建了一个程序,当我想禁用功能区时,我需要使用以下代码:

代码 WPF:

<Fluent:RibbonGroupBox x:Name="GpRibbonFormats" ...>
  <Fluent:Button x:Name="AjoutTole" Header="{x:Static p:Resources.Ajouter}">
    <Fluent:Button.ToolTip>
      <Fluent:ScreenTip x:Name="ScreenTipAjoutTole"...>    
      </Fluent:ScreenTip>
    </Fluent:Button.ToolTip>
  </Fluent:Button>
  <Fluent:Button x:Name="EditQtyFormat" ...>
    <Fluent:Button.ToolTip>
      <Fluent:ScreenTip x:Name="ScreenTipEditQtyFormat"...>
      </Fluent:ScreenTip>
    </Fluent:Button.ToolTip>
  </Fluent:Button>
  <Fluent:Button x:Name="DeleteFormat" SizeDefinition="Large">
    <Fluent:Button.ToolTip>
      <Fluent:ScreenTip x:Name="ScreenTipDeleteFormat" ...>
      </Fluent:ScreenTip>
    </Fluent:Button.ToolTip>
  </Fluent:Button>
</Fluent:RibbonGroupBox>

代码背后:

AjoutTole.IsEnabled = false;
ScreenTipAjoutTole.DisableReason = isBlocked;
EditQtyFormat.IsEnabled = false;
ScreenTipEditQtyFormat.DisableReason = isBlocked;
DeleteFormat.IsEnabled = false;
ScreenTipDeleteFormat.DisableReason = isBlocked;

它工作正常,但我想做一个这样的功能,所以我确信我总是在 DisableReason 中发送正确的信息:

DisableButton(Fluent:Button NameOfButton,string ReasonOfDisable)
{
    NameOfButton.IsEnabled = false;
    NameOfButton.AllScreenTipChild.DisableReason=ReasonOfDisable
}

就像我想禁用所有一组按钮一样:

DisableGroup(Fluent:RibbonGroupBox myGroup,string ReasonOfDisable)
{
    foreach(Fluent:Button button in myGroup)
    {
        button.isEnable=false;
        button.AllScreenTipChild.DisableReason=ReasonOfDisable;
    }
}

这怎么可能?我希望能够从代码隐藏中做到这一点。

编辑:

在尝试获取按钮的子项时,我返回一个 System.Windows.Controls.Border 类型的元素,其名称为“border”,但我的 XAML 文件中没有这样的元素。 我也试图让我的 RibbonGroupBox 的孩子,但在这种情况下,我返回一个网格(grid2),而那个网格甚至不在功能区中......

使用的代码:

for (int i = 0; i < VisualTreeHelper.GetChildrenCount(DeleteOL); i++)
{
   var child = VisualTreeHelper.GetChild(DeleteOL, i);
   string monType = child.GetType().ToString();
   if(monType== "System.Windows.Controls.Border")
   {
      System.Windows.Controls.Border bb = (System.Windows.Controls.Border)child;
      string name = bb.Name;
   }
}

编辑 2:

我确认 getChild 在功能区上不起作用(为什么?),但我可以找到如何获取组中的按钮列表:

foreach(var item in GpRibbonFormats.Items)
{
    if(item.GetType().ToString()=="Fluent.Button")
    {
         Fluent.Button button = (Fluent.Button)item;
         button.IsEnabled = false;
    }
}

现在我还在寻找如何找到按钮的屏幕提示

【问题讨论】:

  • 你真的应该考虑使用 MVVM,因为它让这种事情变得非常容易。您的代码中有什么不起作用,我不明白为什么它不起作用。
  • 我的代码运行良好,只是想做一个独特的功能来改变 button.IsEnable 和 ScreenTip.DisableReason,现在对于每个按钮我有两行代码,并且作为我有很多按钮,这会减少我的代码。
  • 刚刚编辑的问题,如您所见,我在寻找儿童时得到了奇怪的结果。如果我在网格内(在功能区之后)执行此操作,则该功能运行良好。但在 Ribbon 里面没有

标签: c# wpf fluent-ribbon


【解决方案1】:

您似乎混合了 XAML 和 C# 中的命名空间约定,在 C# 中您不使用 : 来引用命名空间,而是使用 . 分隔符。例如,StackPanelSystem.Windows.Controls 命名空间内,所以在 C# 中这样引用它:

System.Windows.Controls.StackPanel stackPanel = new System.Windows.Controls.StackPanel();

我从未尝试过 Fluent,但这段代码应该可以工作。

    public void DisableGroup(Fluent.RibbonGroupBox ribbonGroup, string reasonOfDisable)
    {
        foreach (var item in ribbonGroup.Items)
        {
            if (item is Fluent.Button)
            {
                DisableButton((Fluent.Button)item, reasonOfDisable);
            }
        }
    }

    public void DisableButton(Fluent.Button button, string reasonOfDisable)
    {
        button.IsEnabled = false;

        if (button.ToolTip is Fluent.ScreenTip)
        {
            Fluent.ScreenTip screenTip = (Fluent.ScreenTip)button.ToolTip;
            screenTip.DisableReason = reasonOfDisable;
        }
    }

要禁用整个组,您可以这样称呼它

    DisableGroup(GpRibbonFormats, "Ce groupe n'est pas disponible");

要禁用一个按钮,你可以这样称呼它

    DisableButton(AjoutTole, "Ajouter est désactivé pour le moment");

顺便说一句,Fluent.RibbonGroupBox 继承自 ItemsControl,这个控件有自己的IsEnabled 属性,你可以通过将属性设置为 false 来禁用整个组(虽然我没有测试过),但无论如何你都必须通过每个按钮来设置它们的屏幕提示。

    GpRibbonFormats.IsEnabled = false;

对于这种事情,Binding 在 WPF 中非常强大,您可能想阅读一下 MVVM。一开始实施起来并不容易,但一旦掌握了窍门,它就会改变游戏规则,并真正简化您的代码和逻辑。

【讨论】:

  • 感谢它完美运行,事实上对我来说缺少的部分是 (Fluent.ScreenTip)button.ToolTip;没想到我可以那样转换它。饲养绑定我在一两个月前开始使用它,我经常用它来浏览列表视图,但是对于这些按钮,我看不出它对我有什么帮助?实际上我可以禁用一个完整的组通过设置其值“IsEnabled”,但在我的情况下,我有许多不同的条件可以阻止一个组,或者只是阻止一个/几个按钮,而且并不总是相同的。如果我总是需要阻止绑定按钮,我会看到绑定按钮的优势,但在那种情况下呢?
  • 或者你会建议制作完整的 MVVM 吗?即使它没有那么必要?只要我这样做,我就会有一个很大的上下文,这就是为什么现在我只在必要时使用绑定,如果我想自动显示一些数据修改,在这些按钮的情况下,使用绑定不会让我保存代码(只有这样函数才会在上下文中)。当然欢迎任何建议。另外,我有 4 个不同的 WPF,并为它们制作了一个上下文文件(里面有 4 个不同的类),你会建议我制作 4 个单独的文件吗?
  • MVVM 是实现目标的一种方式,使用后面的代码是另一种方式。两者都是有效的,你决定你喜欢哪一个。在 MVVM 中,每个按钮都可以绑定到 CommandCommandCanExecute 将为您处理 IsEnabled 属性。对于每个按钮ToolTip,您可以使用MultiConverter 绑定到父组IsEnabledToolTip 属性,并根据父组的IsEnabled 值在父组ToolTip 或默认值之间进行选择。 MVVM 不会使您的代码更短,但它将视图与逻辑分开(即:不需要 ScreenTip 转换)。
  • 如果有一天您决定将Fluent Ribbon 更改为另一个控件,您的ViewModelConverter 根本不需要更改,因为它甚至不知道@987654347 @ 正在使用其属性。
  • 非常感谢(事实上,最近我将标准菜单更改为功能区,你说得对,如果我这样做会更快一些),感谢您的帮助
【解决方案2】:

我花了一些时间,但我终于明白了用户试图向我解释的内容(对于从 MVVM 开始的人来说并不明显,这就是我在这里写它的原因)。

我相信我可以在代码中轻松地将我的属性 IsEnabled 设置为 true 或 false(如 Roger Leblanc 的回答),然后继续绑定我的 ViewModel。 事实并非如此,因为当我将 IsEnable(设置为 true)属性时,它会将 IsEnabled="{Binding EnableEditNesting}" 替换为 IsEnabled=true,所以在那之后就没有完成了更多绑定(如果我错了,请告诉我)。

最后我做了以下事情:

  • 对于不需要每个按钮有不同行为的 GroupBox,我只是在其 IsEnable 参数上进行了绑定。

     <Fluent:RibbonGroupBox x:Name="GpRibbonFormats" IsEnabled="{Binding EnableGpRibbonFormats}" Header="{x:Static p:Resources.Stock}">
           <Fluent:RibbonGroupBox.ToolTip>
                 <Fluent:ScreenTip x:Name="ScreenTipGpRibbonFormats" Image="img\image_engrenage.png" Width="250" Text="{x:Static p:Resources.NestingSendToProduction}" DisableReason="{Binding EnableGpRibbonFormatsReason}">
    
                 </Fluent:ScreenTip>
           </Fluent:RibbonGroupBox.ToolTip>
           <Fluent:Button x:Name="AjoutTole" SizeDefinition="Large" LargeIcon="img\image_add.png" Header="{x:Static p:Resources.Ajouter}" Click="Add_ToleOL_Click">
    
           </Fluent:Button>
                    ...
     </Fluent:RibbonGroupBox>
    
  • 对于我需要在每个按钮上具有特定行为的 GrouBox,我为每个按钮(组上没有任何内容)设置了一个 Binding,当我需要禁用所有组时,我会一个一个地禁用按钮。

    <Fluent:RibbonGroupBox x:Name="GpRibbonOL" Header="{x:Static p:Resources.NestingLaunchingOrder}">
         <Fluent:Button x:Name="DeleteOL" IsEnabled="{Binding EnableDeleteOL}" SizeDefinition="Large" LargeIcon="img\image_delete.png" Header="{x:Static p:Resources.Supprimer}" Click="Supprimer_OF">
              <Fluent:Button.ToolTip>
                  <Fluent:ScreenTip x:Name="ScreenTipDeleteOL" Image="img\image_delete.png" Title="Delete OL" Width="250" Text="Delete element" DisableReason="{Binding EnableEditNestingReason}">
                  </Fluent:ScreenTip>
              </Fluent:Button.ToolTip>
         </Fluent:Button>
         ...
    </Fluent:RibbonGroupBox>
    

ViewModel 看起来是这样的,所以当我想启用/禁用时,我只需更改工具提示:

    private bool enableGpRibbonNesting;
    public bool EnableGpRibbonNesting
    {
        get { return enableGpRibbonNesting; }
        set
        {
            enableGpRibbonNesting = value;
            this.NotifyPropertyChanged("EnableGpRibbonNesting");
        }
    }
    private string enableGpRibbonNestingReason;
    public string EnableGpRibbonNestingReason
    {
        get { return enableGpRibbonNestingReason; }
        set
        {
            enableGpRibbonNestingReason = value;
            if (value == "")
            {
                EnableGpRibbonNesting = true;
            }
            else
            {
                EnableGpRibbonNesting = false;
            }
            this.NotifyPropertyChanged("EnableGpRibbonNestingReason");

        }
    }

【讨论】:

  • 干得好,这个代码对于其他人来说会更容易阅读。使用 MVVM,您走在了正确的轨道上!
  • 谢谢,你认为我可以把我的回答当作好的回答吗?因为最后,我理解你的回答,即使它工作正常(直到你不使用 MVVM),也不是一个“好的解决方案”(而是一个好的提示)。如果你不介意的话,我会把它当作好的。
猜你喜欢
  • 1970-01-01
  • 2018-10-27
  • 1970-01-01
  • 1970-01-01
  • 2021-08-19
  • 2013-11-23
  • 2015-05-16
  • 2018-01-29
  • 2018-04-19
相关资源
最近更新 更多