C# 如何从ResourceDictionary的代码隐藏中访问UI控件

C# 如何从ResourceDictionary的代码隐藏中访问UI控件,c#,.net,wpf,xaml,C#,.net,Wpf,Xaml,所以我有一个ResourceDictionary来定义我的自定义窗口样式。我正在努力做的是从XAML文件访问控件。 资源字典看起来像这样 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key=

所以我有一个ResourceDictionary来定义我的自定义窗口样式。我正在努力做的是从XAML文件访问控件。 资源字典看起来像这样

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style x:Key="MyCustomWindowStyle" TargetType="{x:Type Window}">

    <Setter Property="WindowChrome.WindowChrome">
        <Setter.Value>
            <WindowChrome CaptionHeight="30"/>
        </Setter.Value>
    </Setter>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Window}">
                <Grid>
                    <!-- the root window -->
                    <Border BorderThickness="0.3" BorderBrush="{DynamicResource GeneralDarkBlue}">
                        <AdornerDecorator>
                            <ContentPresenter />
                        </AdornerDecorator>
                    </Border>

                    <DockPanel Height="30" Background="{TemplateBinding Background}" VerticalAlignment="Top" LastChildFill="False">

                        <Viewbox x:Name="HamburgerMenu" DockPanel.Dock="Left" WindowChrome.IsHitTestVisibleInChrome="True">
                            <Viewbox.InputBindings>
                                <MouseBinding MouseAction="LeftClick" Command="{Binding SettingsClick}"/>
                            </Viewbox.InputBindings>
                            <Border Width="47" Height="32" Background="Transparent">
                                <Canvas>
                                    <Path x:Name="TopbarIconHamburgerMenu" Margin="14,10" Data="M12.5,19h19.2v1H12.5V19z M12.5,13.7h19.2v1H12.5V13.7z M12.5,8.5h19.2v1H12.5V8.5z" Stretch="UniformToFill" Fill="#FFFFFF"/>
                                </Canvas>
                            </Border>
                        </Viewbox>

                        // the rest of viewboxes for minimize, maximize controls...

                    </DockPanel>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>

</Style>
 public partial class MyCustomWindowStyle : ResourceDictionary
 {
        public MyCustomWindowStyle()
        {
            InitializeComponent();
        }

        public void DoSomething()
        {
            var window = (Style)Application.Current.Resources["MyCustomWindowStyle"];
            var hm = (Viewbox)window.Resources.FindName("HamburgerMenu");
        }
}
这在hm中返回null


你知道怎么做吗?

首先,
风格。Resource
是一个
资源字典
,在
资源字典中有两件重要的事情需要注意。FindName
方法:

摘要部分说:

此字典实现不支持

和返回值部分,说明:

始终返回null

其次,即使您尝试按键检索
查看框
,也必须将其定义为资源:

<Style x:Key="MyCustomWindowStyle" TargetType="{x:Type Window}">
    <Style.Resources>
        <ViewBox x:Key="HamburgerMenu" />
    </Style.Resources>
</Style>
<Style x:Key="MyCustomWindowStyle" TargetType="{x:Type Window}">
    <Style.Resources>
        <ControlTemplate x:Key="Template" TargetType="{x:Type Window}">
            <Grid>
                (...)
                    <ViewBox x:Key="HamburgerMenu" />
                (...)
            </Grid>
        </ControlTemplate>
    </Style.Resources>
    <Setter Property="Template" Value="{StaticResource Template}" />
</Style>
那么,这应该对您有帮助:

var window = (Style)Application.Current.Resources["MyCustomWindowStyle"];
var template = (ControlTemplate)window.Resources["Template"];
var root = (FrameworkElement)template.LoadContent();
var hm = (ViewBox)root.FindName("HamburgerMenu");

更新 如果您的目标是在应用了该模板的现有窗口中获得
ViewBox
,那么首先您需要知道如何获得该特定窗口。它可能是
Application.Current.main窗口
,否则很可能在
Application.Current.Windows
集合中找到它。您还可以为该窗口实现单例模式,或者使用其他方法,例如在应用程序中的某个位置公开引用该窗口的静态属性,或者使用第三方工具,例如在Prism中

一旦您手中有了窗口,您只需要使用前面提到的
ControlTemplate.FindName
方法:

var window = (...);
var hm = (ViewBox)window.Template.FindName(name: "HamburgerMenu", templatedParent: window);
请注意,不需要访问在其中定义模板的资源字典


至于您尝试使用以前的解决方案失败的原因,这是因为每次调用
ControlTemplate.LoadContent
方法时都会生成新创建的元素,修改它不会反映以前由该模板创建的元素。

是否已将生成操作设置为资源?MyCustomWindowStyle.xaml已设置为页面生成操作。并且MyCustomWindowStyle.xaml.cs设置为编译。如果我将第一个设置为Resource,则会出现错误“名称'InitializeComponent'在当前上下文中不存在”“HamburgerMenu”不在样式的资源列表中。它是ControlTemplate中的子元素。因此,在进入“汉堡菜单”之前,您必须通读ControlTemplate中的子网格。希望这有帮助@Fireboyd78谢谢你的评论,但这没什么帮助,因为我不知道怎么做!非常感谢您的时间和非常好的解释。然而,仍然存在一些问题。首先,我仍然无法在Viewbox中设置x:Key。我得到错误“key属性只能在IDictionary中使用”。但是我留下了x:Name,代码也起作用了。。。直到我试图设置hm.Visibility=Visibility.Hidden;它什么也没做!它没有隐藏控制。我是遗漏了什么还是误解了?是的,我想你误解了模板的工作原理。正如我所说,模板基本上是创建可视化树的方法,它只“知道”如何创建这样的可视化树,而不知道如何在应用程序的深渊中找到以前创建的树。作为一名程序员,您需要跟踪这些信息。看到我更新的答案。我承认我还有很多关于XAML、模板等的知识要学习。非常感谢你的回答@Grx70我发布了类似的问题-以防您有时间提出建议/意见或解决方案。非常感谢。