Laden...

Forenbeiträge von BhaaL Ingesamt 656 Beiträge

14.05.2019 - 12:26 Uhr

Nunja, Tuple ist eine Class, das stimmt - aber gemeint waren Named Tuples (die durch ValueTuple) umgesetzt sind; das ist eine Struct. Das Kapitel in der Doku dazu heißt nur "Tuples", drum hab ichs initial nicht näher ausgeführt (weil sowohl die named als auch die unnamed tuple syntax zu ValueTuple führt)

14.05.2019 - 08:59 Uhr

Statt KeyValuePair bieten sich auch Tuples an, wenn du einen aktuellen Compiler sowie C# Version verwenden kannst:

            var group1 = new OptionGroup("Motor", new []
            {
                (1, "TSI"),
                (2, "TDI")
            });
            var group2 = new OptionGroup("Farbe", new []
            {
                (1, "Weiß"),
                (2, "Schwarz"),
                (3, "Rot")
            });
[...]

    public class OptionGroup
    {
        public string Name {get;set;}

        public IEnumerable<(int ID, string Name)> Options {get; }

        public OptionGroup(string name, IEnumerable<(int ID, string Name)> options)
        {
            Name = name;
            Options = options;
        }
    }

        // Verwendung 1 mit Zugriff über Name:
        static StringBuilder GenerateExportString(KeyValuePair<string, string> prefix, IEnumerable<IEnumerable<(int ID, string Name)>> options)
        {
            var sb = new StringBuilder();
            foreach (var selection in options)
            {
                sb.Append(selection.ID).Append(';').Append(selection.Name);
            }
            return sb;
        }

        // Verwendung 2 mit Deconstruction:
        static StringBuilder GenerateExportString(KeyValuePair<string, string> prefix, IEnumerable<IEnumerable<(int ID, string Name)>> options)
        {
            var sb = new StringBuilder();
            foreach (var (id, name) in options)
            {
                sb.Append(id).Append(';').Append(name);
            }
            return sb;
        }
17.04.2019 - 15:13 Uhr

Jedes cross apply multipliziert deine Zeilen. Das ist mit hoher Wahrscheinlichkeit nicht das, was du willst (also: mehrere cross apply). Schreibs doch einfach vorne beim orga.ref.value dazu, und nicht hinten?

Oder du belässt es so und benutzt STUFF (bzw. wenn du einen SQL Server 2017 oder neuer hast, STRING_AGG).

17.04.2019 - 12:48 Uhr

Dann schreibst du im X-Path einfach marc21:datafield[@tag = '035']

12.04.2019 - 12:11 Uhr

Das Insert brauch ich zum Testen, das brauchst du natürlich nicht. Bei dir muss stattdessen deine Unterabfrage rein, die das XML liefert.

Und irgendwie wundert mich nicht, dass du immer noch NULLs rausbekommst, wenn du im apply auf datafield gehst.
Erst kommt das apply - alles was dort rauskommt, wird ins orga.ref geschrieben; und ausgehend davon kannst du im Select mit .value auf Werte dieses Elements zugreifen.

12.04.2019 - 11:22 Uhr

An sich ist das Forum kein Code-Generator, aber ich will dich irgendwie auch nicht hängen lassen...
Bei mir klappt folgendes:

