Laden...

Regal in WPF selber zeichnen

Erstellt von IamTheBug vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.074 Views
I
IamTheBug Themenstarter:in
401 Beiträge seit 2006
vor 8 Jahren
Regal in WPF selber zeichnen

Hallo,

mir stellt sich folgende Aufgabe aber ich bin mir nicht ganz sicher wie ich diese Umsetzen soll und hoffe auf ein paar Gedankenanstöße von euch.

Ich habe eine WPF Anwendung. In dieser Anwendung soll ich ein Regal in der Frontansicht zeichnen. Bestehenden aus zwei Seitenteilen eben und den Einlegeböden. Eventuell das ganze auch noch in einer Holzfarbe einfärben.
Recht im Fenster befinden sich ein paar Textfelder. Dort kann man einstellen wie hoch und breit das Regal sein soll. Weiterhin kann die Einteilung eingestellt werden. Also wie viele Böden vorhanden sind und wie groß ihr Abstand zueinander ist.
Anschließend soll jeder Boden angeklickt werden können und gehighlited werden.

Wie mache ich das ganze in WPF?

Meine Gedankengeänge waren bisher wie folgt:

-ein eigenes UserControl erstellen oder von Canvas ableiten
-im CodeBehind neue DependencyProperties erstellen für Höhe, Breite, Anzahl der Böden
-im Codebehind dann selber Rechtecke zeichnen und positionieren, anhand der Merkmale
oder
-im Codebehind anhand der Merkmale RadioButtons erstellen und diese durch Styles und Templates so verändern das sie aussehen wie ein Regalboden, somit können diese angeklickt werden
oder

  • RadioButtons im XAML erstellen Stylen und im Codebehind auf diese Resourcen zugreifen und das ganze anschliessen positionieren

Was wäre der Beste weg?
Mir ist einfach unklar wie ich am flexiblesten (damit es auch einfach erweiterbar ist) die einzelnen Böden/Ebenen darstellen soll. Weiterhin erschließt sich mir nicht wie das ganze dynamisch passieren soll (der Nutzer gibt ja de Anzahl ein). Und drittens so gemacht ist das der Nutzer die einzelnen ebenen anklicken kann.

Das ganze ist natürlich dann per MVVM an ein Model mittels ViewModel zu binden.
Eventuell soll das ganze irgendwann erweitert werden und links und rechts sollen Linien für die Bemaßung erscheinen.

Vielen Dank und viele Grüße

Mfg

IamTheBug

742 Beiträge seit 2005
vor 8 Jahren

Ich würde ein CustomControl erstellen und da wirst du dann einfach auf Änderungen in den Dependency Properties reagieren müssen.

Dann kannst du die Regelböden einfach per Code erzeugen. Anklicken kann man ja jedes Control und mit Trigger solltest man auch das Styling gut hinbekommen könnem.

I
IamTheBug Themenstarter:in
401 Beiträge seit 2006
vor 8 Jahren

Ich würde ein CustomControl erstellen und da wirst du dann einfach auf Änderungen in den Dependency Properties reagieren müssen.

Ok da sind wir uns da schon einmal einige. Das war auch mein Gedanke.

Dann kannst du die Regelböden einfach per Code erzeugen. Anklicken kann man ja jedes Control und mit Trigger solltest man auch das Styling gut hinbekommen könnem.

Hierbei habe ich noch ein Problem.
Soll ich einfach im CodeBehind des Custom Controls so etwas machen:


Rectangle blueRectangle = new Rectangle();
blueRectangle.Height = 100;
blueRectangle.Width = 200;

und diese anschließend im Canvas oder wo auch immer positionieren.

Oder soll ich im XAML einen Button in der Resource anlegen und diesen stylen. Oder ein Rectangle anlegen und stylen. Im Codebehind würde ich diesen dann sehr oft erzeugen und positionieren.

Eine andere Idee kam mir auch noch. Über ein ItemsControl zu gehen:


        <ItemsControl ItemsSource="{Binding ShelfItems}">
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type local:RectItem}">
                    <TextBlock Text="" TextAlignment="Center">
                        <Rectangle Width="{Binding Width}" Height="{Binding Height}" Stroke="{Binding Color}" StrokeThickness="2" Margin="2"/>
                    </TextBlock>
                </DataTemplate>
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="WhiteSmoke"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding X}"/>
                    <Setter Property="Canvas.Top" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.ItemContainerStyle>
        </ItemsControl>

