0

我有一个带有 a 的模板,Style它使用EventSettera 将公共事件处理程序设置为 some Hyperlink。但我想不在资源字典的.cs文件中而是在自定义控件的.cs文件中处理此事件。我怎样才能做到这一点?我正在将资源移动到主题.xaml文件中。我考虑过分离超链接样式的功能部分,但我应该把事件设置器放在哪里?我以为我可以使用命令,但是是否有更简洁的技术不需要更改每个Hyperlink元素并且适用于不支持命令的元素?

我使用 .NET Framework 4.7.2。我在网上做了一些搜索和一个简单的测试示例:

应用程序.xaml

<Application x:Class="wpf_test_2.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:wpf_test_2"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Dictionary.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

字典.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:local="clr-namespace:wpf_test_2">
    <ControlTemplate x:Key="MyControlTemplate">
        <ControlTemplate.Resources>
            <Style TargetType="Button">
                <!-- obviously, this does not compile: -->
                <EventSetter Event="Click" Handler="MyHandler"/>
            </Style>
        </ControlTemplate.Resources>
        <UniformGrid Rows="5" Columns="5">
            <Button>A</Button>
            <Button>B</Button>
            <Button>C</Button>
            <Button>D</Button>
            <Button>E</Button>
            <Button>F</Button>
            <Button>G</Button>
            <Button>H</Button>
            <Button>I</Button>
        </UniformGrid>
    </ControlTemplate>
</ResourceDictionary>

主窗口.xaml

<Window x:Class="wpf_test_2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:wpf_test_2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:MyControl/>
    </Grid>
</Window>

MyControl.xaml

<Control x:Class="wpf_test_2.MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:wpf_test_2"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
         Template="{DynamicResource MyControlTemplate}">
</Control>

MyControl.xaml.cs

/// <summary>
/// Interaction logic for MyControl.xaml
/// </summary>
public partial class MyControl : Control
{
    public MyControl()
    {
        InitializeComponent();
    }

    private void MyHandler(object sender, RoutedEventArgs e)
    {
        var b = sender as Button;

        MessageBox.Show($"Button {b.Content.ToString()} was clicked!");
    }
}

截屏

截屏

预期:项目编译,当我单击其中一个按钮时,会出现一个 MessageBox,其中按钮的内容为字符串。

实际:项目没有编译。

谢谢你。

4

1 回答 1

0

受 Clemens 评论的启发,我创建了一个RoutedUICommand,一个相应的命令绑定,以及设置和设置的设置CommandCommandParameter

AboutWindow.xaml

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:cs_timed_silver"
        x:Class="cs_timed_silver.AboutWindow"
        mc:Ignorable="d"  
        Width="448" Height="200" ResizeMode="NoResize"
        WindowStartupLocation="CenterOwner"

        Loaded="Window_Loaded"
        Closed="Window_Closed"

        Style="{DynamicResource AboutWindowStyle}">

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static local:AboutWindow.NavigateCommand}"
                        CanExecute="CommandBinding_CanExecute"
                        Executed="CommandBinding_Executed"/>
    </Window.CommandBindings>
</Window>

AboutWindow.xaml.cs

    public partial class AboutWindow : Window
    {
        public static RoutedUICommand NavigateCommand { get; set; } =
            new RoutedUICommand("", "NavigateCommand", typeof(AboutWindow));

        [...]

        private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            System.Diagnostics.Process.Start(
                new System.Diagnostics.ProcessStartInfo((e.Parameter as Uri).AbsoluteUri));
        }

Light.xaml

<Style x:Key="AboutWindowStyle" TargetType="local:AboutWindow">
    [...]
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Window}">
                <ControlTemplate.Resources>
                    [...]
                    <Style TargetType="{x:Type Hyperlink}">
                        <Setter Property="Command" Value="{Binding NavigateCommand}"/>
                        <Setter Property="CommandParameter"
                            Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=NavigateUri}"/>
                        </Style>
                    </ControlTemplate.Resources>
                    [...]
于 2019-09-03T11:33:28.360 回答