Преобразовать любую старую геометрию WPF в PathFigureCollection?

#wpf

#wpf

Вопрос:

У меня есть ряд классов view-model, связанных с формой. Ваша типичная традиционная иерархия: базовый класс ShapeVm, затем LineVm, CircleVm и т. Д. Каждый предоставляет свойство геометрии соответствующего типа.

 public abstract class ShapeVm
{
    public abstract Geometry Geometry { get; }
}
public class LineVm : ShapeVm
{
    public override Geometry Geometry => new LineGeometry(P1, P2);
    public Point  P1 { get; set; }
    public Point  P2 { get; set; }
}
 

До сих пор я предоставлял их в XAML, используя один и тот же тип Path, независимо от типа фигуры.

 <Path Fill="Yellow" StrokeThickness="3" Data={Binding Geometry}"/>
 

Но теперь я хочу иметь возможность применять преобразование к каждой PathGeometry в XAML. Это вызывает у меня проблемы, связанные с «запахом моего кода»:

Мой подход заключается в том, чтобы вручную создать PathGeometry моего объекта Path в XAML и установить его свойство Transform. Но я не могу понять, как чисто преобразовать все различные типы геометрии (LineGeometry, EllipseGeometry и т. Д.) В PathGeometry. Мне нужно предоставить свойство «Цифры» для PathGeometry.

 <Path Fill="Yellow" Stroke="Blue" StrokeThickness="3">
    <Path.Data>
        <PathGeometry Figures="???" **** WHAT DO I USE HERE??? ***
                      Transform="{Binding MyViewGeoTransform}"/>
    </Path.Data>
</Path>
 

Геометрия пути.Свойство Figures имеет тип PathFigureCollection . Есть ли где-нибудь встроенный конвертер, который преобразует любую старую геометрию WPF в PathFigureCollection? Система.Windows.Медиафайлы.GeometryConverter, похоже, не справляется с задачей.

Есть ли какой-нибудь очевидный простой способ сделать это, которого мне не хватает? Должен ли я просто написать свой конвертер?

(Я понимаю, что мог бы просто написать другой шаблон данных для каждого типа фигуры и сделаю это, если он самый чистый, но использование только одного объекта Path в XAML отвечает моему чувству простоты)

Комментарии:

1. У Pathgeometry есть метод addgeometry.

Ответ №1:

Возможно, самым простым подходом к применению преобразования к пути было бы установить его RenderTransform свойство:

 <Path Fill="Yellow" StrokeThickness="3"
      Data="{Binding Geometry}"
      RenderTransformOrigin="0.5,0.5"
      RenderTransform="{Binding MyViewGeoTransform}"/>
 

Если это по какой-либо причине нежелательно, вы можете использовать многосвязку с конвертером, который создает преобразованную GeometryGroup:

 <Path Fill="Yellow" StrokeThickness="3">
    <Path.Data>
        <MultiBinding Converter="{StaticResource TransformedGeometryConverter}">
            <Binding Path="Geometry"/>
            <Binding Path="MyViewGeoTransform"/>
        </MultiBinding>
    </Path.Data>
</Path>
 

Преобразователь:

 public class TransformedGeometryConverter : IMultiValueConverter
{
    public object Convert(
        object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var geometry = new GeometryGroup { Transform = (Transform)values[1] };
        geometry.Children.Add((Geometry)values[0]);
        return geometry;
    }

    public object[] ConvertBack(
        object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}
 

Комментарии:

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

2. Я должен сказать, что я использовал не мультиконвертер, а скорее простой IValueConverter. Я требую, чтобы пользователь передал преобразование в качестве параметра ConverterParameter. Интересно, есть ли какой-либо недостаток в этом по сравнению с подходом IMultiValueConverter.

3. Вы не можете привязать параметр ConverterParameter, но {Binding MyViewGeoTransform} в вашем вопросе есть.

4. Приношу свои извинения. Я оговорился. Я не «привязываю» параметр ConverterParameter. Но я заставляю ConverterParameter использовать расширение StaticResource для ссылки на преобразование в моих ресурсах, которое само связано с необходимыми свойствами. Этот подход, похоже, работает и избавляет меня от необходимости использовать / писать мультиконвертер и все это многословие.