Мои особые потребности визуального наследования wpf - PullRequest
0 голосов
/ 01 марта 2012

Я знаю, что здесь много вопросов о визуальном наследовании wpf, но я не могу найти тот, который очень близок к тому, что мне нужно.В приложении CRUD у меня много представлений (на самом деле это пользовательские элементы управления), которые имеют большинство общих компонентов.У меня есть несколько строк и несколько столбцов сетки, заполненной метками, текстовым полем и другими элементами управления.Сфокусируемся, например, на ячейке в строке 2 и столбце 2. В зависимости от операции CRUD, которую пользователь выполняет, в качестве альтернативы содержит метку, текстовое поле, поле со списком или оно пустое.Из других ответов на этом сайте я узнал, как сделать текстовое поле доступным только для чтения при помощи стилей и триггеров, но в моем случае мне пришлось изменить тип элемента управления.Конечно, я могу перекрывать все необходимые мне элементы управления и изменять их видимость, но я не думаю, что это лучший подход.Чтобы выразить это другими словами, у меня есть некоторые представления, которые разделяют большинство ячеек сетки, используемой для разметки, но они отличаются для некоторых компонентов внутри определенных и ограниченных ячеек.Что бы вы сделали в этом случае?В выигрышных формах я могу поместить общие части в базовый класс и извлечь из него, с xaml я не могу это сделать.

Спасибо, Филиппо

Ответы [ 3 ]

1 голос
/ 02 марта 2012

ОК, из ваших комментариев я понимаю, что вы хотите, чтобы каждый контекст имел свой собственный файл XAML, но чтобы он ссылался на какой-то общий шаблон.Вы можете сделать это следующим образом:

Установите общий шаблон, например, в CommonControl.xaml:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Rectangle Grid.Row="0" Grid.Column="0" Fill="Yellow" />
    <TextBlock Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="15" Text="This is some fixed text"/>
    <ComboBox Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    <StackPanel Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center">
        <CheckBox>My first checkbox</CheckBox>
        <CheckBox>My second checkbox</CheckBox>
    </StackPanel>
    <ContentControl Grid.Row="1" Grid.Column="1" Content="{Binding Path=SpecificPart1, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
    <Ellipse Grid.Row="1" Grid.Column="2" Fill="Blue"/>
</Grid>

Это имеет различные элементы пользовательского интерфейса, образующие общий пользовательский интерфейс во всех позициях сетки,за исключением строки сетки 1, столбца 1 (нижняя центральная панель), где будет отображаться специфичный для контекста пользовательский интерфейс.

Теперь в коде CommonControl.xaml.cs вы создали объект зависимости, чтобы разрешитьспецифичный для контекста пользовательский интерфейс, который будет введен в шаблон:

    public object SpecificPart1
    {
    get { return this.GetValue(SpecificPart1Property); }
    set { this.SetValue(SpecificPart1Property, value); } 
    }
    public static readonly DependencyProperty SpecificPart1Property = DependencyProperty.Register(
        "SpecificPart1", typeof(object), typeof(CommonControl), new PropertyMetadata(false));

Если есть несколько позиций, в которые вы хотите поместить контекстный пользовательский интерфейс, вы можете добавить другое свойство зависимости здесь для другой части.

Затем вы можете настроить столько XAML-файлов, сколько захотите, и все они ссылаются на это и вставляют свой собственный элемент пользовательского интерфейса, чтобы переходить в изменяющуюся часть.Вот один пример, который помещает некоторый зеленый курсив туда.В MySpecificControl.xaml:

    <my:CommonControl>
        <my:CommonControl.SpecificPart1>
            <TextBlock Foreground="DarkGreen" FontStyle="Italic" FontSize="14">This is my context specific UI</TextBlock>
        </my:CommonControl.SpecificPart1>
    </my:CommonControl>
0 голосов
/ 01 марта 2012

Ну, я бы определенно посмотрел на DataTemplate с .

