Răspuns Entwicklung von Usercontrols

  • 12 iunie 2012 10:14
     
     

    Hallo alle zusammen!

    In meiner silverlight-basierten WEB-Seite soll es mehrere unterschiedliche grafische Objekte bzw. Objekttypen geben, die zum einen in Abhängikeit von Prozesswerten ihren visuellen Zustand ändern (Farbumschlag, rot blinken etc.) und per Doppelklick ein typ-spezifisches Popup anzeigen.
    Bei diesen Objekten handelt es sich zur Zeit um Objekte vom Typ UserControl.
    Alle diese Objekte (egal von welchem Typ) besitzen den gleichen schematischen Aufbau und somit beispielsweise die folgenden
    a) Eigenschaften, die beim Einfügen in die Seite parametriert werden müssen:
    - Name des Obejkts (String)
    - Variablenname für den Prozesswert für den Alarm (Integer oder Bool)
    - Variablenname für den Prozesswert für den Status (Integer oder Bool)

    b) Ereignisse, auf die zur Laufzeit reagiert werden muss:
    - Änderung des Prozesswerts für den Alarm führt z.B. zum Farbumschlag, rot blinken
    - Änderung des Prozesswerts für den Status führt z.B. zum Farbumschlag grün aktiv, grau inaktiv
    - Doppelklick öffnet besagtes PopUp und reicht die Variablennamen für die Prozesswerte weiter

    c) Methoden:
    - ShowPopup
    - DisplayAlarm
    - DisplayStatus

    Bislang ist das ganze leider recht statisch ohne echten Objekt-Gedanken umgesetzt. Das führt dazu, das ca. 75% des Quellcodes bei allen Objekt-Typen identisch ist und bei Änderungen manuell von einem Objekt-Typ zum anderen umkopiert werden muss.

    Bei genauerem Nachdenken erscheint das ganze wie geschaffen für einen objektorientierten Ansatz:

    Eine Basisklasse, die den gemeinsamen Quellcode von ca. 75% an die unterschiedlichen Detail-Klassen für die Objekt-Typen (ca. 1..10) weitervererbt.

    Mein Problem ist die Umsetzung in Bezug auf das Usercontrol. Mir ist bewusst, dass man Daten (Eigenschaften) und Oberfläche trennen sollte. Meine ersten Versuche einfach den "gemeinsamen Quellcode" in einer eigenen Klasse zu isolieren und einem vorhandenen UserControl hinzuzufügen sind leider kläglich gescheitert....

    Bin ich hier gedanklich überhaupt auf dem richtigen Weg?

    Wie funktioniert die Verbindung zwischen den einzelnen Elementen auf dem UserControl und der Basis- bzw. Detail-Klasse?

    Was würdet Ihr empfehlen?  Hat jemand ein Beispiel?

    Ich bin für jede Hilfe dankbar  :)

