views:

244

answers:

2

Hi everyone,

I hope I am not being silly asking this, but I am trying to design a graph viewer in WPF being a total newb in the framework; although I did come up with a couple of solutions to my problems, the one I'm most proud of... does not work where it should. What I'm trying to do is to place a node on the ItemsControl at a position I calculated with Dijkstra's alg + some maths. The problem is that what I move around when using a normal X and Y Binding is the upper-left corner of the TextBlock with Border but what I'd like to manpulate is their center instead. Thus, my nodes end up sticking down and to the right from the point I specify, not centered on it.

I finally settled for a Multibinding using the X/Y property of my NodeViewModel and the Grid's ActualWidth/Height. What happens is that all my nodes get placed at (0,0)! I even debugged the code and looked at the converter, but the return value seems OK. I even tried some random things like binding to other properties etc.

I am totally puzzled.

So one question would be - does MultiBinding work that way? Or am I making some stupid mistake? I'll post my Converter below the XAML code. The parts in XAML cut out are a tooltip and an embedded ItemsControl, but cutting these out changes nothing (except for improving the clarity of the code). The casting in the converter is because casting directly to float does not work for me (but that's irrelevat - it works the way it is even if it's not very beautiful).

And another question would be - can I do it in any simpler way? Like manipulate the center of the TextBlock directly?

XAML:

    <Grid>
        <ItemsControl ItemsSource="{Binding Source={StaticResource Nodes}, Path=Nodes}">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="vievModels:NodeViewModel">
                    <Grid>
                        <Grid x:Name="nodeGrid">
                            <Grid.RenderTransform>
                                <TranslateTransform>
                                    <TranslateTransform.X>
                                        <MultiBinding Converter="{StaticResource PositionConverter}">
                                            <Binding Path="Position.X"/>
                                            <Binding ElementName="nodeGrid" Path="ActualWidth"/>
                                        </MultiBinding>
                                    </TranslateTransform.X>
                                    <TranslateTransform.Y>
                                        <MultiBinding Converter="{StaticResource PositionConverter}">
                                            <Binding Path="Position.Y"/>
                                            <Binding ElementName="nodeGrid" Path="ActualHeight"/>
                                        </MultiBinding>
                                    </TranslateTransform.Y>
                                </TranslateTransform>
                            </Grid.RenderTransform>
                            <Border BorderBrush="Black" BorderThickness="2" CornerRadius="7">
                                <Border.Background>
                                    <SolidColorBrush Color="{Binding Color}" Opacity="0.5"/>
                                </Border.Background>
                                <TextBlock x:Name="Label" Margin="5,5,5,5" MaxWidth="160" TextAlignment="Center" TextWrapping="Wrap" FontFamily="Lucida Console" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Path=Label}"/>
                            </Border>
...
                        </Grid>
...
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="Transparent"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>

C#:

public class PositionConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        float point = float.Parse(values[0].ToString());
        float size = float.Parse(values[1].ToString());
        return point - size / 2;

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

Cheers, Michael

A: 

Just as I thought - a silly mistake. The converted property is of double precision and cannot have float assigned to it. I had to learn how to turn on the debug output to see that.

Michal Gielda
By the way, the way to do it is described here: http://bea.stollnitz.com/blog/?p=52It's a really helpful thing!
Michal Gielda
A: 

If you set RenderTransformOrigin=".5,.5" on the Grid, it should work with a binding to your original values.

Abe Heidebrecht