Hallo miteinander,
mir ist leider keine bessere Überschrift eingefallen; Daher kann diese gerne im Laufe des Gesprächs durch einen Mod. angepasst werden.
Folgende Bibliothekenstruktur habe ich aktuell umgesetzt.
FooApp.Common
FooApp.UI -> benutzt intern ua. AOI.RemoteControl
FooApp.RemoteControl -> TCP ClientServer Bibliothek
FooApp.Server.RemoteControl -> Schnittstellen Server zwischen SPS und FoOApp.UI. Benutzt ua. FooApp.RemoteControl / OPC.FooApp
fertige Anwendung die als Standartprodukt vertrieben wird.
OPC.Alarms -> Schnittstelle zwischen SPS und Suite.Common
OPC.FooApp -> Schnittstelle zwischen SPS und FooApp.Common
OPC.Local -> OPC Client
OPC.AOI -> Schnittstelle zwischen SPS und AOI.Common
OPC.QuellTextGenerator -> Software um SPS auszulesen und daraus Quellen etc. zu generieren
OPC.Leitsystem -> Schnittstelle zwischen SPS und Suite.Common
Suite.Common -> Sämtliche Interfaces und Basisklassen
Suite.ErrorCodes -> Unternehmensweite Deklaration von Fehlercodes. Wird in jeder Anwendung verwendet
Suite.GraphQL.Client -> Benutzt Suite.Common um mit dem Suite.Server zu kommunizieren
Suite.GraphQL.Server -> Benutzt Suite.Common um als Suite.Server zu fungieren und mit dem GraphQL.Client zu kommunizieren
Suite.Local -> Beinhaltet sämtliche Module wie bspw. Alarme, Datenbanken, Benutzerverwaltung, Betriebsdaten, Übersetzungen, Leitsystem
Suite.Server -> Serveranwendung. Benutzt ua. OPC.Alarms, OPC.Leitsystem, OPC.Local, sowie projektabhängig AOI.RemoteControl und/oder FooApp.RemoteControl
Suite.UI.Leitstand -> Anwendung zur Verwaltung des Leitsystems. Benutzt intern den Suite.GraphQL.Client
Suite.UI.Client -> Geführter Werkeranwendung. Benutzt intern den Suite.GraphQL.Client
Aus dem Suite "Softwarepaket" wird für unseren Sonderanlagenbau das Kundenprojekt entwickelt.
AOI.RemoteControl -> TCP Client zur Kommunikation mit einem AOI
AOI.Common -> Schnittstellen
AOI.Server.RemoteControl -> Schnittstellen Server zwischen SPS und AOI. Benutzt ua. AOI.RemoteControl / OPC.AOI
AOI.UI.RemoteControl -> Windows Anwendung zum Fernbedienen des AOI. Benutzt ua. AOI.RemoteControl
Mit der folgenden Struktur bin ich aktuell sehr zufrieden.
Eine spezifische Kundenanwendung lässt sich schnell umsetzen durch das hinzufügen der entsprechenden Bibliotheken. Über die DI werden die Interfaces (*.Common) entsprechend zugewiesen. Sei es nun eine Server oder Clientanwendung.
Als nächsten Schritt würde ich die *.RemoteControl Klassen in ein eigenes Projekt auslagern wollen.
Remote.Common -> Beinhaltet Interfaces für FooApp, AOI usw.
Remote.TCP -> Basis TCP Client
Remote.Serial -> Basis SerialCommunication Client
Remote.AOI -> AOI Client / Server
Remote.FooApp -> FooApp Client / Server
In dem FooApp und dem AOI Projekt müsste ich nur noch die entsprechende Remote.##AppName## Bibliothek einbinden, passendes Protokoll TCP / Serial oder beides hinzufügen und hätte in allen Anwendung den selben Client / Server.
Dabei stellt sich nun die Frage ob es nicht sinnvoller ist, die "Teilprojekte" in die Suite zu packen, da dort in der Regel die komplette Logik vollzogen wird und Debuggen dadurch erheblich einfacher wäre. Konkret meine ich, folgende Projekte
OPC.Alarms
OPC.Leitsystem
werden in das Suite Projekt verschoben:
Suite.OPC -> Beinhaltet OPC.Local bzw. die komplette Logik aus ehemals OPC.Alarms / OPC.Leitsystem
Dadurch würde bei einer Anpassung unseres Suite Projektes (bzw. deren Interfaces) kein erneutes Anpassen der OPC Bibliothek erforderlich. Wenn sich jedoch etwas grundlegendes an der OPC Kommunikation ändert, so müsste man das OPC Projekt aktualisieren und (ggfs.) nur im Kundenprojekt auf die letzte OPC Version gehen.
Dies würde natürlich ebenso für den AOI Teil und dann auch die noch nicht implementierte Remote.* Bibliothek erfolgen.
Ich hoffe mein Problem kann der eine oder andere nachvollziehen und mir einen guten Rat geben wohin ich mit meiner Reise gehen soll bzw. wie man bei so einem Fall am besten seine Projekte aufteilt.
Vielen Dank Vorab!
Gruß
Dominic
Habe eine Erläuterung gefunden: https://thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
The message is rather cryptic, but the meaning is actually quite simple: WPF doesn’t know which FrameworkElement to use to get the DataContext, because the column doesn’t belong to the visual or logical tree of the DataGrid.
Ich glaube,
> wäre hier die einfachste Möglichkeit.
Das habe ich bereits getestet gehabt.
Thread kann geschlossen werden
Hallo zusammen,
Ich habe ein Control (ZlsUnitBrowserActive) mit zwei DependencyProperties MaxWidthIdentifier/PropertiesDataTemplate. Wenn ich versuche die beiden properties über "RelativeSource" anzubinden, bekomme ich immer folgende Fehlermeldung:
Fehlermeldung:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='PlcFramework.Zls.Production.ProductionControls.ZlsUnitBrowserActive', AncestorLevel='1''. BindingExpression:Path=PropertiesDataTemplate; DataItem=null; target element is 'DataGridTemplateColumn' (HashCode=30225241); target property is 'CellTemplate' (type 'DataTemplate')
<Style TargetType="productionControls:ZlsUnitBrowserActive">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="productionControls:ZlsUnitBrowserActive">
<DataGrid>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate
MaxWidth="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=productionControls:ZlsUnitBrowserActive}, Path=MaxWidthIdentifier}"
CellTemplate="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=productionControls:ZlsUnitBrowserActive}, Path=PropertiesDataTemplate}"/>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Nun habe ich bereits die Lösung hier gefunden: https://www.mycsharp.de/wbb2/thread.php?postid=3787237
<Style TargetType="productionControls:ZlsUnitBrowserActive">
<Style.Setters>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="productionControls:ZlsUnitBrowserActive">
<DataGrid>
<DataGrid.Resources>
<xamlHelper:BindingProxy x:Key="DataContextBindingProxy" Data="{Binding RelativeSource={RelativeSource TemplatedParent}}"/>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate
MaxWidth="{Binding Path=Data.MaxWidthIdentifier, Source={StaticResource DataContextBindingProxy}}"
CellTemplate="{Binding Path=Data.MaxWidthIdentifier, Source={StaticResource PropertiesDataTemplate}"/>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Kann mir bitte einer eine Erklärung geben warum ich das ganze so lösen muss oder gibt es vielleicht noch eine bessere bzw. elegantere Lösung?
Danke!
Habe meinen Post editiert..
Hallo zusammen,
ich habe das Problem das seit Neustem meine "MarkupExtensions" nicht mehr in VisualStudio sauber funktionieren. Dabei erhalte ich immer folgenden Fehler:
Fehlermeldung:
ArgumentException: "ThemeExtension" ist für "Setter.Value" nicht gültig. Unterstützt werden nur die MarkupExtension-Typen "DynamicResourceExtension" und "BindingBase" oder abgeleitete Typen.
bei System.Windows.Setter.Seal()
bei System.Windows.SetterBaseCollection.Seal()
bei System.Windows.Style.Seal()
bei System.Windows.StyleHelper.UpdateStyleCache(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle, Style& styleCache)
bei System.Windows.FrameworkElement.OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
bei System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
bei System.Windows.Controls.TextBox.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
bei System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
bei System.Windows.FrameworkElement.UpdateStyleProperty()
bei System.Windows.FrameworkElement.OnInitialized(EventArgs e)
bei System.Windows.FrameworkElement.TryFireInitialized()
bei System.Windows.FrameworkElement.EndInit()
bei MS.Internal.Xaml.Runtime.ClrObjectRuntime.InitializationGuard(XamlType xamlType, Object obj, Boolean begin)
Dies hat nun seid gut 6 Wochen ohne Probleme funktioniert und von heute auf Morgen spackt mein VS rum und ich kann nicht mehr arbeiten. Auch Blend schafft es nicht. Sobald ich den Code ausführe läuft das alles wie es soll. Ändere ich ein Zeichen in meinem XAML Code wird dieser auch fehlerfrei angezeigt und sauber kompilliert (design time).
Ich habe dazu bereits auf SO einen Post erstellt, ebenso beim Bug Tracker von VSCommunity:
Mehr Details befindet sich im SO Post. Sollte es erwünscht sein, werde ich diesen hier nochmals komplett schreiben.
Ich habe im Internet ein Beispielprojekt gefunden. Bei diesem tritt genau das selbe Phänomen auf!:
Ist das Problem bereits bei einem von euch aufgetreten?
Danke schonmal!
ThemeExtension.cs
[MarkupExtensionReturnType(typeof(Color))]
public class ThemeColorExtension : ThemeExtension
{
internal override object ModifyThemeValue(object value)
{
if (value is SolidColorBrush solidColorBrush)
return solidColorBrush.Color;
return value;
}
}
[MarkupExtensionReturnType(typeof(SolidColorBrush))]
public class ThemeExtension : MarkupExtension
{
// ##############################################################################################################################
// Properties
// ##############################################################################################################################
#region Properties
// ##########################################################################################
// Public Properties
// ##########################################################################################
/// <summary>
/// The Key in the Resource Theme file
/// </summary>
public string Key { get; set; }
// ##########################################################################################
// Private Properties
// ##########################################################################################
private static readonly List<ThemeExtension> _Cache = new List<ThemeExtension>();
private static readonly ResourceDictionary _DefaultTheme;
private static ResourceDictionary _CurrentTheme;
private PropertyInfo _Property { get; set; }
private DependencyProperty _DependencyProperty { get; set; }
private WeakReference _TargetReference { get; set; }
#endregion
// ##############################################################################################################################
// Constructor
// ##############################################################################################################################
#region Constructor
static ThemeExtension()
{
_DefaultTheme = new ResourceDictionary
{
Source = new Uri("/HtPlcFramework;component/Themes/DefaultTheme.xaml", UriKind.Relative)
};
_CurrentTheme = _DefaultTheme;
NavigationService.Navigated += _OnNavigated;
}
public ThemeExtension() { }
#endregion
// ##############################################################################################################################
// public methods
// ##############################################################################################################################
#region public methods
/// <summary>
/// https://social.msdn.microsoft.com/Forums/vstudio/en-US/931d7bff-90b6-4a70-bb0b-3a097e1301a1/net-40-breaking-change-using-a-markup-extension-as-value-of-property-setter-in-xaml-style?forum=wpf
/// </summary>
/// <param name="serviceProvider"></param>
/// <returns></returns>
public override object ProvideValue(IServiceProvider serviceProvider)
{
IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (target == null)
return this;
if (target.TargetObject != null && target.TargetProperty != null)
{
_TargetReference = new WeakReference(target.TargetObject);
if (target.TargetProperty.GetType() == typeof(PropertyInfo))
{
_Property = (PropertyInfo)target.TargetProperty;
}
else if (target.TargetProperty is DependencyProperty)
{
_DependencyProperty = (DependencyProperty)target.TargetProperty;
}
}
if (!_Cache.Contains(this))
_Cache.Add(this);
return ModifyThemeValue(_ReadThemeKey(Key));
}
/// <summary>
/// Change the Theme set
/// </summary>
/// <param name="themeUri">Default is: new Uri("/HtPlcFramework;component/Themes/DefaultTheme.xaml", UriKind.Relative)</param>
public static void ChangeTheme(Uri themeUri)
{
_CurrentTheme = new ResourceDictionary { Source = themeUri };
foreach (ThemeExtension reference in _Cache)
{
reference._UpdateTheme();
}
}
/// <summary>
/// Get the current theme entry. Can be null!
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public static object ReadThemeKey(string key) => _ReadThemeKey(key);
internal virtual object ModifyThemeValue(object value)
{
return value;
}
#endregion
// ##############################################################################################################################
// private methods
// ##############################################################################################################################
#region private methods
private static void _OnNavigated(object sender, string layer)
{
_Cache.RemoveAll(ti => !ti._TargetReference.IsAlive);
}
private static object _ReadThemeKey(string key)
{
try
{
return _CurrentTheme[key] ?? _DefaultTheme[key];
}
catch (Exception)
{
Trace.WriteLine($"The key '{key}' was not found in {_CurrentTheme.Source}!");
return null;
}
}
private void _UpdateTheme()
{
if (_TargetReference.IsAlive)
{
if (_Property != null)
_Property.GetSetMethod().Invoke(_TargetReference.Target, new object[] { _ReadThemeKey(Key) });
else if (_DependencyProperty != null)
{
DependencyObject dependencyObject = _TargetReference.Target as DependencyObject;
dependencyObject?.SetValue(_DependencyProperty, _ReadThemeKey(Key));
}
}
else
{
_Cache.Remove(this);
}
}
#endregion
}
Auch wenn dieser Thread schon sehr alt ist..
Wenn es hierführ mittlerweile eine Lösung gibt, ich wäre auch daran interessiert!
Danke!
HTTPS? Muss im Fiddler extra aktiviert werden.
Ja das hatte ich gemacht, sonst wird mir auch die RestSharp Kommunikation nicht angezeigt. Dennoch wird mir die Kommunikation mit der Chilkat Bibliothek überhaupt nicht angezeigt.
Thread kann geschlossen werden!
Ich bedanke mich nochmal für eure Hilfe, dank Fiddler bin ich auf die Lösung gekommen.
Das Problem war das "/" am Ende:
Falsch
RestRequest request = new RestRequest("Orders/2013-09-01/", Method.POST);
Richtig
RestRequest request = new RestRequest("Orders/2013-09-01", Method.POST);
Falls jemand dennoch die Lösung weis, warum die externe Bibliothek nicht von Fiddler geloggt wird, bin ich gerne offen.
Gruß
d.jonas
Danke für eure Hilfe! Ich wollte gerade die beiden Requests miteinander vergleichen, jedoch wird der Traffic der "Chilkat" Bibliothek nicht aufgezeichnet, bei RestSharp geht das ohne Probleme. Gibt es hier spezielle Einstellungen vorzunehmen?
Folgendes habe ich schon probiert: http://docs.telerik.com/fiddler/Configure-Fiddler/Tasks/ConfigureDotNETApp Leider ohne Erfolg.
GlobalProxySelection.Select = new WebProxy("127.0.0.1", 8888);
<configuration>
<system.net>
<defaultProxy>
<proxy bypassonlocal="false" usesystemdefault="true" />
</defaultProxy>
</system.net>
</configuration>
Ich habe soeben mal diese Bibliothek (Chilkat C# library) getestet und musste feststellen, dass es damit funktioniert. Nun ist die Frage warum es bei mir nicht funktioniert?!
https://www.example-code.com/csharp/mws_list_orders.asp
Da dies mein erstes Projekt mit einer RestAPI ist, steh' ich ein bisschen auf dem Schlauch.
Danke im Voraus!