declare @xml table(xmlData xml not null);
insert into @xml values ('<collection xmlns="http://www.loc.gov/MARC21/slim">
   <record type="Authority">
       <leader>00000nz  a2200000nc 4500</leader>
       <controlfield tag="001">1011387409</controlfield>
       <controlfield tag="003">DE-101</controlfield>
       <controlfield tag="005">20150227101359.0</controlfield>
       <controlfield tag="008">110430n</controlfield>
       <datafield tag="024" ind1="7" ind2=" ">
         <subfield code="a">http://d-nb.info/brd/123</subfield>
         <subfield code="2">uri</subfield>
       </datafield>
       <datafield tag="035" ind1=" " ind2=" ">
         <subfield code="a">(DE-101)105f563</subfield>
       </datafield>
       <datafield tag="035" ind1=" " ind2=" ">
          <subfield code="a">(DE-588)632a452</subfield>
       </datafield>
    </record>
</collection>')



select
	orga.ref.value('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:leader[1]','varchar(255)') leader,
	orga.ref.value('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:controlfield[1]','varchar(255)') controlfield,
	orga.ref.value('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:datafield[1]/@tag','varchar(255)') datafield,
	orga.ref.value('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:datafield[1]/marc21:subfield[1]','varchar(255)') subfield
from @xml xml
outer apply xml.xmlData.nodes('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:collection/marc21:record') orga(ref)

Liefert mir als Ergebnis

leader                      controlfield     datafield     subfield
00000nz  a2200000nc 4500    1011387409       024           http://d-nb.info/brd/123

Hätte mein Beispiel mehrere record Elemente, würden auch mehrere Zeilen rauskommen (das macht der outer apply)

12.04.2019 - 08:35 Uhr

Ein wenig Selbstständigkeit wäre sicher nicht verkehrt; nachdem dein Dokument Namespaces benutzt gilt das natürlich auch hinten für dein outer apply.
Vermutlich wirst du mit dem Ergebnis aber nicht glücklich sein, da wäre ein X-Path Tutorial zu empfehlen.

12.04.2019 - 08:02 Uhr

Ja, das ist ein Namespace Problem (was am gekürzten Snippet leider nicht ersichtlich war).
Sobald du Namespaces benutzt, ist das wie in anderen (Programmier-)Sprachen; du meinst etwas anderes wenn der Namespace anders ist.

Da du einen default Namespace hast, gilt der automatisch für alle Elemente; sofern nicht ein anderer Namespace (über das xmlns Attribut, oder ein Präfix was vorher per xmlns:yourPrefixHere definiert wurde) näher dran angegeben wird.

Vermutlich bräuchtest du sowas:

SELECT

orga.ref.value('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:leader[1]','varchar(255)') leader,
orga.ref.value('declare namespace marc21="http://www.loc.gov/MARC21/slim"; marc21:controlfield[1]','varchar(255)') controlfield,
...
outer apply xml.xmlData.nodes('collection/record') orga(ref)

Der Namespace muss leider in jedes .value rein, weils unabhängige Ausdrücke sind. Dabei ist jedoch egal, wie du den Namespace nennst; solang du ihn später vor das Element schreibst.

11.04.2019 - 14:43 Uhr

Ich rat jetzt einfach mal ins blaue, aber versuch mal beim X-Path hinten das /datafield wegzulassen:

SELECT
...
outer apply xml.xmlData.nodes('collection/record') orga(ref)

Mit .value(...) greifst du nämlich auf das Element zu, was letztendlich aus dem apply rauskommt; und rein namenstechnisch sind die Elemente im <record> zu finden, nicht im <datafield>

04.04.2019 - 13:34 Uhr

Hab mir jetzt erstmal ein eigenes UserControl gemacht, aber leichter wäre es doch irgendwie, wenn ich ein UserControl vom Typ ComboBox hätte wo ich nur das ControlTemplate erweiter, aber die Eigenschaften wie ItemsSource etc. beibehalten werden.

Geht das?

Ich fürchte nein. Das ist leider auch einer der Punkte, der mich an den Templates ein wenig stört (aber nunmal nicht anders geht) - wenn du das ControlTemplate überschreibst, dann überschreibst du alles. Was umgekehrt auch bedeutet, dass du alles dort rein-replizieren musst und nicht einfach nur als Extension Point sagst "füg da drüben zusätzlich was ein".
Spätestens da haben deine eigenen User Controls aber den Vorteil, dass du so etwas eventuell schon weißt und das Control gleich entsprechend drauf vorbereiten kannst (wie zb. mein Vorschlag einer Command Collection anstatt den Button direkt rein zu werfen. Das könnte man theoretisch sogar noch weiter auflösen und ein "Dropdown Footer" Property oder so anbieten, wo standardmäßig die Command Collection drin ist - is halt alles im Template).

04.04.2019 - 09:12 Uhr

Die Billiglösung wäre ein zusätzliches Item in der ItemSource, wo dann einfach ein anderes DataTemplate dranhängt und den Button generiert. Aber das ist irgendwie unhübsch.
Alternativ schreibst du ein eigenes Control und definierst dafür ein Control Template, was wie die Combobox aussieht - nur dass du im Dropdown-Berech zusätzlich noch deinen Button hinzufügst (oder vielleicht sogar mehrere, über ein ItemsControl aus einer DependencyProperty aus deinem Control wo Commands drin sind).

Könnte in etwa so aussehen (das Template für die Combobox kannst du dir per Blend oder Google raussuchen, das wär vermutlich zu lang um hier als Ganzes zu posten):

public class MyComboBox : ComboBox
{
  static MyComboBox()
  {
    // WPF instruieren, dass es standardmäßig einen Style anwenden soll, dessen Key typeof(MyComboBox) ist:
    DefaultStyleKeyProperty.OverrideMetadata(typeof(MyComboBox), new FrameworkPropertyMetadata(typeof(MyComboBox)));
  }
  public static readonly DependencyProperty DropDownCommandsProperty = DependencyProperty.Register(nameof(DropDownCommands), typeof(IEnumerable<ICommand>), typeof(MyComboBox), new PropertyMetadata(null));
  public IEnumerable<ICommand> DropDownCommands
  {
    get => (IEnumerable<ICommand>)GetValue(DropDownCommandsProperty);
    set => SetValue(DropDownCommandsProperty, value);
  }
  // ...möglicherweise mehr Code, je nachdem was du brauchst
}
<Style x:Key="{x:Type local:MyComboBox}" BasedOn="{StaticResource {x:Type ComboBox}}" TargetType="{x:Type local:MyComboBox}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type local:MyComboBox}">
        <!-- der Inhalt von dem Template hier ist eine Kopie des Standardmäßigen ComboBox Template. Einfach von Blend, Google oder sonstwo hier reinkopieren und dann anpassen. -->
        <Grid ...>
          <Popup ...>
            <!--
             Ab hier wirds interessant; normal ist hier ein DropShadowChrome mit Border usw. drin, die du aus Look&Feel Gründen vielleicht auch willst.
             Das StackPanel (oder auch ein Grid, wie du willst) ersetzt das, was "aufklappt"
             -->
            <StackPanel Orientation="Vertical">
              <StackPanel.Resources>
                <!-- dein Button (oder Buttons); hier so Stylen wie dus gerne möchtest. Wird dann unten im ItemsControl genutzt. -->
                <DataTemplate TargetType="ICommand"><Button/><DataTemplate>
              </StackPanel.Resources>
              <ScrollViewer ...> <!-- hier sind deine Items drin --> </ScrollViewer>
              <!-- hier sind sind dann die Buttons (wo du gern auch vorher die Trennlinie etc. einbauen kannst) -->
              <ItemsControl ItemSource="{TemplateBinding DropDownCommands}"/>
   ...</>
25.03.2019 - 08:08 Uhr

Und wenns unbedingt C# sein soll/muss, gäbe es die üblichen Verdächtigen XDocument sowie Xsd.exe

21.02.2019 - 14:18 Uhr

Sieht ein wenig nach UN/EDIFACT aus.
Falls ich damit ins Schwarze treffe, würde ich empfehlen es nicht per Regex zu machen sondern einen (wenn auch minimalistischen) Parser zu schreiben - erstens deshalb, weil die Strings im Normalfall einer gewissen Struktur entsprechen und zweitens weil sowohl das Escape-Zeichen (das Fragezeichen ?) als auch das Komponenten-Trennzeichen (der Doppelpunkt :) über das UNA Segment angepasst/auf andere Zeichen geändert werden können.

19.12.2018 - 14:57 Uhr

Kannst du genauer beschreiben, was du machen möchtest?

Zumindest mir ist nicht klar, ob du eine WpfProjekt.exe aus der WinFormsProjekt.exe starten möchtest (in dem Fall vermutlich: Process.Start) oder ob du innerhalb desselben Prozesses einfach nur WinForms und WPF mischen möchtest (also quasi sowas ähnliches wie new WpfWindow().Show() aus einer WinForms Form heraus)

12.12.2018 - 08:33 Uhr

Du kannst Lazy<T> im wesentlichen auf 3 Arten initialisieren:1.per Standard-Konstruktor 1.per direkter Objekt-Übergabe 1.per Aufruf einer Factory-Methode

Die Nutzung ist immer dieselbe: Zugriff auf das Value Property.

IsValueCreated gibt nur an, ob Value bereits einen Wert hat den es direkt zurück liefern kann, oder diesen erst erzeugen muss (zb. per Standard-Konstruktor oder über die Factory-Methode).

Möchtest du unbedingt etwas machen, bevor das Objekt genutzt wird; und du kannst das nicht direkt im Konstruktor erledigen, dann bietet sich die Factory-Methode an.

Näheres gibts auch in der :rtfm:

02.10.2018 - 07:57 Uhr

Wenn du mehrere Inhalte möchtest, suchst du vermutlich das ItemsControl als Basisklasse/Container (oder eine dessen abgeleiteter Klassen).

28.09.2018 - 12:13 Uhr

.. die unheimlich langsam ist und deswegen kaum einer verwendet 😃

Really? Wäre mir noch nie aufgefallen; und teilweise werf ich da auch umfangreichere JSON aus Jira und Co rein.
Aber schön langsam wirds echt off-topic 😉

28.09.2018 - 07:50 Uhr

...was viele nicht wissen: Es gibt auch im Framework was dafür; nämlich die JsonReaderWriterFactory, die JSON auf XML und umgekehrt mappt.

29.08.2018 - 09:48 Uhr

Ich weiß, dass man ToolStripDropDownItems per ToolStripDropDownItem.ShowDropDown() aufklappen kann...nachdem das ToolStripMenuItem von dem ableitet würde ichs einfach mal ausprobieren (zb. in einem "Item Clicked" EventHandler oder so).

28.08.2018 - 10:02 Uhr

In Java sind das Annotations.

Also zb.

@Deprecated
void YouShouldNotUseThis() { }

Wäre in C# ein

[Obsolete("This method should not be used")]
void YouShouldNotUseThis() { }

(Name ist anders, Obsolete vs. Deprecated; aber die Funktion ist sehr ähnlich)

10.08.2018 - 08:35 Uhr

XML-Attribute sind standardmäßig nicht in Namespaces, wenn man es im jeweiligen XML-Schema nicht explizit als solches deklariert.
Deine beiden XML-Fragmente sind nicht äquivalent, in beiden Fällen müsste es encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" heißen (ohne Namespace!)
Damit sollte hoffentlich auch klar sein, warum sich die beiden Fragmente nicht gleich verhalten.

Wenn der Namespace jedoch erfoderlich ist, musst dus auch beim XmlAttribute dazu schreiben (wie Coffeebean schon gepostet hat) - denn die Namespaces in den Serialisierungs-Attributen vererben sich nicht.

08.08.2018 - 08:38 Uhr

Und vielleicht der Vollständigkeit halber: so ein Cast ist eigentlich undefined behavior, und sollte vermieden werden. Sogesehen werden die gebräuchlichsten Compiler das richtige machen (sofern nix anderes in der Nähe ist, was eventuell optimierbar aussieht), aber sicherer ist ein std::memcpy der jeweiligen Bytes in den gewünschten Zieltyp:

double ergdouble;
std::memcpy(&ergdouble, &file_buf[inhalt], sizeof(double));
// use ergdouble

Stichwörter type-punning, strict-aliasing und undefined behavior

06.08.2018 - 13:01 Uhr

Wir hatten früher auch ein (selber gebasteltes) resx2xls (weil wir nicht wussten, dass es sowas schon gibt; plus ein paar applikationsspezifische Extras wie das Erkennen obsoleter Strings aufgrund des Source Code).
Inzwischen ist das Ganze bei uns aber webbasiert in Weblate - womit die Übersetzung kontinuierlich erfolgen kann (und nicht nur dann, wenn mal ein Entwickler Zeit/Lust hat um das Tool zu starten). Basiert auf Translate Toolkit und kann neben ResX auch noch jede Menge anderer Formate (allen voran das zugrunde liegende PO/POT, aber auch multilinguale Formate wie XLIFF oder monolinguale Formate wie JSON).

Hilft dir vermutlich aber nicht für deine "Slang" Assemblies, sondern nur für die eigenen Ressourcen (weil ResX reingeht und wieder rauskommt; keine Assemblies)

27.07.2018 - 13:16 Uhr

Klingt als ob du einen ContentPresenter oder ein ContentControl möchtest...wenn du jetzt in WPF weiter arbeitest.
Unter WinForms wärs vermutlich einfach ein Panel oder so, was du zur Laufzeit durch ein anderes ersetzt (bzw. dessen enthaltenen Controls).

Und man kann theoretisch WPF Controls unter WinForms und umgekehrt hosten. Die Frage ist eher, ob man das unbedingt tun sollte...

11.07.2018 - 09:48 Uhr

Gibts einen Grund, warum du das XAML nicht einfach per XDocument liest, sondern versuchst es per Regex zu parsen? 😃

Zu Punkt 1: Der Ausschluss vom Zeichen ist ok, zumindest ist es die straight-forward Variante die ich dort (vermutlich) auch nutzen würde.
Als Alternative gäbe es noch den non-greedy modifier ? (bzw. auch das Non-Greedy flag vom Regex selber), was das Verhalten umdreht.
Standardmäßig ist ein Regex "greedy" (aka. es wird versucht, so viel wie möglich zu matchen). Mit dem Fragezeichen hinter dem Quantifier (zb. "(.*?)") dreht man dieses Verhalten um, damit so wenig wie nötig gematcht wird.

Zu Punkt 2: Das Stichwort hier ist "look-around", bzw. je nachdem ob du nach vorne/hinten auf Präsenz/Absenz prüfen willst ein "negative look-ahead" (bzw. in entsprechenden Kombinationen ein "positive look-ahead", "negative look-behind" bzw. "positive look-behind").
In deinem Fall willst du den look-ahead aber vermutlich zwischen dem Gänsefüßchen und dem [^"]* (weil du das Auto ja nicht am Anfang haben möchtest; dein jetziger Regex prüft es am Ende). Also so: "((?!Auto)[^"]*)"

06.07.2018 - 13:51 Uhr

Schon mal das Fusion Log aktiviert und genauer begutachtet?

13.06.2018 - 16:30 Uhr

Uns ist das früher immer im Designer passiert, wenn der AutoScaleMode gesetzt war:

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

Oft in Kombination mit übersetzten Forms, sobald die Sprache geändert wurde.

Haben wir einfach "gelöst" indem wir den AutoScaleMode auf None gesetzt haben; aber das kommt mit dem Nachteil dass das Formular nicht wirklich skaliert wenn man auf unterschiedlichen DPI unterwegs ist.

07.06.2018 - 10:43 Uhr

Wir verwenden für diverse PDF-Manipulationen den PDF Clown, der aber leider recht abandoned aussieht...damals (vor knapp 7 Jahren!) hatten wir von iText PDF rüber gewechselt weil iText API-mäßig recht umständlich war und teilweise nicht wirklich das hergegeben hatte, was wir gebraucht hatten. YMMV.
PDF Sharp gäbe es auch noch, aber mit dem habe ich keine wirkliche Erfahrung.

Hast du für die eigentliche PDF-Erstellung schon etwas? Sonst würde ich das UI einfach mit einem Canvas (zb. WinForms Control/Panel mit OnPaint Überladung oder WPF Canvas) machen und komplett unabhängig vom PDF arbeiten.

06.06.2018 - 10:27 Uhr

Wenn du nur Standardwerte vorgeben möchtest, kannst du diese einfach als AppSetting machen (wenn sie nicht änderbar sein müssen) oder beim UserSetting direkt eintragen (damit ist es einfach ein Standardwert, wenn der User noch keine Settings hat). Gespeichert werden UserSettings aber trotzdem pro User.

Wenn du aber meinst, dass UserA ein Setting ändert und UserB dieses dann beim nächsten Start sehen soll, wirst du vermutlich selber ran müssen - zumindest wüsste ich nix Built-in.
Stichwort SettingsProviderAttribute, das packst du einfach über die Settings-Klasse drüber und schon wird ein anderer Provider benutzt:

[SettingsProvider(typeof(MySettingsProvider))]
public partial class Settings
{
    // ...
}

public sealed class MySettingsProvider : SettingsProvider
{
    // ...
    public override SettingsPropertyValueCollection GetPropertyValues(SettingsContext context, SettingsPropertyCollection collection)
    {
        string settingsPath = "path to custom settings";
        var config = ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { /* ... */ LocalUserConfigFilename = settingsPath }, /* ... */);
        var section = config.GetSection("userSettings/" + context["GroupName"]);
        // use section, return property value collection
    }
}

Hab ich schonmal implementiert um anstelle der Basis-Generierten Folder Names pro Assembly einen Shared Folder zwischen zwei Applikationen (aber gemeinsam genutzter Library) zu erreichen - allerdings trotzdem pro User und nicht User-übergreifend; drum bin ich mir nicht sicher wie es da mit Berechtigungen aussieht.

Und ist leider...recht involved, weil man defacto die Serialisierung selber übernehmen muss (ggf. mit etwas Inspiration aus ClientSettingsStore bzw. LocalFileSettingsProvider).

22.05.2018 - 17:08 Uhr

Das war ja auch nicht die Frage 😃
Wenn du zb. NetTcpBinding oder so drin hast (und keine *HttpBinding) dann ist das natürlich auch keine HTTP-basierte Kommunikation (was WebAPI nunmal hauptsächlich wenn nicht sogar ausschließlich ist).

Kann aber auch sein dass dir das schon so bewusst war; und ich deinen Post einfach falsch interpretiert hatte.

22.05.2018 - 15:35 Uhr

Welche Transports/Encodings ("Bindings") hast du zur Zeit im Einsatz?

Für die clientseitige Nutzung gäbe es dotnet/wcf, aber soweit ich weiß ist davon noch kein wirklicher Server-Teil verfügbar.

04.04.2018 - 16:48 Uhr

Das klingt eigentlich nach einem Duplex Service (wo der Client beim Verbindungsaufbau ein Callback-Interface mitgibt, damit Messages in beide Richtungen laufen können). Braucht halt entsprechende Bindings/Transports, die sowas unterstützen.

Aber wenn du schon schreibst, dass es ein 3rd Party Service ist (woraus ich ableite, dass es nicht von dir ist) wirst du vermutlich an deren Technologie/Gegebenheiten gebunden sein und nicht von dir aus ein netTcpBinding (oder ähnliches) wählen können.
Hast du genauere Infos über das 3rd Party Service, welche Schnittstelle/Bindings/Transports es anbietet (SOAP/REST/POX/JSON/MTOM um ein paar Schlagwörter zu nennen; oder auch net.tcp/http/https/tcp/udp/msmq/named pipes die ggf. in beliebiger Kombination auftreten könnten)?

07.12.2017 - 11:34 Uhr

Der Pfad sieht nämlich ungewöhnlich aus.

Wenn ich mich recht entsinne ist das aber der Pfad auf dem Microsoft Buildserver (oder whatever), der in den Framework-PDBs mit drin ist...

28.11.2017 - 15:02 Uhr

Da steht auch nicht mehr drin, zumindest nichts, womit ich groß was anfangen kann: [...]

Nur um hier noch kurz einzuhaken; üblicherweise finden sich in dem Fall drei (oder zumindest zwei) Einträge im Event Viewer unter "Windows Logs" > "Application": Eins von "Windows Error Reporting" (was du hier gepostet hast, was leider auch sinnlos ist; und üblicherweise auch nur das Level "Information" hat), eins von "Application Error" (mit Level "Error" wo zumindest der Pfad zur Datei stehen sollte) und bei .NET Programme von ".NET Runtime" (auch "Error") wo dann oft ein Stacktrace drinsteht. Letzterer ist der interessante (sofern es sie gibt).

23.11.2017 - 09:00 Uhr

Kein Problem. Geht mir übrigens auch so; ich bin immer etwas skeptisch wenn jemand sagt "Nimm A statt B" ohne zu begründen warum.

Microsoft hat da auch eine recht schöne Tabelle gebastelt, wo man die beiden high-level gegenübergestellt bekommt:
WCF and ASP.NET Web API
(wo aber leider die angesprochene Lernkurve auch nicht explizit drinsteht)

Hilft vielleicht auch bei der Suche nach der geeigneten Technologie.

23.11.2017 - 07:56 Uhr

Geht die Frage genauer?

Ich versuchs mal: Warum "Klar die (Web)API" wenn man zwischen .NET und .NET kommunizieren möchte? Da bietet sich doch WCF mit net.tcp Binding an, wenn man keine Interopabilität braucht. Oder vielleicht msmq wenn man wirklich immer sicherstellen möchte, dass die Anfragen zur Aufgaben-Durchführung beim Service landen (auch wenns mal kurz offline ist). Oder...oder...oder.
Service-Referenz hinzufügen, Client erzeugen und Methode aufrufen; reicht fürs erste um die Füße Nass zu bekommen.
Wenn das Ziel klar Web ist (bzw. auch HTML/JS Clients und nicht WinForms), gehts zwar auch mit WCF; aber spätestens dann würde ich auch eher zur WebAPI greifen.
Ich muss an der Stelle auch zugeben, dass ich hauptsächlich mit WCF zu tun habe, weils 1. die WebAPI damals noch nicht gab und 2. aufgrund der Fachanforderungen net.tcp der geeignetste Transport ist. Web ist in meinen Applikationen kaum ein Thema, abgesehen von gelegentlichen "ich möchts aber von meinem $Tool aus ansprechen" - wofür es dann halt einen REST Endpoint mit webHttp Binding und JSON Serializer gibt, der ausgewählte Methoden anbietet.

04.09.2017 - 07:57 Uhr

Passiert das zufällig (erst) seit dem Upgrade auf 15.3? Und möglicherweise noch in einer etwas größeren bzw. kompleteren Solution? Werf bitte mal einen Blick auf https://developercommunity.visualstudio.com/content/problem/95826/vs2017-153-outofmemoryexception.html

12.07.2017 - 15:33 Uhr

Kannst Du mir das bitte mal genauer erklären ?

Im zweiten Visual Studio auf Debug > Attach to Process und dort das erste Visual Studio auswählen; dann im ersten Visual Studio dein Copy&Paste durchführen.
Ab hier ist's dann dasselbe als ob du dein eigenes Programm debuggst.

Einziger Unterschied: liegt der Fehler nicht in deinem eigenen Code, kann es sein dass der Debugger nicht stehen bleibt - daher ggf. "Enable Just My Code" deaktivieren damit du auch Exceptions ohne Source bekommst.
Und für die Nummer Sicher noch aktivieren, dass der Debugger auch bei handled Exceptions stehen bleibt.

12.07.2017 - 15:22 Uhr

Ohne weiteres Infos ist es hier recht schwierig, dir genauere Hinweise zu geben. Pauschal hätte ich mal gesagt, dass in der Basisklasse irgendwo im Konstruktor oder in überschriebenen Events (zb OnPaint) die NullRef triggert, weil im Designer nicht notwendigerweise alles initialisiert ist.

Aber du könntest mal versuchen, ein zweites Visual Studio zu starten und dich ans erste dran zu hängen. Wenns in deinem eigenen Code kracht, solltest du das damit auch rausbekommen. Eventuell vorher unter Tools > Options, Debugging den Haken bei "Enable Just my Code" weg.

12.01.2017 - 13:17 Uhr

Üblicherweise benutzt man für das Backing-Field auch ein Field, keine andere Property. Bei dir sind beides Properties - name ist ein automatic Property und Name ein per Hand implementiertes.

21.12.2016 - 13:33 Uhr

Strings sind immutable. Replace gibt den geänderten String zurück, den du aktuell ignorierst.

20.12.2016 - 14:26 Uhr

Alternativ: Schonmal über den XmlDataProvider nachgedacht? Wenns wirklich nur ums 1:1 anzeigen geht, reicht das vollkommen.

Edit: ach, Aufgabenstellung missverstanden, sorry 😕

06.12.2016 - 07:50 Uhr

Schon richtig, aber das ist eben nicht testbar, da es nicht austauschbar ist.

Der IServiceLocator ist aber generisch und es gibt Implementierungen für fast jeden Container

So ganz versteh ich dich da jetzt aber leider nicht...der Unterschied bei Windsor ist es, dass ich statt einem hol-dir-was-du-willst IServiceLocator spezifisch eine IOutputWriterFactory als Ctor-Parameter möchte, die unmissverständlich aussagt "ich brauch einen Output Writer, von irgendwo, durch irgendjemanden bereit gestellt". Und ich persönlich finde das testbarer als ein zb. Interface mit einer Get<T> Methode, die potenziell erst recht wieder alles machen könnte, was man sich vorstellen und nicht vorstellen kann.

Das einzige wo ich dir da (mehr oder weniger) zustimme ist die Namensgebung, weil das Ding ja theoretisch auch Singletons zurückgeben kann und damit nicht notwendigerweise eine Factory darstellt (die traditionell immer neue Objekte liefert)...aber man muss das Interface ja nicht I...Factory nennen, nur weil die Facility TypedFactory heißt.

05.12.2016 - 12:50 Uhr

Aber es gibt ja Microsoft.Practices.ServiceLocation, mit dem Interface IServiceLocator.
Das muss halt jeder injected bekommen der andere Klassen dynamisch erzeugen muss.

Vielleicht der Vollständigkeit halber, Windsor bietet sowas auch an - dort läuft das Ganze aber bevorzugt über den Begriff Factory (bzw. über TypedFactory, wo Windsor automatisch eine Service Locator-ähnliche Implementierung per Proxy generiert) - ansonsten selbes Prinzip, irgendwas reingeben, was die Abhängigkeit auflösen kann.

05.12.2016 - 08:19 Uhr

Service Locator kann gefährlich sein, weil er recht einfach schlampigen Code erlaubt (du brauchst eine Instanz von IFoo? Frag den Service Locator, wurscht wo du grade bist) - drum ist er auch einer meiner Lieblings-Anti-Patterns, weil ich bisher nur schlechte Erfahrungen damit gemacht habe.
Solang du dir sowas aber im Hinterkopf behältst und nicht am Software Design vorbei arbeitest (nur weil dus damit kannst), sollte es auch kein Problem sein.

Der Service Locator Teil in dem Windsor Beispiel ist exakt an einer Stelle, weil zumindest irgendwo ein Service Locator Aufruf drin sein muss - üblicherweise ist das direkt in Program.Main für dein Haupt- oder Root-Objekt, von dem aus alles seinen Lauf nimmt (üblicherweise die Applikation, das Service oder wie auch immer es bei deiner Applikation auch grade aussieht).
Das kann auch eine Klasse sein, in der Praxis macht man aber halt üblicherweise Interfaces draus, wenn es sinnvoll und zweckmäßig ist (aus den von Abt genannten Gründen).

An anderen Stellen (zb. wenn deine Applikation einen IOutputWriter braucht) übernimmt der IoC Container die Arbeit für dich und versucht, die passende Komponente dafür zu finden (er macht den Service Locator indirekt) - ohne dass du irgendwo ein GottKlasse.GibMir<IOutputWriter>() oder ähnliches schreiben musst.
Alles was du selber dazu tun musst, ist ihm bekannt zu geben, welche Abhängigkeiten du haben willst - und das wurde schon zu Genüge über Konstruktoren usw. in früheren Posts hier drin angesprochen.

01.12.2016 - 09:54 Uhr

Damit du in WPF ein Binding draufsetzen kannst - ja, dazu brauchst du ein DependencyProperty.
Wenn du nur statische String-Werte nutzt, kannst du vielleicht sogar ein normales Property machen; aber das müsste man einfach ausprobieren.

01.12.2016 - 08:54 Uhr

In der Form (XAML-Namespace plus "Property"?) kenne ich das eigentlich nicht, sondern nur über statische Properties (Klasse Punkt Property, mit optionalem XAML-Namespace). Und das ist keine wirkliche Magic, sondern nur ein stinknormales Dependency Property.

Ansehen kann man das unter anderem in der WPF Localization Extension (Beispielnutzung hier)

18.11.2016 - 08:02 Uhr

Die beiden gehen meist Hand-in-Hand, weil das holen einer Abhängigkeit per Konstruktor oder Property (Dependency Injection, weil man die Abhängigkeit nicht selbst innerhalb per new erzeugt, sondern von außen herein bekommt) gleichzeitig auch bedeutet, dass man nicht mehr selbst die Kontrolle drüber hat, was man da tatsächlich bekommt (Inversion of Control, der Aufrufende entscheidet, ob mein IDocumentRepository ein Fake im Unit-Test, ein Dateibasiertes FS-Repository oder ein Datenbankbasiertes DB-Repository in Production ist).

Oft werden dazu Libraries verwendet (zb. Castle Windsor, TinyIoC, Microsoft Unity und noch viele mehr), aber man kann natürlich auch per Hand rand - und dann passiert genau das, was du grade ansprichst: du musst an einer Stelle (im Zweifelsfall ganz oben, also in Program.Main oder so) alles erzeugen und bis ganz unten runtergeben - oder zumindest irgendwo zwischenspeichern, bis du die jeweiligen Instanzen brauchst).
Hält dich natürlich nicht davon ab, es per Hand zu machen - wie es oft in Unit-Tests uä. gemacht wird (weil nur ein kleiner Teil des Gesamtsystems geprüft werden soll).

Ob deine Dependencies dann Interfaces, abstrakte Klassen oder einfach nur Klassen mit ggf. unterschiedlichen Property-Werten/Konfigurationen sind, hängt von der Komplexität, Flexibilität und Notwendigkeit bei deiner jeweiligen Implementierung ab; und musst du fallweise entscheiden - oder zb. per Schema-F sagen, dass du zwecks Flexibilität immer auf Interfaces setzt.

Kleines Beispiel:

class LineBasedProcessor
{
    public void ProcessLines(string[] lines)
    {
        Console.WriteLine($"Processing {lines.Length} lines");
    }
}

Hier hast du eine fixe Abhängigkeit zu Console, und du bist darauf limitiert nur auf die Konsole zu schreiben.

class LineBasedProcessor
{
    public void ProcessLines(IOutputWriter writer, string[] lines)
    {
        writer.WriteLine($"Processing {lines.Length} lines");
    }
}

Jetzt schreibst du immer noch, aber es ist außerhalb deiner Kontrolle, wo die Ausgabe hingeht - oder ob sie überhaupt irgendwo landet (IoC). Damit hast du jetzt eine Abhängigkeit zu einem IOutputWriter, die von jemand anders bereitgestellt werden muss (DI).

18.05.2016 - 07:48 Uhr

Man muss es nicht übertreiben.){gray}

Stimmt schon, aber wenns einem keiner sagt, kanns passieren dass mans auch nie erfährt 😃
Mir wurde das zb. in der Schule aufs Auge gedrückt, und grade mit dem Beispiel hier ("ich lese den Betrag, ändere ihn, und speichere ihn wieder zurück") kann viel schief gehen, wenn man viel damit macht ("wenn ein zweiter das gleiche macht, stimmt die Summe am Ende nicht"); grade in Richtung Mehrbenutzer und Concurrent Access, was in der Praxis ja nicht so weit weg ist. Andere haben den Luxus nicht, und müssen sich das Wissen mit Hilfe von Foren wie diesem hier erst aneignen.

Und schon mit einer kleinen Änderung im Gedankengang (eine Abfrage die ändert statt zwei) erzielt man einen großen Effekt, der grade am Anfang sicherlich nicht unmittelbar einschätzbar ist. Es gibt immer mehrere Wege zum Ziel, man sollte nur in der Lage sein, sie zu erkennen und den für einen sinnvollsten (nicht notwendigerweise besten, wenn der verbundene Aufwand damit zu hoch wäre) Weg zu wählen.

17.05.2016 - 08:13 Uhr

Und generell wäre davon abzuraten, sowas ohne Transaktion oder ähnlichem zu machen (zb. direkt in der DB per Update Statement mit set Kontostand = Kontostand + @Betrag, Stored Procedure etc.)
Sonst passieren dir eventuell Dirty reads usw. wenn nicht sogar schlimmer - 2 konkurrierende Updates wo am Ende sogar Beträge verloren gehen oder mehr Geld da ist als es am Anfang war.