Если требования достаточно просты, чтобы просто выбрать шаблон на основе DataType, то все готово ... Например, вот некоторый XAML, который автоматически использует правильный шаблон (TextBox или DatePicker), если у вас коллекция объектов, представляющая собой смесь string и DateTime.

<MyControl.Resources>
  <DataTemplate DataType="{sys:String}">
    <TextBox Text="{Binding}" />
  </DataTemplate>

  <DataTemplate DataType="{sys:DateTime}">
    <DatePicker Date="{Binding}" />
  </DataTemplate>
</MyControl.Resources>

<ItemsControl Items="{Binding MyListOfObjects}" />

Если вам нужна дополнительная логика вне простого типа, тогда вы захотите взглянуть на DataTemplateSelector. Например, если у вас есть коллекция сложных объектов и некоторые свойства в этих сложных объектах, которые будут определять, какой DataTemplate выбрать, тогда вам следует использовать DataTemplateSelector.

<MyControl.Resources>
  <DataTemplate x:Key="TextViewTemplate">
    <StackPanel Orientation="Horizontal">
      <Label Content="Name:" />
      <TextBox Text="{Binding Path=Name}" />
    </StackPanel>
  </DataTemplate>

  <DataTemplate x:Key="TextUpdateTemplate">
    <StackPanel Orientation="Horizontal">
      <Label Content="Name:" />
      <TextBox Text="{Binding Path=Name}" IsReadOnly="True" />
    </StackPanel>
  </DataTemplate>

  <local:MyDataTemplateSelector x:Key="MySelector"
     ManagerTemplate="{StaticResource TextUpdateTemplate}"
     EmployeeTemplate="{StaticResource TextViewTemplate}" />
</MyControl.Resources>

<ItemsControl Items="{Binding Employees}"
              ItemTemplateSelector="{StaticResource MySelector}" />


public MyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate ManagerTemplate { get; set; }
    public DataTemplate EmployeeTempalte { get; set; }

    public override DataTemplate SelectTemplate(object item,
        DependencyObject container)
    {
         switch (UserClass.UserLevel)
         {
            case UserLevel.Manager:
                if (ManagerTemplate != null)
                    return ManagerTemplate;
                break;

            case UserLevel.Employee:
                if (EmployeeTemplate != null)
                    return EmployeeTemplate;
                break;

            default:
                throw InvalidOperationException("Invalid enumeration value.");
         }

         return base.SelectTemplate(item, container);
    }
}

Имейте в виду, что это всего лишь один из способов сделать это ... DataTemplateSelector очень редко используются, потому что большая часть логики выбора может быть просто применена к подобным шаблонам и предоставляя дополнительное свойство. Например, вместо использования этого селектора вы можете просто предоставить свойство «IsEditable» и связать его с IsReadOnly DependencyProperty. Но это был только пример, чтобы показать использование. В любом случае, надеюсь, что это поможет.

0 голосов
/ 01 марта 2012

Похоже, вы хотите использовать ContentControl с триггерами.Я не знаю точно, что определяет, какой тип элемента управления вы хотите отобразить, но, например, скажем, у вас есть свойство «Condition», которое может принимать значения «ConditionValue1» или «ConditionValue2», и вы хотите показать другой фрагмент пользовательского интерфейса, зависимыйпо какому значению вы можете использовать XAML следующим образом:

   <ContentControl Grid.Row="2" Grid.Column="2">
        <ContentControl.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Condition}" Value="ConditionValue1">
                        <Setter Property="ContentControl.Template">
                            <Setter.Value>
                                <ControlTemplate>
                                    [ First control goes here ]
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Condition}" Value="ConditionValue2">
                        <Setter Property="ContentControl.Template">
                            <Setter.Value>
                                <ControlTemplate>
                                    [ Second control goes here ]
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>

Большим преимуществом этого по сравнению с использованием Visibility является то, что элементы управления загружаются только тогда, когда они необходимы, и когда в них вставлен другой элемент управления.место, старый может быть выгружен.При Visibility = Collapsed элемент управления все еще загружается и висит в фоновом режиме.

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