Toate mesajele

  • 12 iunie 2012 10:53
     
     

    Hast Du in Deinem/Deinen UserControl/s dependency properties eingebaut? Z.B. für die Werte Name, Alarm und Status?

    Wenn nicht, dann solltest Du das machen. Dependency Properties ermöglichen Dir dann Datenbindung, mit deren Hilfe kannst Du dann z.B. die Werte eines CLR-Objects einer selbstdefinierten Klasse mit den Prozesswerten an die DependencyProperties binden und über einen PropertyChangedCallback beispielsweise zusätzliche Manipulationen vornehmen.

    Womit schreibst Du, C# oder VB.NET? In VB.NET könnte ich Dir ein schnelles Beispiel geben.

  • 12 iunie 2012 11:37
     
      Are cod

    Hallo Martin!

    Erstmal vielen Dank für die schnelle Rückmeldung. Ich programmiere in C#.

    Vielleicht poste ich mal kurz ein Objekt exemplarisch. Allerdings bitte nicht gleich die Hände über'm Kopf zusammenschlagen... Das ganze ähnelt inzwischen leider mehr ungewolltem Spaghetti-Code als von mir gewolltem strukturiertem Quellcode.... Wie leider oft hat auch hier ein schneller ungeplanter Anfang über die Zeit mehr Probleme und dergleichen mit sich gebracht .. :(

    Deswegen jetzt der Neuansatz (besser spät als nie):

    Also hier die XAML:

    <UserControl
    	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    	mc:Ignorable="d"
    	xmlns:controlsToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"
    	xmlns:WFIndicators="clr-namespace:WFSilverlight.Indicators;assembly=WFIndicators" xmlns:WFShared="clr-namespace:WFSilverlight.Shared;assembly=WFShared"
    	x:Class="LS_PF_Elements.LSDrive" d:DesignHeight="480" Width="623.499">
    
    	<UserControl.Resources>
    		<Style x:Key="WFIndicator1Style1" TargetType="WFIndicators:WFIndicator1">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="WFIndicators:WFIndicator1">
    						<Grid x:Name="LayoutRoot" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Background="{x:Null}">
    							<VisualStateManager.VisualStateGroups>
    								<VisualStateGroup x:Name="CommonStates">
    									<VisualState x:Name="Normal"/>
    									<VisualState x:Name="State1">
    										<Storyboard>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Offset)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    											</DoubleAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2E9900"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA4FF4E"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Offset)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State2">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF9B0000"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Offset)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFF0000"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State3">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFAD7700"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFDFF2A"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State4">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF0047AF"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF00DAFB"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State5">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2E9900"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF2E9900"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA3FF4E"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFA3FF4E"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State6">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF9B0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF9B0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF9B0000"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFF0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFF0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFFF0000"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State7">
    					<Storyboard RepeatBehavior="Forever">
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Lime"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Lime"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>									</VisualState>
    									<VisualState x:Name="State8">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF0047AF"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF0047AF"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF0047AF"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF00DAFB"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF00DAFB"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF00DAFB"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="ellipse1" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    								</VisualStateGroup>
    							</VisualStateManager.VisualStateGroups>
    							<Rectangle x:Name="ellipse1" Stroke="{x:Null}" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
    								<Rectangle.RenderTransform>
    									<TransformGroup>
    										<ScaleTransform ScaleX="0.9" ScaleY="0.9"/>
    										<SkewTransform/>
    										<RotateTransform/>
    										<TranslateTransform/>
    									</TransformGroup>
    								</Rectangle.RenderTransform>
    								<Rectangle.Fill>
    									<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    										<GradientStop Color="#FF828282"/>
    										<GradientStop Color="#FFFFFFFF" Offset="1"/>
    									</LinearGradientBrush>
    								</Rectangle.Fill>
    							</Rectangle>
    							<WFShared:DialogControl x:Name="PopupDialogElement" IsTabStop="False"/>
    							<Rectangle x:Name="rectangle1" Fill="White" Stroke="Black"/>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<Style x:Key="WFIndicator1Style2" TargetType="WFIndicators:WFIndicator1">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="WFIndicators:WFIndicator1">
    						<Grid x:Name="LayoutRoot" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Background="{x:Null}">
    							<VisualStateManager.VisualStateGroups>
    								<VisualStateGroup x:Name="CommonStates">
    									<VisualState x:Name="Normal"/>
    									<VisualState x:Name="State1">
    										<Storyboard>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Offset)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
    											</DoubleAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2E9900"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA4FF4E"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Offset)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State2">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF9B0000"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Offset)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFF0000"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State3">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFAD7700"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFDFF2A"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State4">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF0047AF"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF00DAFB"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State5">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF2E9900"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF2E9900"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFA3FF4E"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFA3FF4E"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State6">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF9B0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF9B0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF9B0000"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFF0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFF0000"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFFF0000"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State7">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFAD7700"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFAD7700"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFAD7700"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FFFDFF2A"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FFFDFF2A"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFFDFF2A"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State8">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF0047AF"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF0047AF"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF0047AF"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
    												<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF00DAFB"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.2000000" Value="#FF00DAFB"/>
    												<SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FF00DAFB"/>
    											</ColorAnimationUsingKeyFrames>
    											<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever" Storyboard.TargetName="RectDrive" Storyboard.TargetProperty="(UIElement.Opacity)">
    												<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.2000000" Value="0"/>
    												<SplineDoubleKeyFrame KeyTime="00:00:00.4000000" Value="1"/>
    											</DoubleAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    								</VisualStateGroup>
    							</VisualStateManager.VisualStateGroups>
    							<Rectangle x:Name="RectDrive" Stroke="Black" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5" StrokeThickness="5">
    								<Rectangle.RenderTransform>
    									<TransformGroup>
    										<ScaleTransform ScaleX="0.9" ScaleY="0.9"/>
    										<SkewTransform/>
    										<RotateTransform/>
    										<TranslateTransform/>
    									</TransformGroup>
    								</Rectangle.RenderTransform>
    								<Rectangle.Fill>
    									<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
    										<GradientStop Color="#FF828282"/>
    										<GradientStop Color="#FFFFFFFF" Offset="1"/>
    									</LinearGradientBrush>
    								</Rectangle.Fill>
    							</Rectangle>
    							<WFShared:DialogControl x:Name="PopupDialogElement" IsTabStop="False"/>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    		<Style x:Key="StopperStyle" TargetType="WFIndicators:WFIndicator1">
    			<Setter Property="Template">
    				<Setter.Value>
    					<ControlTemplate TargetType="WFIndicators:WFIndicator1">
    						<Grid x:Name="LayoutRoot" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Width="Auto" Background="{x:Null}">
    							<VisualStateManager.VisualStateGroups>
    								<VisualStateGroup x:Name="CommonStates">
    									<VisualState x:Name="Normal">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="White"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="White"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State1">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="Yellow"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="Yellow"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State2">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="Lime"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="Lime"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State3">
    										<Storyboard RepeatBehavior="Forever">
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="White"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="White"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>									
    									<VisualState x:Name="State4">
    										<Storyboard RepeatBehavior="Forever">
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Yellow"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Yellow"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State5">
    										<Storyboard RepeatBehavior="Forever">
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Lime"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Lime"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State6">
    										<Storyboard>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="Blue"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<EasingColorKeyFrame KeyTime="00:00:00" Value="Blue"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>									
    									<VisualState x:Name="State7">
    										<Storyboard RepeatBehavior="Forever">
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Blue"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    											<ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
    												<DiscreteColorKeyFrame KeyTime="00:00:00" Value="Red"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:00.5000000" Value="Blue"/>
    												<DiscreteColorKeyFrame KeyTime="00:00:01" Value="Red"/>
    											</ColorAnimationUsingKeyFrames>
    										</Storyboard>
    									</VisualState>
    									<VisualState x:Name="State8"/>
    								</VisualStateGroup>
    							</VisualStateManager.VisualStateGroups>
    							<WFShared:DialogControl x:Name="PopupDialogElement" IsTabStop="False"/>
    							<Path x:Name="path" Stretch="Fill" Data="M295.63489,-2.7848101 L296.01819,120.44855 L-3.7952416,120.44832 L-4.7428055,-2.7848103 z" UseLayoutRounding="False" Stroke="Black" StrokeThickness="5" Margin="-4.5,-5.5,-3.309,66.742">
    								<Path.Fill>
    									<LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
    										<GradientStop Color="#FF828282"/>
    										<GradientStop Color="White" Offset="0.5"/>
    										<GradientStop Color="Gray" Offset="1"/>
    									</LinearGradientBrush>
    								</Path.Fill>
    							</Path>
    						</Grid>
    					</ControlTemplate>
    				</Setter.Value>
    			</Setter>
    		</Style>
    	</UserControl.Resources>
    
    	<Viewbox>
    
    		<Grid x:Name="LayoutRoot" Height="480" Width="640" Loaded="LayoutRoot_Loaded">
    			<WFIndicators:WFIndicator1 x:Name="I1" Style="{StaticResource StopperStyle}" ConditionRule1="((State &amp; 6) != 0) " ConditionRule2="((State &amp; 512) != 0) " ConditionRule3="(Alarm != 0)" ConditionRule5="(((State &amp; 512) != 0)  &amp;&amp; (Alarm != 0))" ConditionRule4="(((State &amp; 6 != 0)  &amp;&amp; (Alarm != 0))" ConditionRule8="((Q1 != 192) || (Q2 != 192))" MouseLeftButtonDown="I1_MouseLeftButtonDown" Margin="0,0,8,140" ConditionRule7="(((State &amp; 64) !=0) &amp;&amp; (Alarm!=0))" ConditionRule6="((State &amp; 64) != 0) ">
    				<WFIndicators:WFIndicator1.ConditionSignals>
    					<WFShared:ConditionSignalItem ParameterName="State" SignalName="Buffer 1"/>
    					<WFShared:ConditionSignalItem ParameterName="Alarm" SignalName="Buffer 2"/>
    					<WFShared:ConditionSignalItem ParameterName="Q1" SignalName="Buffer 3"/>
    					<WFShared:ConditionSignalItem ParameterName="Q2" SignalName="Buffer 3"/>
    				</WFIndicators:WFIndicator1.ConditionSignals>
    			</WFIndicators:WFIndicator1>
    			<TextBlock x:Name="T1" Text="TextBlock" TextWrapping="Wrap" Margin="66,281,65,76" FontSize="96" Height="123" TextAlignment="Center"/>
    			<Ellipse x:Name="Circle1" Fill="White" Stroke="Black" Height="148" HorizontalAlignment="Left" Margin="90,76,0,0" VerticalAlignment="Top" Width="148" StrokeThickness="8"/>
    			<Ellipse x:Name="Circle2" Fill="White" Stroke="Black" StrokeThickness="8" Height="148" HorizontalAlignment="Right" Margin="0,76,89,0" VerticalAlignment="Top" Width="148"/>
    			<Rectangle x:Name="Line1" Fill="Black" Stroke="#FFEA0A27" StrokeThickness="0" Height="6" Margin="164,76,172,0" VerticalAlignment="Top"/>
    			<Rectangle x:Name="Line2" Fill="Black" Stroke="#FFEA0A27" StrokeThickness="0" Height="6" Margin="164,218,172,0" VerticalAlignment="Top"/>
    		</Grid>
    	</Viewbox>
    </UserControl>

    und im Anschluss gleich den Code-Behind:

    #define HasPopup
    
    #region using
    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.ComponentModel;
    using WFSilverlight.Shared;
    using WFSilverlight.Core;
    using System.Globalization;
    using LS_Std_Controls;
    #endregion using
    
    namespace LS_PF_Elements
    {
    	public partial class LSDrive : UserControl, LSInterfaceTrackelement
        {
            #region Template LS-Trackelement
            // START TEMPLATE TrElement01 -----------------------------------------------------
            WFConnector wfConnector;
    
            public long LastTicks = 0;
            private string AlarmVarName;
    
            #region LS Parameter
            private string pLCConnectionName;
            [Category("LS")]
            public string PLCConnectionName
            {
                get
                {
                    if ((pLCConnectionName == null) || (pLCConnectionName == ""))
                    {
                        pLCConnectionName = Globals.PLC_CONNECTION_NAME;
                    }
                    return pLCConnectionName;
                }
                set
                {
                    pLCConnectionName = value;
                    ElementID = ElementID;
                }
            }
    
            private string elID;
            [Category("LS")]
            public string ElementID
            {
                get
                {
                    return elID;
                }
                set
                {
                    elID = value;
    #if HasPopup
                    if ((elID.Length > 5) && (elID.Length < 8))
                    {
                        T1.Text = elID;
                        I1.ConditionSignals.Clear();
                        // so soll's aussehen: PuF_0x/DB_Kette 01.F01FM04.Status	
                        string sub = PLCConnectionName          // "PuF_01"
                                   + Globals.PLC_SEP            // '/'
                                   + Globals.PLC_PUF_DBNAME     // "DB_Kette "
                                   + elID.Substring(0, 2)        // z.B. "01"
                                   + Globals.PLC_SEP            // '/'
                                   + Globals.PLC_PUF_PRE        // 'F'
                                   + elID;                      // z.B. "01FM04"
    
                        AddConditionItem("State", sub + Globals.PLC_SEP + "Status");
                        AddConditionItem("Q1", Globals.WF_QUALITY + sub + Globals.PLC_SEP + "Status");
                        AddConditionItem("Q2", Globals.WF_QUALITY + sub + Globals.PLC_SEP + Globals.PLC_PUF_ALARM);
    #if !IsStaumelder
                        AddConditionItem("Alarm", sub + Globals.PLC_SEP + Globals.PLC_PUF_ALARM);
    #endif
                        AlarmVarName = sub + Globals.PLC_SEP + Globals.PLC_PUF_ALARM;
                        popup.PUvarPrefix = sub;
                    }
                    else
                    {
                        T1.Text = "###";
                    }
    #else					
    					// ACHTUNG: Wenn das Element keinen Status benötigt (z.B. Notaus), dann sollten 
    					// auch die Conditions State und Q1 in I1 (farbiger Verlaufspfad) gelöscht werden.
    					T1.Text = elID;	
    #endif
                }
            }
    
            #region IsLift
    #if IsLift
    			private string AlarmVarNameTransfer;
    		
    			private string tfID;		
    			[Category("LS")]				
    			public string ElementIDTransfer
    			{
    				get
    				{
    					return tfID;
    				}
    				set
    				{
    					tfID = value;
    					T1.Text = elID+"\n"+tfID;
    					if ((tfID!=null) && (tfID.Length > 5) && (tfID.Length < 8))
    					{
    						// so soll's aussehen: DB_Kette 01.F01FM04.Status					
    						string sub = Globals.PLC_PUF_DBNAME +   // "DB_Kette "
    									tfID.Substring(0,2) +       // z.B. "01"
    									Globals.PLC_SEP +          // '/'
    									Globals.PLC_PUF_PRE +      // 'F'
    									tfID;                      // z.B. "01FM04"
    						AddConditionItem("AlarmTransfer", sub + Globals.PLC_SEP + Globals.PLC_PUF_ALARM);
    						AddConditionItem("Q3", Globals.WF_QUALITY + sub + Globals.PLC_SEP + Globals.PLC_PUF_ALARM);	
    						AlarmVarNameTransfer=sub + Globals.PLC_SEP + Globals.PLC_PUF_ALARM;
    						popupTF.PUvarPrefix = sub;					
    					}		
    				}
    			}
    			
    			private bool TFAlarm=false;
    #endif
            #endregion IsLift
    
            #region HasPopUp
    #if HasPopup
            private bool enableEdit = true;
            [Category("LS")]
            public bool EnableEdit
            {
                get
                {
                    return enableEdit;
                }
                set
                {
                    enableEdit = value;
                }
            }
    #else
    			private string alarmVariable;
    			[Category("LS")]				
    			public string AlarmVariable 
    			{
    				get
    				{
    					return alarmVariable;
    				}
    				set
    				{
    					alarmVariable = value;
    					if (alarmVariable.Length>0)
    					{
    						AlarmVarName=alarmVariable;
    						I1.ConditionSignals.Clear();
    						AddConditionItem("Alarm", alarmVariable);
    						AddConditionItem("Q2", Globals.WF_QUALITY + alarmVariable);	
    					}
    				}
    			}
    #endif
            #endregion HasPopUp
    
            #region Text-Transformation
            private bool sTextVisible = true;
            [Category("LS")]
            public bool TextVisible
            {
                get
                {
                    return sTextVisible;
                }
                set
                {
                    sTextVisible = value;
                    if ((sTextVisible) && (Globals.TrEl_TxtVisible))
                    {
                        T1.Visibility = Visibility.Visible;
                    }
                    else
                    {
                        T1.Visibility = Visibility.Collapsed;
                    }
                }
            }
    
    
            private double txtRotate = 0;
            [Category("LS")]
            public double TextRotation
            {
                get
                {
                    return txtRotate;
                }
                set
                {
                    txtRotate = value;
    
                    T1.RenderTransform = Globals._transformTxt(xOfs, yOfs, txtRotate, T1.ActualWidth, T1.ActualHeight);
                }
            }
    
            private int xOfs = 0;
            [Category("LS")]
            public int xOffset
            {
                get
                {
                    return xOfs;
                }
                set
                {
                    xOfs = value;
                    T1.RenderTransform = Globals._transformTxt(xOfs, yOfs, txtRotate, T1.ActualWidth, T1.ActualHeight);
                }
            }
    
            private int yOfs = 0;
            [Category("LS")]
            public int yOffset
            {
                get
                {
                    return yOfs;
                }
                set
                {
                    yOfs = value;
                    T1.RenderTransform = Globals._transformTxt(xOfs, yOfs, txtRotate, T1.ActualWidth, T1.ActualHeight);
                }
            }
            #endregion Text-Transformation
    
            private int alarmFrameNo;
            [Category("LS")]
            public int AlarmFrameNo
            {
                get
                {
                    return alarmFrameNo;
                }
                set
                {
                    alarmFrameNo = value;
                }
            }
            #endregion LS Parameter
    
    
            private bool alarmIsSet;
            public bool AlarmIsSet
            {
                get
                {
                    return alarmIsSet;
                }
                set
                {
                    alarmIsSet = value;
                }
            }
    
    
            private void AddConditionItem(string name, string signal)
            {
                ConditionSignalItem csi = new ConditionSignalItem();
                csi.ParameterName = name;
                csi.SignalName = signal;
                I1.ConditionSignals.Add(csi);
            }
    
            private void I1_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
            {
    #if HasPopup
                if (((DateTime.Now.Ticks - LastTicks) < Globals.DOUBLE_CLICK_TICKS) && Globals.TrEl_OpenPopup)
                {
                    popup.Title = ElementID;
                    bool userEnable = true;
                    if ((Globals.TrackPage != null) && (Globals.TrackPage is LSInterfaceTracklayout))
                    {
                        userEnable = (Globals.TrackPage as LSInterfaceTracklayout).CheckProjectAuthorizationTrackelement();
                    }
                    popup.EnableEdit = enableEdit && Globals.TrEl_EnableEdit && userEnable;
    #if IsLift
    					popup.TransferAlarm=TFAlarm;
    #endif
                    popup.Show();
                }
                LastTicks = DateTime.Now.Ticks;
    #endif
            }
    
            public void SetTxtVisible()
            {
                bool b = TextVisible;
                TextVisible = b;
            }
    
            public void SetEnableEdit()
            {
    #if HasPopup
                bool b = EnableEdit;
                EnableEdit = b;
    #endif
            }
    
            public int getAlarmFrameNo()
            {
                if (AlarmIsSet) return AlarmFrameNo; else return -1;
            }
    
            private void LayoutRoot_Loaded(object sender, System.Windows.RoutedEventArgs e)
            {
                // TODO: Ereignishandlerimplementierung hier einfügen.
                if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
                {
                    if (wfConnector == null)
                    {
                        wfConnector = new WFConnector(false);
                    }
    #if !IsStaumelder
                    wfConnector.RegisterSignalChangedHandler("", AlarmVarName, AlarmVarNameChanged);
    #endif
    #if IsLift
    					wfConnector.RegisterSignalChangedHandler("", AlarmVarNameTransfer, AlarmVarNameTransferChanged);
    #endif
    
                }
            }
    
            void AlarmVarNameChanged(string name, object value)
            {
                // Ansicht mit Inhalt bei jeder Änderung updaten
                if (value != null)
                {
                    if (int.Parse(value.ToString()) != 0) AlarmIsSet = true; else AlarmIsSet = false;
                    Globals.CheckAlarms(this);
                }
            }
    
    #if IsLift
    			void AlarmVarNameTransferChanged(string name, object value)
    			{
    				// Ansicht mit Inhalt bei jeder Änderung updaten
    				if (value != null)
    				{						
    					if (int.Parse(value.ToString())!=0) {
    						AlarmIsSet=true; 
    						TFAlarm=true;
    					}
    					else 
    					{
    						AlarmIsSet=false;
    						TFAlarm=false;
    					}
    					Globals.CheckAlarms(this);
    				}
    			}
    #endif
    
            // END TEMPLATE TrElement01 -------------------------------------------------------
            #endregion Template LS-Trackelement
    
            _LSDrivePopup popup;
    		
    		public LSDrive()
    		{
    			// Für das Initialisieren der Variablen erforderlich
                InitializeComponent();
                popup = new _LSDrivePopup();
    		}		
    		
    	}
    		
    }

    An dieser Stelle vielleicht noch einige zusätzliche Gedanken:

    • In der bereits erwähnten Silverlight-WEB-Seite wird es für unterschiedliche Projekte bzw. Einsatz-Fälle  zum einen immer die selben Objekt-Typen (allerding in unterschiedlicher Anzahl) wie das obige geben.
    • Zum anderen wird es auch immer neue "projektspezifische" Objekt geben, die allerdings trotzdem den bisher identischen Grundaufbau besitzen
      z.B.: Objekte für Antriebe und Pumpen, Gebläse etc. (sie unterscheiden sich in ihrem Symbol, den möglichen Fehlermeldungen sind von der anparametrierten Eigenschaften her aber identisch bzw. besitzen höchstens zusätzliche)
    • Aus dem obrigen ergibt sich für mich eine Aufteilung in zwei Bibliotheken
      a) eine allgemeingültige und
      b) eine Projekt-spezifische

    Ich hoffe das verwirrt nicht zu sehr :)

    Vielen Dank im Vorraus!

  • 12 iunie 2012 15:07
     
     
    Ok, Du hast also keine Abhängigkeitseigenschaften in Deinem UserControl. Bist Du vertraut mit Datenbindung und der Verwendung von Abhängigkeitseigenschaften?
  • 13 iunie 2012 13:46
     
     

    Ich habe mich schon mal ein wenig damit beschäftigt. Würde mich aber nicht als Experte auf diesem Gebiet verstehen...

  • 15 iunie 2012 08:00
     
     Răspuns

    Du solltest Deine Quellcode-Struktur m.E. grundlegend neu aufstellen. Das klingt möglicherweise zunächst einmal heavy, aber Du wirst defintiv im Ergebnis profitieren.

    Dabei ist es empfehlenswert, die Datenebene von Deinen UserControls zu trennen und die Datenobjekte über Abhängigkeitseigenschaften mittels Datenbindung an UI-Schicht zu koppeln.

    Das Konzept der Datenbindung ist DAS Schlüsselkonzept für Silverlight. Es wäre unmöglich (und wäre zudem redundant) hier das Konzept der Datenbindung darzustellen. Das ist an andere Stelle sehr gut dargestellt. Empfehlenswert für den grundlegenden Einstieg ist die MSDN-Library, und zwar hier.

    Ohne, dass ich auf Deinen Quellcode vollständig eingehe und Dir hier eine fertige, neue Struktur darstelle, würde eine Struktur mit Datenbindung ungefähr wie folgt aussehen:

    Du implementierst in Deinen UserControls Abhängigkeitseigenschaften bzw. nutzt die Abhängigkeitseigenschaften der in der UI des UserControls verwendeten UI-Elemente. Jeder Abhängigkeitseigenschaft entspricht eine Eigenschaft eines Objekts oder einer Liste von Objekten Deiner Datenschicht, genauer: Eine Eigenschaft eines Datenobjekts bzw. einer Liste von Datenobjekten, bzw. wird an eine solche datengebunden. Die Verbindung zwischen Abhängigkeitseigenschaften und Eigenschaften von Datenojekten wird mittels Datenbindung implementiert.

    Ein Beispiel:

    Angenommen, Du hast ein Datenobjekt, das einen bestimmten MaschinenProzess representiert. Dieser MaschinenProzess hat eine ID, einen Namen und einen AlarmStatus. Dann baust Du eine CLR-Klasse MaschinenProzess mit den Eigenschaften ID, Name und Alarmstatus. Diese CLR-Klasse muss die Schnittstelle INotifyPropertyChanged implementieren. In Deinem UserControl hast Du eine UI, auf der (angenommen) ein TextBlock für den Namen, eine TextBlock für die ID und ein Rectangle für die Anzeige des AlarmStatus enthalten sind. Für das Rectangle hast Du zwei VisualStates definiert, einen für AlarmAn (roter Fill) und einen für AlarmAus (grüner Fill). Nun wird die CLR-Klasse als Datenkontext für das UserControl gesetzt. Die Text-Eigenschaften der beiden TextBlock-Elemente werden nun direkt an die CLR-Eigenschaften ID bzw. Name gebunden. Für die Steuerung des Rectangle-Zustands baust Du eine Abhängigkeitseigenschaft in Deinem UserControl mit der Bezeichnung AlarmStatusProperty. Die CLR-Eigenschaft AlarmStatus des CLR-Datenobjekts bindest Du an die Abhängigkeitseigenschaft AlarmStatusProperty. Und um die visuellen Zustände des Rectangle (also AlarmAn und AlarmAus) steuern zu können, erzeugst Du einen PropertyChangedCallback für diese Abhängigkeitseigenschaft mit dem Namen OnAlarmStatusChanged. Dieser PropertyChangedCallback feuert bei jeder Veränderung des Eigenschaftswerts, und der wiederum wird infolge der Datenbindung an das CLR-Datenobjekt immer dann verändert, wenn der Wert der Eigenschaft des CLR-Datenobjekts sich verändert. Im PropertyChangedCallback (also im Methodenrumpf von OnAlarmStatusChanged) fragst Du den aktuellen Wert von AlarmStatusProperty ab, also entweder True oder False, vorausgesetzt AlarmStatusProperty ist vom Typ Boolean, und je nach dem boolschen Wert aktivierst Du entweder den visuellen Zustand AlarmAn oder AlarmAus.

    Es gibt noch andere, mächtige Werkzeuge im Konzept der Datenbindung, die Du ergänzend oder alternativ verwenden kannst. Beispielsweise kannst Du auch DataTemplates verwenden, was sich insbesondere bei einer Mehrzahl von CLR-Datenobjekten anbietet, deren Daten mit einem bestimmten (UI-)Erscheinungsbild (z.B.) einer ListBox dargestellt werden sollen. Welche Werkzeuge Du letztendlich verwendest, hängt von Deinen konkreten Anforderungen ab.

    Ich hoffe, das hat Dir etwas geholfen.

  • 19 iunie 2012 12:44
    Proprietar
     
     

    Hallo hsackmann,

    Ich gehe davon aus, dass die Antwort Dir weitergeholfen hat.
    Solltest Du noch "Rückfragen" dazu haben, so gib uns bitte Bescheid.

    Grüße,
    Robert


    Robert Breitenhofer, MICROSOFT  Twitter Facebook
    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „Entwickler helfen Entwickler“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.