【问题标题】:'Failed to create a 'Type' from the text 'local:ImageButton''无法从文本'local:ImageButton'创建'类型'
【发布时间】:2021-10-11 16:47:11
【问题描述】:

我有一个包含许多用户控件的类程序集。我想向此类程序集添加一种新型按钮,并且还想为其添加样式。具体来说,我想要一个包含多个图像的按钮,用于正常、悬停(IsMouseOver)和禁用状态。它还将包含要显示的文本。然后我可以使用这个类程序集在任何应用程序中添加它,如下所示:

<ns:ImageTextButton NormalImage="{StaticResource SomeImage}" HoverImage="{StaticResource SomeHoverImage}" Text={StaticResource SomeText}" />

首先我创建了一个 C# 类:

public class ImageTextButton : Button {
   public DependencyProperty ImageProperty = DependencyProperty.Register(nameof(Image), typeof(DrawingBrush), typeof(ImageTextButton));
   public DependencyProperty HoverImageProperty = DependencyProperty.Register(nameof(HoverImage), typeof(DrawingBrush), typeof(ImageTextButton));
   public DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(ImageTextButton));

   public DrawingBrush Image {
      get { return GetValue(ImageProperty) as DrawingBrush; }
      set { SetValue(ImageProperty, value); }
   }

   public DrawingBrush HoverImage {
      get { return GetValue(HoverImageProperty) as DrawingBrush; }
      set { SetValue(HoverImageProperty, value); }
   }

   public string Text {
      get { return GetValue(TextProperty) as string; }
      set { SetValue(TextProperty, value); }
   }
}

然后我在 Styles.xaml 文件中创建了一个样式,该文件编译为 Resource

<Style TargetType="{x:Type local:ImageTextButton}" x:Key="ImageTextButtonStyle">
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="Button">
            <Border BorderThickness="{TemplateBinding BorderThickness}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    CornerRadius="0" Background="{Binding RelativeSource={RelativeSource AncestorType=local:ImageTextButton}, Path=Image}">
               <StackPanel>
                  <Canvas x:Name="canvas" Background="{Binding RelativeSource={RelativeSource AncestorType=local:ImageTextButton}, Path=Image}" />
                  <TextBlock Style="{Binding RelativeSource={RelativeSource AncestorType=local:ImageTextButton}, Path=TextStyle}" 
                             Text="{Binding RelativeSource={RelativeSource AncestorType=local:ImageTextButton}, Path=Text}" />
               </StackPanel>
            </Border>
            <ControlTemplate.Triggers>
               <Trigger Property="IsMouseOver" Value="True">
                  <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Mode=Self}, Path=HoverImage}" TargetName="canvas" />
               </Trigger>
            </ControlTemplate.Triggers>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

我无法测试这种风格,而且很可能存在问题。我无法启动应用程序,因为上面的 TargetType 不存在。我相信这是因为我的 Styles.xaml 是一种资源,并且实际的类是编译的。我得到的错误是 Failed to create a 'Type' from text 'local:ImageTextButton'

我怎样才能做到这一点?其次,有什么方法可以默认将此样式应用于此类型?我不想总是在此用户项的每个实例中指定 Style={StaticResource ImageTextButtonStyle}

【问题讨论】:

  • DependencyProperty 字段必须是静态的。
  • @Clemens 是的,当然。感谢您指出。请向被否决的人解释我如何在未来改进我的问题。

标签: c# wpf xaml wpf-controls


【解决方案1】:

首先,您必须决定是要构建 UserControl 还是 CustomControl。

UserControl 需要从“UserControl”基类派生。由于您的 C# 代码扩展了“Button”,因此该实现不属于“UserControl”。

对于自定义控件,您的样式应该存在于名为“Generic.xaml”的文件中,该文件应该放置在“主题”文件夹中。 (您仍然可以更改默认主题文件夹位置)。您的 C# 文件应定义用于查找/定位/识别 Xaml 样式的键。

您的上述设置不应该工作,因为它既不满足用户控件也不满足自定义控件要求。

我无法创建完整的示例,但可以在一定程度上指导您。

您需要具有以下静态方法才能将默认样式设置为最低限度。根据需要添加剩余的属性。

public class ImageButton : Button
{
  
    static ImageButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), new FrameworkPropertyMetadata(typeof(ImageButton)));
    }

    public ImageButton()
    {

    }

对于 Xaml 部分。创建一个 文件夹主题 并在其中创建一个名称为 "Generic.xaml" 的资源字典。在您的 Generic.Xaml 中,添加您的样式。 (将您的 xaml 逻辑放在控件模板中)。

<Style TargetType="{x:Type bc:ImageButton}">
    <Setter Property="Cursor" Value="Hand"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type bc:ImageButton}">
            </ControlTemplate>
        </Setter>
    </Style>

以上所有内容都是自定义控件的最低要求。如果您希望创建一个 UserControl,您需要一个 .xaml 和一个 .xaml.cs 文件。您可以轻松使用 Visual Studio 上下文菜单(右键单击解决方案)并创建用户控件。

重要提示: 当你创建一个自定义控件时,你不需要像下面这样的东西

Background="{Binding RelativeSource={RelativeSource AncestorType=local:ImageTextButton}, Path=Image}">

随便用,TemplateBinding

 Background="{TemplateBinding Image}">

【讨论】:

  • 谢谢,这让我更进一步。我已经添加了许多 UserControl 项目。这应该是一个自定义控件,因为我想要按钮行为和事件,但只是以不同的方式对其进行模板化。我从来不知道 XAML 位置有一个标准,也没有覆盖样式的方法。我最初有TemplateBinding,但我收到了一个错误The member Image is not recognized or is not accessible
  • TemplateBindingControlTemplate 触发器中不起作用。因此与RelativeSource 绑定。我确实得到了这个工作。谢谢。
  • 我很高兴它有帮助。我编写了一个带有多个 WPF 自定义控件的开源库。 (该库会定期更新。)请查看 github repo。 github.com/TheHaleyProject/HaleyWPF/tree/development 它有 15+ 个自定义控件(包括图像按钮、图像组合按钮、分页、数字增量器等)。我还发布了一个 nuget 库 Haley.WPF。看看吧,你可能会得到一些想法。
  • 疯狂 - 我正在制作一个程序集以添加到一堆 WPF 应用程序中。我已经添加(并且运行良好)的组件包括分页器、日历范围、范围滑块和屏幕键盘。现在这个按钮在那里。听起来我过去可以为自己节省一些工作。
【解决方案2】:

RelativeSource 模式 FindAncestor 缺失

{RelativeSource AncestorType=local:ImageTextButton} 更改为{RelativeSource FindAncestor, AncestorType=local:ImageTextButton}

【讨论】:

    猜你喜欢
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 2015-12-06
    相关资源
    最近更新 更多