Преобразование одного значения в несколько свойств - PullRequest
1 голос
/ 25 марта 2011

Я использую следующий шаблон данных:

<DataTemplate>
    <Grid Width="40" Height="40">
        <Ellipse Width="30" Height="30" x:Name="ellipse" />
        <TextBlock Text="{Binding Robot.Id}" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <Line X1="20" X2="40" X2="20" X2="30" x:Name="line" />
    </Grid>
</DataTemplate>

Я хочу применить следующий код к строке при изменении свойства DataContext:

void UpdateHeading(double angle)
{
    var center = grid.Width/2;
    var radius = ellipse.Width/2;
    line.X1 = center + (radius+5)*Math.Sin(angle);
    line.Y1 = center + (radius+5)*Math.Cos(angle);
    line.X2 = center + (radius-5)*Math.Sin(angle);
    line.Y2 = center + (radius-5)*Math.Cos(angle);
}

Обратите внимание, что для кода требуется доступ к размеру двух других элементов

Как лучше всего добавить код? использование преобразователя значений здесь не кажется правильным, поскольку мне нужно преобразовать одно свойство в четыре

Ответы [ 3 ]

0 голосов
/ 26 марта 2011

Реализуйте INotifyPropertyChanged в своем классе, который предоставляет DataContext и предоставляет свойства для всех значений, которые необходимо обновить. Затем просто привязать к этим свойствам. Свойства могут вычислять любые значения, которые им нужны, и пользовательский интерфейс будет обновляться.

Например:

public class Heading : INotifyPropertyChanged
{
    private string name = "";
    public string Name { get { return name; } set { name = value; SendPropertyChanged("Name"); } }
    public int Radius { get { return GridWidth/2; } }
    public double X1 { get { return Center + (Radius + 5) * Math.Sin(Angle); } }
    public double X2 { get { return Center + (Radius + 5) * Math.Cos(Angle); } }
    public double Y1 { get { return Center + (Radius - 5) * Math.Sin(Angle); } }
    public double Y2 { get { return Center + (Radius - 5) * Math.Cos(Angle); } }
    public int Center { get { return GridWidth/2; } }

    private int gridWidth = 50;
    public int GridWidth { get { return gridWidth; } set { gridWidth = value; } } 

    private double angle;
    public double Angle { get { return angle; } set { angle = value; SendPropertyChanged(""); } } //Empty string to notify of all properties

    public event PropertyChangedEventHandler PropertyChanged;
    void SendPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Тогда просто установите привязку в вашем шаблоне так:

<DataTemplate>
    <Grid >
        <Ellipse Width="{Binding GridWidth}" Height="40" x:Name="ellipse" Fill="Green" />
        <TextBlock Text="{Binding Name}" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <Line X1="{Binding X1}" X2="{Binding X2}" Y1="{Binding Y1}" Y2="{Binding Y2}" x:Name="line" Stroke="Black" />
    </Grid>
</DataTemplate>

Надеюсь, это поможет.

0 голосов
/ 27 марта 2011

Я решил создать свою собственную форму.

Использование XAML:

<Grid Width="40" Height="40">
    <Ellipse x:Name="ellipse" Width="30" Height="30" />
    <TextBlock Text="{Binding Robot.Id}" HorizontalAlignment="Center" VerticalAlignment="Center" />
    <Controls:HeadingLine BoundingSize="40" ShapeSize="30" Length="10" Angle="{Binding Heading}" Stroke="Black" StrokeThickness="1" />
</Grid>

И код:

public sealed class HeadingLine : Shape
{
    // Properties definitions
    ....
    // Code based on http://www.codeproject.com/KB/WPF/wpfarrow.aspx 

    protected override Geometry DefiningGeometry
    {
        get
        {
            var geometry = new StreamGeometry();
            using (var context = geometry.Open())
            {
                InternalDrawArrowGeometry(context);
            }

            geometry.Freeze();
            return geometry;
        }
    }

    private void InternalDrawArrowGeometry(StreamGeometryContext context)
    {
        var center = BoundingSize / 2;
        var radius = ShapeSize / 2;
        var offset = Length / 2;
        var angle = Math.PI - Angle;

        var x1 = center + (radius + offset) * Math.Sin(angle);
        var y1 = center + (radius + offset) * Math.Cos(angle);
        var x2 = center + (radius - offset) * Math.Sin(angle);
        var y2 = center + (radius - offset) * Math.Cos(angle);

        context.BeginFigure(new Point(x1, y1), false, false);
        context.LineTo(new Point(x2, y2), true, true);
    }
}
0 голосов
/ 25 марта 2011

Существует также IMultiValueConverter

EDIT: У вас должна быть ViewModel со свойством угла, и вы можете связать его следующим образом (я продемонстрировал только для x1:

<DataTemplate>
    <Grid Width="40" Height="40" x:Name="grid">
        <Ellipse Width="30" Height="30" x:Name="ellipse" />
        <TextBlock Text="{Binding Robot.Id}" HorizontalAlignment="Center" VerticalAlignment="Center" />
        <Line X2="40" X2="20" X2="30" x:Name="line">
            <Line.X1>
                <MultiBinding Converter="{StaticResource yourConverter}" ConverterParameter="{yourns:Enum">
                    <Binding ElementName=grid Path=Width />
                    <Binding ElementName=ellipse Path=Width />
                    <Binding Path=Angle />
                </MultiBinding>
            </Line.X1>
        </Line>    
    </Grid>
</DataTemplate>
...