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