C# DataBinding Klasse an Canvas Binden

PapstRatze

Lt. Junior Grade
Registriert
Aug. 2008
Beiträge
436
Wie immer, lande ich am Ende bei euch und erbete um eure Hilfe :):
Folgendes Problem habe ich:
Ich bin gerade drauf und dran DataBindings in meinen Schädel zu quetschen. Und nach langem hin und her hänge ich etwas fest. Das Problem ist, dass ich zwei Klassen habe, abgeleitet von einer abstrakten Mutterklasse. Diese möchte ich nun in meinem ItemsControl Binden, allerdings nimmt er die DataTemplates aus dem Window.Resources nicht an. Es ist möglich eine Klasse darzustellen, wenn ich das DataTemplate direkt im ItemsControl festlege.
So funktioniert es, allerdings nur mit einer Klasse:
Code:
<ItemsControl Name="myItemsControl" ItemsSource="{Binding}" Margin="5,5,5,5">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="local:Bakterie">
                <Canvas Height="{Binding Path=Size}" Width="{Binding Path=Size}" Margin="5,5,5,5">
                    <Ellipse Width="5" Height="5" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" Fill="Red"/>
                </Canvas>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
Ich würde jetzt eigentlich gerne die DataTemplates aus dem Window.Resources verwenden:
Code:
 <Window.Resources>
        <DataTemplate DataType="local:Amoebe" x:Key="test">
            <Canvas Height="{Binding Path=Size}" Width="{Binding Path=Size}" Margin="5,5,5,5">
                <Ellipse Width="10" Height="10" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" Fill="Green"/>
            </Canvas>
        </DataTemplate>
        <DataTemplate DataType="local:Bakterie">
            <Canvas Height="{Binding Path=Size}" Width="{Binding Path=Size}" Margin="5,5,5,5">
                <Ellipse Width="5" Height="5" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" Fill="Red"/>
            </Canvas>
        </DataTemplate>
    </Window.Resources>
Für Tipps jeglicher Art wäre ich sehr dankbar, denn DataBindings sind für mich immer noch ein wenig Neuland und ich würde sehr gerne ein bisschen weiter kommen auf dem Gebiet.

Danke schon mal im Voraus für eure Geistreichen Antworten :)

#Edit: den x:Key="test" könnt ihr getrost beiseite lassen, das war wie es eigentlich erkennbar ist nur ein Test ;)
#Edit2: Habe mal die Satzzeichen ein wenig besser platziert :P

#Antwort: Okay, ich habe es jetzt etwas unelegant gelöst, indem ich den Klassen einfach eine "Size" und einen "Brush" beigefügt habe. Falls doch jemand einen Eleganteren Weg kennt, ich bin erpicht darauf von diesem zu Erfahren ;).
 
Zuletzt bearbeitet:
Wenn du den DataType angibst, musst du den Key weglassen ;)
Edit Und natürlich DataType auch korrekt angeben mit DataType="{x:Type TYPE}"
Siehe hier:

MainWindow.xaml
Code:
<Window x:Class="wpfPlayground.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:MyTypes="clr-namespace:wpfPlayground.MyTypes"
        Title="MainWindow" Height="350" Width="525">
    
    <Window.Resources>
        <DataTemplate DataType="{x:Type MyTypes:Foo}">
            <Grid Background="Red" HorizontalAlignment="Stretch" Height="25">
                <Label VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding Title}" />
            </Grid>
        </DataTemplate>
        <DataTemplate DataType="{x:Type MyTypes:Bar}">
            <Grid Background="Green" HorizontalAlignment="Stretch" Height="25">
                <Label VerticalAlignment="Center" HorizontalAlignment="Center" Content="{Binding Title}" />
            </Grid>
        </DataTemplate>
    </Window.Resources>
    
    <Grid>
        <ItemsControl Name="control" ItemsSource="{Binding}" Margin="0,0,0,0" Background="Yellow" />
    </Grid>
</Window>

MainWindow.xaml.cs
Code:
namespace wpfPlayground
{
    using System.Collections.Generic;

    using MyTypes;

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

            List<Base> list = new List<Base>();
            for ( int i = 0; i < 5; i++ )
            {
                list.Add( new Foo() );
                list.Add( new Bar() );
            }

            control.DataContext = list;
        }
    }
}

MyTypes:
Code:
namespace wpfPlayground.MyTypes
{
    public class Base
    {
        public string Title { get; set; }

        public Base()
        {
            Title = GetType().ToString();
        }
    }

    public class Foo : Base
    {
    }

    public class Bar : Base
    {
    }
}

Siehe Screenshot für Ergebnis ;)
 

Anhänge

  • datatemplate.png
    datatemplate.png
    13,5 KB · Aufrufe: 125
