如何查找 UserControl 而不是 Window 的子级 - 替换 Window.FindName

发布于 2024-08-11 09:33:48 字数 1618 浏览 7 评论 0原文

我目前有一个 WPF 项目,它有一个主窗口和许多作为该窗口子窗口的用户控件。该窗口的许多子窗口都是选项卡。我已成功用用户控件替换了我的主窗口,该控件实现了与主窗口几乎完全相同的功能。

用 UserControl 替换 Window 会带来一个问题 - 目前我们的应用程序通过使用如下所示的 Window.FindName 方法根据父窗口确定要显示哪个编程选项卡。因此,我需要将 Application.Current.MainWindow 替换为我的主用户控件的适当描述。请参阅下面的错误 C# 方法和选项卡的 wpf 实例化以进行澄清。

关于 Window.FindName() 方法的注意事项 - 我将其替换为 UserControl 后它不起作用的原因是因为 FindName 方法在可视化树中向上搜索,如此处所述

有谁知道如何根据 x:Name 查找用户控件,类似于 Application.Current.MainWindow ?另外,是否有比查找 x:Name 字符串更好的方法来查找 UserControl,以防它被重命名?

我们当前如何找到 MainWindow - 现在需要找到 MainUserControl:

(C#)
private static void SetCurrentProgram(int num)
    {
        Window window = Application.Current.MainWindow;
        ProgrammingTab programmingTab1 = window.FindName("ProgrammingTab1") as ProgrammingTab;
        ProgrammingTab programmingTab2 = window.FindName("ProgrammingTab2") as ProgrammingTab;

        programmingTab1.Visibility = num == 1 ? Visibility.Visible : Visibility.Collapsed;
        programmingTab2.Visibility = num == 2 ? Visibility.Visible : Visibility.Collapsed;

    }

编程选项卡的实例化。

(xaml)
<Grid>
 <ProgrammingControl:ProgrammingTab x:Name="ProgrammingTab1" Program="1" IsVisibleChanged="ProgrammingTab_IsVisibleChanged" />
 <ProgrammingControl:ProgrammingTab x:Name="ProgrammingTab2" Program="2" IsVisibleChanged="ProgrammingTab_IsVisibleChanged" />
</Grid>

I currently have a WPF project which has one main Window, and many UserControls which are children of this Window. Many of the children of this window are Tabs. I have successfully replaced my main Window with a User Control that implements almost exactly the same functionality as the Main Window.

Replacing the Window with a UserControl introduced one problem - currently our application determines which programming tab to display based on the parent window by using the Window.FindName method shown below. Therefore I need to replace the Application.Current.MainWindow with an appropriate description of my main user control. See the erroring C# method below and wpf instantiation of the tabs for clarification.

Note Regarding Window.FindName() method - the reason why it does not work after I replaced it with a UserControl is because the FindName method searches upwards in the visual tree, as described here.

Does anyone know how to find a user control based on the x:Name, similar to Application.Current.MainWindow ? Also, is there a better way to find the UserControl than looking for the x:Name string in case it gets renamed?

How we currently find the MainWindow - need to now find MainUserControl:

(C#)
private static void SetCurrentProgram(int num)
    {
        Window window = Application.Current.MainWindow;
        ProgrammingTab programmingTab1 = window.FindName("ProgrammingTab1") as ProgrammingTab;
        ProgrammingTab programmingTab2 = window.FindName("ProgrammingTab2") as ProgrammingTab;

        programmingTab1.Visibility = num == 1 ? Visibility.Visible : Visibility.Collapsed;
        programmingTab2.Visibility = num == 2 ? Visibility.Visible : Visibility.Collapsed;

    }

Instantiation of programming tabs.

(xaml)
<Grid>
 <ProgrammingControl:ProgrammingTab x:Name="ProgrammingTab1" Program="1" IsVisibleChanged="ProgrammingTab_IsVisibleChanged" />
 <ProgrammingControl:ProgrammingTab x:Name="ProgrammingTab2" Program="2" IsVisibleChanged="ProgrammingTab_IsVisibleChanged" />
</Grid>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

捂风挽笑 2024-08-18 09:33:48

听起来您的应用程序是按照非常类似于 WinForms 的风格开发的。为了坚持这种风格并简单地回答您的问题,您可以使用 FindName() 来查找 UserControl,然后再次查找 ProgrammingTab,如下所示:

var userControl = (MyUserControl)Application.Current.MainWindow.FindName("userControlName");
var programmingTab1 = (ProgrammingTab)userControl.FindName("ProgrammingTab1");
var programmingTab2 = (ProgrammingTab)userControl.FindName("ProgrammingTab2");
...

不过,我建议您考虑使用 WPF 的高级功能,例如数据绑定。您可以在静态属性引用的单例对象上拥有 DependencyProperty“CurrentProgram”,并使用转换器简单地将可见性数据绑定到它。

<ProgrammingTab Visibilty="{Binding CurrentProgram,
   Source={x:Static MyState.Instance},
   Converter={x:Static VisibleIfEqualConverter},
   ConverterParameter=1}" ...>
  ...

通过此更改,您的 SetCurrentProgram 变得简单:

public void SetCurrentProgram(int num)
{
   MyState.Instance.CurrentProgram = num;
}

此技术的优点在于,每次 MyState.Instance.CurrentProgram 的值更改时,应用程序中任何位置的任何 PlanningTab 都会自动出现或消失,无需使用 FindName() 或其他方式查找它们。

It sounds like your app is developed in a very WinForms-like style. To stick with that style and simply answer your question, you can FindName() to find the UserControl and again to find the ProgrammingTab, like this:

var userControl = (MyUserControl)Application.Current.MainWindow.FindName("userControlName");
var programmingTab1 = (ProgrammingTab)userControl.FindName("ProgrammingTab1");
var programmingTab2 = (ProgrammingTab)userControl.FindName("ProgrammingTab2");
...

However I would recommend you look into using WPF's advanced capabilities such as data binding. You can have a DependencyProperty "CurrentProgram" on a singleton object referenced by a static property, and simply databind Visiblity to it using a converter.

<ProgrammingTab Visibilty="{Binding CurrentProgram,
   Source={x:Static MyState.Instance},
   Converter={x:Static VisibleIfEqualConverter},
   ConverterParameter=1}" ...>
  ...

