Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WPF, Silverlight Новый топик    Ответить
 Векторная графика, Geometry, Path и Adobe Illustator  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4042
Тема для меня крайне актуальная, но так как не до конца понятно, как же всё работает это в WPF У меня есть куча вопросов, на которые я надеюсь получить ответы.

Начнем с простого, есть коллекция объектов Person и окно которое отображает эту коллекцию в виде списка в окне. Всё просто.
В шаблон данных элемента списка мы в панели размещаем иконку и имя Person'ы.
Итак у нас есть масса разных путей для размещения иконки в этом элементе.
Начнем с самого простого:
Вариант 1. мы сохраняем в формате PNG или любом другом картинку в ресурсах, помечаем её как Reousrce, добавляем в шаблоне Image и указываем в Source URI адрес нашего ресурса.
Ресурс загружается в память 1 раз в виде BitmapImage и далее эта картинка будет дёргаться от туда для каждого элемента списка.
(это мое виденье происходящего, я могу ошибаться! и буду раз, если вы меня поправите).

Вариант 2. В шаблоне данных мы создаем элемент Canvas, внутри этого элемента мы рисуем иконку с помощью объекта Path.
Так как я художник рукожоп, я конечно сам не рисую иконки, для этого есть дизайнеры, они рисуют в AI, а я с помощью Blend импортирую эту картинку. В результате импорта я получаю тот же самый Canvas с объектам Path внутри, в каждом объекте Path в свойстве Data указана геометрия этого объекта.
Так как свойство Data имеет тип Geometry и принимает в значение в виде строки, которая преобразуется с помощью конвертера в GeometryStream, сколько раз будет происходить это преобразование? 1 раз при инициализации шаблона или каждый раз при его размещении в окне?

Вариант 3. С помощью бубна и прочих инструментов в ресурсах приложения я создаю собственный ресурс с геометрией иконки. Затем мне нужно разместить объект Path там, где мне нужно и в свойстве Data указать ему через {StaticResource } имя ресурса с моей геометрией. Так как в геометрии я не могу размещать объекты относительно друг друга, приходится использовать трансформации, комбинирование, группировку и другое, что крайне усложняет сам процесс.
Очевидно, что в таком случае геометрия создается 1 раз, загружается в память в виде ресурса, а потом просто извлекается где нужно по имени ресурса. С точки зрения работы, размера визуального дерева вариант #3 быстрее вариант 2, так как я не использую множество панелей Canvas и прочей лабуду. А в самом шаблоне иконка размещается в виде 1 строки.

Буду рад советам от тех, кто на этом уже собаку съел.
4 авг 15, 11:04    [17972632]     Ответить | Цитировать Сообщить модератору
 Re: Векторная графика, Geometry, Path и Adobe Illustator  [new]
Сон Веры Павловны
Member

Откуда:
Сообщений: 6034
Roman Mejtes
Вариант 1. мы сохраняем в формате PNG или любом другом картинку в ресурсах, помечаем её как Reousrce, добавляем в шаблоне Image и указываем в Source URI адрес нашего ресурса.
Ресурс загружается в память 1 раз в виде BitmapImage и далее эта картинка будет дёргаться от туда для каждого элемента списка.

Ну так оно и есть:
<Window.Resources>
  <ObjectDataProvider
    x:Key="RangeProvider"
    ObjectType="{x:Type linq:Enumerable}"
    MethodName="Range">
    <ObjectDataProvider.MethodParameters>
      <system:Int32>0</system:Int32>
      <system:Int32>4</system:Int32>
    </ObjectDataProvider.MethodParameters>
  </ObjectDataProvider>
  <DataTemplate x:Key="ItemTemplate">
    <Grid Margin="0,3">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="Auto"/>
      </Grid.ColumnDefinitions>
      <Image Source="/wpftest2;component/jr.png" />
      <TextBlock Grid.Column="1" Text="{Binding}" Margin="10,0,0,0"/>
    </Grid>
  </DataTemplate>
</Window.Resources>
<Grid Margin="10">
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <ListBox
    x:Name="listBox"
    ItemsSource="{Binding Source={StaticResource RangeProvider}}"
    ItemTemplate="{StaticResource ItemTemplate}" />
  <Button
    Grid.Row="1"
    Content="Test"
    Padding="10"
    Margin="10"
    VerticalAlignment="Center"
    HorizontalAlignment="Center"
    Click="ButtonClick" />
</Grid>

public partial class MainWindow
{
  public MainWindow()
  {
    InitializeComponent();
  }

  private void ButtonClick(object sender, RoutedEventArgs e)
  {
    var images = Enumerable.Range(0, 4)
      .SelectMany(n => FindVisualChildren<Image>(listBox.ItemContainerGenerator.ContainerFromItem(n)));
    foreach(var i1 in images)
      foreach (var i2 in images)
        Console.WriteLine("{0} {1}", ReferenceEquals(i1, i2), ReferenceEquals(i1.Source, i2.Source));
  }

  public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
  {
    if (depObj != null)
    {
      for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
      {
        var child = VisualTreeHelper.GetChild(depObj, i);
        if (child != null && child is T)
          yield return (T)child;
        foreach (T childOfChild in FindVisualChildren<T>(child))
          yield return childOfChild;
      }
    }
  }
}

- при нажатии на кнопку выводится:

True True
False True
False True
False True
False True
True True
False True
False True
False True
False True
True True
False True
False True
False True
False True
True True

- т.е. для каждого элемента ItemsControl'а создается отдельный экземпляр Image, но при этом у них у всех одинаковый экземпляр ImageSource.
А по поводу того, что лучше - см., например, здесь. Я уже пробовал как-то использовать векторную графику внутри темплейта для ItemControl - по ощущениям (никаких замеров не делал) получалось тормознутее, чем с картинками из ресурсов.
4 авг 15, 13:27    [17973451]     Ответить | Цитировать Сообщить модератору
 Re: Векторная графика, Geometry, Path и Adobe Illustator  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 4042
да не особо должно быть тормознутее, по сути после того как графический элемент построен, он в любом случае кешируется в Bitmap, после чего отображается на экране.
При этом векторная графика дает мне возможность, налету изменять цвет иконок или их частей, анимировать иконки, производить трансформации без потери качества.
+ для повышения высокой производительности в WPF нужно использовать Visual, а не FrameworkElement, а в Visual всё как раз работает на геометрии.
К сожалению, по ходу работы я пока еще не успел разобраться полностью с элементы Visual , хотя конечно же все видимые элементы являются Visual =)

По идее, есть еще формат GeometrySteam, по сути это поток который можно сохранить в файл, а значит его можно загрузить из файла ресурса (как вариант), этот вариант я еще не рассматривал :)

вопрос остается открытым, но всё равно спасибо Вере Павловне :)
4 авг 15, 13:36    [17973484]     Ответить | Цитировать Сообщить модератору
Все форумы / WPF, Silverlight Ответить