为什么我不能在c#代码中使用我的自定义WPF控件

时间:2010-07-16 04:21:37

标签: c# wpf xaml

我是这个论坛的新手。 我有一个使用c#和xaml定义的自定义用户控件。当我把这个控件放到WPF窗口时,它可以工作。即使我可以编辑xaml代码标签并插入我的控件。但是当我在c#代码中使用我的控件时,它不起作用。

这是我的xaml控件定义

<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:local="clr-namespace:UserControl"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">   
  <!-- Resource dictionary entries should be defined here. -->
  <Style TargetType="{x:Type local:WellImage}">
    <Setter Property="Focusable" Value="false" />
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:WellImage}">
          <Grid Width="Auto" Height="Auto">
            <Ellipse Stroke="{Binding Path=WellBorder, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                     StrokeThickness="{Binding Path=WellBorderThickness, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
                     x:Name="Border" Width="Auto" Height="Auto"
                     HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                     Fill="{Binding Path=OuterBackGround, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
            <Ellipse StrokeThickness="0" Margin="25,37,25,18" RenderTransformOrigin="0.5,0.5"
                     Fill="{Binding Path=InnerBackGround, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
          </Grid>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

这是我的c#控件定义

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace UserControl
{
  public class WellImage : System.Windows.Controls.Button
  {
    public static readonly DependencyProperty InnerBackGroundProperty = DependencyProperty.Register("InnerBackGround", typeof(RadialGradientBrush), typeof(WellImage));
    public static readonly DependencyProperty OuterBackGroundProperty = DependencyProperty.Register("OuterBackGround", typeof(RadialGradientBrush), typeof(WellImage));
    public static readonly DependencyProperty WellBorderProperty = DependencyProperty.Register("WellBorder", typeof(SolidColorBrush), typeof(WellImage));
    public static readonly DependencyProperty WellBorderThicknessProperty = DependencyProperty.Register("WellBorderThickness", typeof(double), typeof(WellImage));

    public WellImage()
    {
      // Insert code required on object creation below this point.
      InnerBackGround = (RadialGradientBrush)this.Resources["WellSelectedInnerCircleBrush"];
      OuterBackGround = (RadialGradientBrush)this.Resources["WellSelectedOuterCircleBrush"];
      WellBorder = (SolidColorBrush)this.Resources["NormalBackgroundBrush"];
      WellBorderThickness =2;
    }

    static WellImage()
    {
      //This OverrideMetadata call tells the system that this element wants to provide a style that is different than its base class.
      //This style is defined in themes\generic.xaml
      DefaultStyleKeyProperty.OverrideMetadata(typeof(WellImage), new FrameworkPropertyMetadata(typeof(WellImage)));
    }

    public RadialGradientBrush InnerBackGround
    {
      get { return (RadialGradientBrush)GetValue(InnerBackGroundProperty); }
      set { SetValue(InnerBackGroundProperty, value); }
    }

    public RadialGradientBrush OuterBackGround
    {
      get { return (RadialGradientBrush)GetValue(OuterBackGroundProperty); }
      set { SetValue(OuterBackGroundProperty, value); }
    }

    public SolidColorBrush WellBorder
    {
      get { return (SolidColorBrush)GetValue(WellBorderProperty); }
      set { SetValue(WellBorderProperty, value); }
    }

    public double WellBorderThickness
    {
      get { return (double)GetValue(WellBorderThicknessProperty); }
      set { SetValue(WellBorderThicknessProperty, value); }
    }
  }
}

这是尝试通过c#

访问此控件的方法
 WellImage image = new WellImage();            
        image.Height = 40; 
        image.Width = 40;
        image.Margin = new Thickness(30, 30, 30, 30);
        image.VerticalAlignment = VerticalAlignment.Top;
        image.HorizontalAlignment = HorizontalAlignment.Left;
        image.Content = "WellButton";
        grid.Children.Insert(0, image);
        grid.Background = Brushes.LightBlue;
        grid.Width = 120;
        grid.Height = 100;
        grid.VerticalAlignment = VerticalAlignment.Top;
        grid.HorizontalAlignment = HorizontalAlignment.Left;
        gridPartialedMicroPlate.Children.Insert(0, grid);

为什么我无法访问我的控件?

1 个答案:

答案 0 :(得分:3)

您有三个主要问题:

  1. 您的InnerBackground,OuterBackground和WellBorder始终为null,
  2. 您的模板中没有ContentPresenter,
  3. 您的省略号为零尺寸
  4. 空刷

    InnerBackground,OuterBackground和WellBorder为null的原因是您在构造函数中将它们设置为null。例如,这一行是个问题:

    InnerBackGround = (RadialGradientBrush)this.Resources["WellSelectedInnerCircleBrush"]; 
    

    这一行有两个问题:

    1. 它使用this.Resoures [],它只查看本地ResourceDictionary。要做相当于StaticResource的事情,你必须查看祖先的ResourceDictionaries,这意味着调用FindResource()。
    2. 它位于构造函数中,因此它在控件具有父级之前执行。由于此时它没有祖先,所以即使FindResource()也不适合你。
    3. 此问题的最佳解决方案是在Style中而不是在构造函数中设置这些属性:

      <Style TargetType="{x:Type local:WellImage}">
        <Setter Property="Focusable" Value="false" /> 
        <Setter Property="InnerBackground" Value="{DynamicResource WellSelectedInnerCircleBrush}" />
        ...
      

      如果你真的想在构造函数中这样做,你可以在那里构造一个DynamicResource引用:

      SetValue(InnerBackgroundProperty,
        new DynamicResourceExtension("WellSelectedInnerCircleBrush")
        .ProvideValue());
      

      缺少ContentPresenter

      如果你在模板中包含了一个ContentPresenter,你会看到显示字符串“WellButton”,即使这些省略号是不可见的。

      您应该考虑修改ControlTemplate以包含ContentPresenter以显示Content属性。分配Content属性但不显示它似乎毫无意义。

      零尺寸椭圆

      每个椭圆都设置为宽度=“自动”高度=“自动”,椭圆表示零大小。即使它们有刷子,这也会使你的椭圆不可见。

      此外,网格设置为Width =“Auto”Height =“Auto”,这意味着将其内容压缩到最小的空间。这意味着如果WellButton设置为VerticalAlignment =“Stretch”或Horizo​​ntalAlignment =“Stretch”,它将固执地拒绝实际伸展。这在自定义控件中是一件坏事。

      删除您说Width =“Auto”和Height =“Auto”的地方,而不是取消设置高度和宽度。

      其他问题和挑剔

      你的第二个椭圆有StrokeThickness =“0”,这对我没有意义,因为没有中风。为什么不把它留下来?因为没有RenderTransform,所以同样适用于RenderTransformOrigin。

      你的第一个椭圆不需要指定Horizo​​ntalAlignment =“Stretch”VerticalAlignment =“Stretch”,因为这是默认值。

      你的绑定太复杂了:

      1. 除非路径包含附加属性,否则可以省略“Path =”。
      2. 您可以省略“Mode = OneWay”,因为这是默认设置,但最重要的是:
      3. 您可以使用更简洁的TemplateBinding:
      4. TemplateBinding语法:

        <Ellipse Stroke="{TemplateBinding WellBorder}"
                 ... />
        

        第二个椭圆上的边距非常大,即使你的C#代码中的宽度=“40”高度=“40”也被尊重(因为自动问题已修复),椭圆仍然没有大小。还有一个椭圆具有如此不寻常的余量似乎很奇怪。

        Nitpick:“背景”是一个英文单词,中间没有大写字母G.