Zuletzt bearbeitet:
Wie erwähnt, war der Key ein sinnloser Test, der beim Kopieren noch drinne stand ;). Äh ja, das Problem an der Geschichte ist, dass ich Ellipsen habe, die zum ordentlichen positionieren ein Canvas brauchen?!
==> Hier sei die Frage erlaubt, ist das eine Falsche Annahme oder ist es tatsächlich so, bin mir da nicht sicher.

Am Ende soll es dann etwa so aussehen wie auf dem Bild im Anhang.
(Das ganze soll halt Bakterien darstellen (rot) und Amöben (grün). Die Amöben fressen die Bakterien und vermehren sich ja nachdem wie viele sie gefressen haben, die Bakterien vermehren sich nach der Zeit automatisch durch Zellteilung (natürlich nur wenn se net gefressen wurden ;))

#Edit: Aktuell sieht es halt so aus und funktioniert, es ist halt nicht wirklich das gelbste vom Ei ;)
Code:
<ItemsControl Name="myItemsControl" ItemsSource="{Binding}" Margin="5,5,5,5">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="x:Type local:Bakterie">
                <Canvas Height="{Binding Path=Size}" Width="{Binding Path=Size}" Margin="5,5,5,5">
                    <!-- Da ich dem ItemsControl nur ein Template mitgeben darf, muss ich neben der Postition auch die Größe und die Farbe binden -->
                    <Ellipse Width="{Binding Path=EllipsSize}" Height="{Binding Path=EllipsSize}" Canvas.Left="{Binding Path=X}" Canvas.Top="{Binding Path=Y}" Fill="{Binding Path=Color}"/>
                </Canvas>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

#Edit2: Auch wenn es augenscheinlich nicht gefordert ist, scheint es doch seinen Sinn zu haben ;) also gut ergänze ich beim DataType noch das x:Type.
 

Anhänge

  • so solls aussehen.png
    so solls aussehen.png
    26,6 KB · Aufrufe: 168
Zuletzt bearbeitet:
Ah, OK. Jetzt versteh ich was du machen willst :D

Edit sagt, dass ich noch ein paar Erklärungen hinzufügen sollte :)
Das ItemsControl fügt für jedes Item einen ContentPresenter ein. Das übergeordnete Panel ist nach dem Template ein Canvas. Da Die Properties Canvas.Left und Canvas.Top nur den "Kindern" zugänglich sind, musst die diese Werte im ContentPresenter setzen und nicht in deinen DataTempates.

Code:
<Window x:Class="wpfPlayground.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:MyTypes="clr-namespace:wpfPlayground.MyTypes"
        Title="MainWindow" Height="500" Width="500">
    
    <Window.Resources>
        <DataTemplate DataType="{x:Type MyTypes:Foo}">
            <Ellipse Width="10" Height="10" Fill="Green"/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type MyTypes:Bar}">
            <Ellipse Width="5" Height="5" Fill="Red"/>
        </DataTemplate>
    </Window.Resources>
    
    <Grid>
        <ItemsControl Name="control" ItemsSource="{Binding}" Margin="0,0,0,0" Background="AntiqueWhite">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="{x:Type ContentPresenter}">
                    <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
                    <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>
    </Grid>
</Window>

Code:
namespace wpfPlayground
{
    using System;
    using System.Collections.Generic;

    using MyTypes;

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

            Random rng = new Random();

            List<Base> list = new List<Base>();
            for ( int i = 0; i < 50; i++ )
            {
                list.Add( new Foo( rng.Next( 1, 499 ), rng.Next( 1, 499 ) ) );
                list.Add( new Bar( rng.Next( 1, 499 ), rng.Next( 1, 499 ) ) );
            }

            control.DataContext = list;
        }
    }
}

Code:
namespace wpfPlayground.MyTypes
{
    public abstract class Base
    {
        public double X { get; set; }

        public double Y { get; set; }
    }

    public class Foo : Base
    {
        public Foo( double x, double y )
        {
            X = x;
            Y = y;
        }
    }

    public class Bar : Base
    {
        public Bar( double x, double y )
        {
            X = x;
            Y = y;
        }
    }
}
 

Anhänge

  • canvas.png
    canvas.png
    15 KB · Aufrufe: 153
Zuletzt bearbeitet:
Ah okay, die Erklärung versteh ich ansich ganz gut, für die Umsetzung muss ich noch ein bisschen üben. Arbeite mich irgendwie gerade kreuz und quer durch DataBindings und habe auch heute erst eine passende Lektüre gefunden.

Ich komm bestimmt die Tage zu Styles, dann werde ich die Geschichte hoffentlich vollends verstehen. Jedenfalls schon mal danke für die Hilfe.
#EDIT: So jetzt hab ich es komplett verstanden ;) Langsam merke ich, das DataBindings echt was gutes sind, man muss sich nur richtig mit ihnen beschäftigen.
 
Zuletzt bearbeitet:
Zurück
Oben