Проблема с отображением объекта в WPF - PullRequest
1 голос
/ 23 марта 2010

Я настолько новичок в этом, что даже не могу сформулировать вопрос правильно ...

Во всяком случае, я пытаюсь сделать что-то очень простое и не смог понять это. У меня есть следующий класс:

public class Day : Control, INotifyPropertyChanged
{
    public static readonly DependencyProperty DateProperty =
        DependencyProperty.Register("Date", typeof(int), typeof(Day));

    public int Date
    {
        get { return (int)GetValue(DateProperty); }
        set 
        { 
            SetValue(DateProperty, value); 
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Date"));
            }
        }
    }

    public static readonly DependencyProperty DayNameProperty =
        DependencyProperty.Register("DayName", typeof(String), typeof(Day));

    public String DayName
    {
        get { return (String)GetValue(DayNameProperty); }
        set 
        { 
            SetValue(DayNameProperty, value); 
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("DayName"));
            }
        }
    }

    static Day()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Day), new FrameworkPropertyMetadata(typeof(Day)));
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
}

Я узнал, что вы не можете вызывать конструктор с параметрами в XAML, поэтому единственный способ установить некоторые данные для этого класса - через два свойства, DayName и Date.

Я создал ControlTemplate для Day, который выглядит следующим образом:

<Style TargetType="{x:Type con:Day}">
    <Setter Property="MinHeight" Value="20"/>
    <Setter Property="MinWidth" Value="80"/>
    <Setter Property="Height" Value="20"/>
    <Setter Property="Width" Value="80"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type con:Day}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <Rectangle Grid.ColumnSpan="2" x:Name="rectHasEntry" Fill="WhiteSmoke"/>    
                    <TextBlock Grid.Column="0" x:Name="textBlockDayName" Text="{TemplateBinding DayName}" FontFamily="Junction" FontSize="11" Background="Transparent"
                               HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,2,0,0"/>
                    <TextBlock Grid.Column="1" x:Name="textBlockDate" Text="{TemplateBinding Date}" FontFamily="Junction" FontSize="11" Background="Transparent"
                               HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,2,0,0"/>
                    <Rectangle Grid.ColumnSpan="2" x:Name="rectMouseOver" Fill="#A2C0DA" Opacity="0"
                               Style="{StaticResource DayRectangleMouseOverStyle}"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Затем я отображаю его на экране в главном окне следующим образом:

<Window x:Class="WPFControlLibrary.TestHarness.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:con="clr-namespace:WPFControlLibrary.Calendar;assembly=WPFControlLibrary"
    Title="MainWindow" Height="500" Width="525"
    WindowStartupLocation="CenterScreen">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="80"/>
    </Grid.ColumnDefinitions>
    <con:Day Grid.Column="1" Height="20" Width="80" DayName="Mon" Date="1"/>
</Grid>

И то, что я на самом деле вижу, ну, ничего. Если я наведу курсор на строку con: Day в XAML, он выделит прямоугольник правильного размера в окне, но я не вижу «Mon» с левой стороны прямоугольника и «1» справа.

Что я делаю не так? Я подозреваю, что это что-то простое, но я буду проклят, если увижу это.

Моя конечная цель состоит в том, чтобы сгруппировать набор элементов управления Day в элементе управления Month, который затем содержится в элементе управления Year, поскольку я пытаюсь создать длинную панель календаря, которая позволяет вам перемещаться по месяцам и годам, в то время как нажатие на День отобразит любую информацию, сохраненную на эту дату. Но я даже не могу заставить часть Дня отображаться независимо от чего-либо еще, поэтому я далек от остальной функциональности. Любая помощь будет принята с благодарностью.

Ответы [ 3 ]

2 голосов
/ 23 марта 2010

Прежде всего, вам не нужно реализовывать INotifyPropertyChanged, если у вас есть DependencyProperties. Этого более чем достаточно:

    public int Date
    {
        get { return (int)GetValue(DateProperty); }
        set { SetValue(DateProperty, value); }
    }

Когда я пробую ваш пример (без rectMouseOver, поскольку у меня нет определения DayRectangleMouseOverStyle), Mon показывает просто отлично, но 1 не отображается. Мне удалось это исправить, заменив TemplateBinding на явную привязку: вместо

{TemplateBinding Date}

использование

{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Date}

После этого изменения ваш пример работал нормально. Я не знаю почему, но TemplateBinding иногда кажется "сломанным".

0 голосов
/ 23 марта 2010

Вы подходите к этому под углом, который не даст вам ничего, кроме горя. Я знаю это, потому что я сделал именно то, что вы пытаетесь сделать один раз.

Подумайте о подходе к этому: у вас есть класс Day, который предоставляет свойства DayName, DayNumber и Column. Затем вы можете создать шаблон данных для этого класса:

<DataTemplate DataType="{x:Type local:Day}">
   <TextBlock Grid.Column="{Binding Column}" 
              Text="{Binding DayNumber}" 
              ToolTip="{Binding DayName}"/>
</DataTemplate>

Теперь создайте класс Week, который содержит коллекцию объектов Day. Создайте шаблон для этого класса:

<DataTemplate DataType="{x:Type local:Week}">
  <ItemsControl ItemSource={Binding Days}>
    <ItemsControl.ItemsPanel>
      <ItemsPanelTemplate>
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
          </Grid.ColumnDefinitions>
        </Grid>
      </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
  </ItemsControl>
</DataTemplate>

И Month класс, который содержит коллекцию Week объектов. Его шаблон данных выглядит так:

<DataTemplate>
  <ItemsControl ItemsSource="{Binding Weeks}"/>
</DataTemplate>

(Вам не нужно создавать ItemsPanelTemplate здесь, потому что шаблон, который ItemsPanel использует по умолчанию, вертикальный StackPanel, это тот, который вам нужен.

Теперь, если вы создадите экземпляр объекта Month (и правильно заполните его недели и дни), в любом месте вашего XAML, который необходим WPF для его визуализации, он создаст вертикальный StackPanel, содержащий несколько Grid s. каждый из которых содержит семь TextBlock с соответствующими номерами дня в них.

Создание объекта Year и шаблона для него я оставлю в качестве упражнения для вас. Со временем вы добавите ScrollViewer s и стили к этим шаблонам и добавите больше свойств в объектную модель, чтобы помочь с пользовательским интерфейсом. Например, если вы хотите, чтобы день отображался по-разному, если у него есть информация, вы можете добавить свойство HasInformation к классу Day и реализовать триггер данных, чтобы изменить его цвет фона или вес шрифта, если это правда. И вы реализуете Command объектов для вещей, которые вы на самом деле хотите, например, для отображения информации за определенный день. Вы попадете туда.

0 голосов
/ 23 марта 2010

Вам необходимо установить DataTemplate для вашего класса, а не ControlTemplate.

Шаблоны данных используются для определения того, как настраивается пользовательский класс. ControlTemplates с помощью стиля используются для стилизации элемента управления.

Для получения дополнительной информации я рекомендую прочитать Обзор шаблонов данных на MSDN .

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