With this change, your SetCurrentProgram becomes simply:

public void SetCurrentProgram(int num)
{
   MyState.Instance.CurrentProgram = num;
}

The beauty of this technique is that any ProgrammingTab anywhere in your application will automatically appear or disappear every time MyState.Instance.CurrentProgram's vaulue changes, with no need to find them with FindName() or otherwise.

婴鹅 2024-08-18 09:33:48

我找到了解决此问题的方法:我根据另一个 StackOverflow 用户的算法创建了一个新算法,该算法递归地查找 DependencyObject 的任何子级。在此处查找我的解决方案。如果您在我的另一篇文章中的 public static class UIHelper {} 中声明 FindChild() 方法,则可以通过执行以下操作来解决问题:

  ProgrammingTab programmingTab1 = UIHelper.FindChild<ProgrammingTab>(Application.Current.MainWindow, "ProgrammingTab1");
  ProgrammingTab programmingTab2 = UIHelper.FindChild<ProgrammingTab>(Application.Current.MainWindow, "ProgrammingTab2");

这仍然使用过程代码而不是像 RayBurns 建议的那样使用声明性 XAML 进行绑定。如果它有效,他的解决方案将更加有效,因为它不会遍历整个树,而只是根据转换器更改选项卡的可见性。我现在将测试该解决方案,看看结果如何。

FindName() 无法正常工作的原因在 在此处发布

I figured out a workaround to this problem: I created a new algorithm based on another StackOverflow user's algorithm that recursively found any children of a DependencyObject. Find my solution here. If you declare the FindChild() method in my other post within public static class UIHelper {} you can then solve the problem by doing this:

  ProgrammingTab programmingTab1 = UIHelper.FindChild<ProgrammingTab>(Application.Current.MainWindow, "ProgrammingTab1");
  ProgrammingTab programmingTab2 = UIHelper.FindChild<ProgrammingTab>(Application.Current.MainWindow, "ProgrammingTab2");

This still uses procedural code instead of declarative XAML for bindings like RayBurns suggested. If it works, his solution will be much more efficient as it wont be traversing a whole tree but rather just changing the visibility of tabs based on a converter. I'll test that solution now and see how it turns out.

The reason why FindName() doesn't work properly is described in the post here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文