und eben für andere Typen ein anderes DataTemplate anlegen. Dann werden die Element eines Regals einfach in eine ObservableCollection gepackt und angezeigt.

Mfg

IamTheBug

742 Beiträge seit 2005
vor 8 Jahren

Die Frage ist ja wie dein Control von außen konzipiert sein soll, was z.B. die API betrifft. Wenn du nur die Anzahl übergeben willst, kannst du intern natürlich mit dem ItemsControl arbeitet.

Du kannst die Liste der Regelbretter natürlich auch einfach über das ViewModel managen und in deiner View mit dem ItemsControl arbeiten.

I
IamTheBug Themenstarter:in
401 Beiträge seit 2006
vor 8 Jahren

Eigentlich soll nicht nur die Anzahl angegeben werden. Ein Abstand zum nächsten Boden wird auch noch benötigt. Eventuell auch die Farbe des Bodens.
Ich habe nur das Gefühl das es viele Wege gibt. Die ich alle im Moment nicht so wirklich durchblicke und nicht weiss was welcher Weg der Beste ist.

Mfg

IamTheBug

742 Beiträge seit 2005
vor 8 Jahren

Ich würde auf jeden Fall nicht mit dem Canvas arbeiten, sondern mit dem Grid und dem StackPanel für deine Regalböden. 😉

Dein Template könnte z.B. so aussehen.


<Grid>
	<ItemsControl x:Name="PART_Floors">
		<ItemsControl.ItemTemplate>
			<Grid>
				<Rectangle Fill="Brown" Height="{TemplateBinding FloorThickness}" />
				
				<!-- Margin kann hier nicht direkt ohne Converter gebindet werden, deshalb der Trick ;). -->
				<Rectangle Height="{TemplateBinding FloorHeight}" />
			</Grid>
		</ItemsControl>
	</ItemsControl>
</Grid>


public class Regal
{
    protected override OnApplyTemplate() 
	{
	    this.floors = GetTemplateChild("PART_Floors") as ItemsControl;
		
		UpdateFloors();
	}
	
	private void OnFloorCountChanged()
	{
		UpdateFloors();
	}
	
	private void UpdateFloors()
	{
	    if (floors != null)
		{
		    // Dummy Array
			floors.ItemsSource = new int[FloorCount];
		}
	}
}

I
IamTheBug Themenstarter:in
401 Beiträge seit 2006
vor 8 Jahren

Hi,

an ein Stackpanel hatte ich auch schon gedacht da ja die Böden zusagen übereinander gestappelt werden. Ist ja nunmal so bei einem Schrank 😄
Aber was ist, wenn ich irgendwann noch einmal etwas daneben zeichnen möchte? Zum Beispiel die Gesamthöhe mit einer Maßlinie.

Mfg

IamTheBug

16.806 Beiträge seit 2008
vor 8 Jahren

YAGNI: plan keine Dinge ein, von denen Du nicht weißt, ob sie jemals kommen.

742 Beiträge seit 2005
vor 8 Jahren

Deshalb das Grid außen rum 😉

I
IamTheBug Themenstarter:in
401 Beiträge seit 2006
vor 8 Jahren

Ich wollte nochmal meinen eingeschlagenden Weg aufzeichnen.

Zuerst hatte ich eine Klasse von Canvas abgeleitet und dann im Codebehind via DependencyProperties gezeichnet. War ganz ok. 😃 Aber ich mache jetzt folgendes:

Eine Klasse abgeleitet von Usercontrol.
Dann habe ich ein Stackpanel genommen und dort "stapel" ich RadioButtons die als DataTemplate der Ebenen herhalten. Die RadioButtons habe ich optisch per ControlTemplate angepasst. Jetzt sie ein RadioButton aus wie eine Ebene. Diese werden übereinander gestapelt. Somit habe ich auch die RadioButton Funktionalität zur Verfügung (was gewünscht war).
Im Codebehind habe ich ein DependencyProperty erzeugt. Das DependencyProperty nimmt ein Objekt des Typ "Shelf" also ein Regal.
Diese Klasse hatte ich ja schon und diese Klasse beschreibt ein Regal in Höhe und Breite und die Anzahl der Ebenen.
Im XAML greife ich eben auf das Object zu und lese die Werte aus.
Das ganze wäre natürlich auch ohne das DependencyObject möglich gewesen, indem ich einfach den DataContext des Elements auf die shelf Klasse setze.

Im Moment genügt es erstmal meinen Anforderungen.

@Abt: danke für den Hinweis. Das beschriebende Problem hatte ich schon oft 😄

Mfg

IamTheBug