Почему я не могу использовать свой пользовательский элемент управления WPF в коде C # - PullRequest
0 голосов
/ 16 июля 2010

Я новичок в этом форуме. У меня есть пользовательский элемент управления, определенный с помощью 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 # control

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 Ответ

3 голосов
/ 16 июля 2010

У вас есть три основные проблемы:

  1. Ваш InnerBackground, OuterBackground и WellBorder всегда равны нулю,
  2. В вашем шаблоне нет ContentPresenter,
  3. Ваши эллипсы имеют нулевой размер

Нулевые кисти

Причина, по которой InnerBackground, OuterBackground и WellBorder имеют значение null, заключается в том, что вы устанавливаете их в null в конструкторе. Например, эта строка является проблемой:

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

В этой строке есть две проблемы:

  1. Он использует this.Resoures [], который просматривает только локальный ResourceDictionary. Чтобы сделать эквивалент StaticResource, вы должны заглянуть в ResourceDictionaries ваших предков, что означает вызов FindResource ().
  2. Он находится в конструкторе, поэтому он выполняется до того, как элемент управления имеет родителя. Поскольку на данный момент у него нет предков, даже FindResource () не будет работать для вас.

Лучшее решение этой проблемы - установить эти свойства в стиле, а не в конструкторе:

<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", что для эллипса означает нулевой размер. Это сделает ваши эллипсы невидимыми, даже если у них есть кисти.

Также для сетки задано Width = "Auto" Height = "Auto", что означает сжатие его содержимого в мельчайшее возможное пространство. Это означает, что если для WellButton задано значение VerticalAlignment = "Stretch" или HorizontalAlignment = "Stretch", он упрямо откажется фактически растягиваться. Это плохая вещь в пользовательском элементе управления.

Удалите оба места, где вы говорите, что Ширина = "Авто" и Высота = "Авто", и вместо этого оставьте значение Высота и Ширина неустановленными.

Прочие вопросы и придирки

Ваш второй эллипс имеет StrokeThickness = "0", что не имеет смысла для меня, так как нет удара. Почему бы не оставить это? То же самое для RenderTransformOrigin, поскольку RenderTransform отсутствует.

Ваш первый эллипс не должен указывать HorizontalAlignment = "Stretch" VerticalAlignment = "Stretch", так как это значение по умолчанию.

Ваши привязки слишком сложны:

  1. Вы можете опустить «Path =», если путь не содержит вложенных свойств.
  2. Вы можете опустить «Mode = OneWay», так как это значение по умолчанию, но самое главное:
  3. Вместо этого вы можете использовать TemplateBinding, который намного чище:

Синтаксис TemplateBinding:

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

Поля на вашем втором эллипсе настолько велики, что даже если в вашем коде C # будет учтено Width = "40" Height = "40" (поскольку проблема с Auto была исправлена), эллипс все равно не будет иметь размера. Также кажется странным иметь эллипс с таким необычным краем.

Nitpick: «Фон» - это одно английское слово, в середине которого нет заглавной буквы G.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...