Laden...

Profil von Mallett

myCSharp.de - Member Mitglied seit

Alle Beiträge

Hallo zusammen,

ich habe aktuell wieder ein Problem, welches ich nicht nachvollziehen kann. Ich nutze InteractionTriggers auch an anderen Stellen und überall funktioniert es bisher, aber hier nicht:


<DataGridTemplateColumn Header="UserState"
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox x:Name="UserStateCombobox" ItemsSource="{Binding Source={StaticResource UserStates}}"                                          
                                          Background="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItem, Converter={StaticResource UserStateToColorConverter}}"
                                          SelectedItem="{Binding UserState}">
                                    <i:Interaction.Triggers>
                                        <i:EventTrigger EventName="DropDownClosed">
                                            <i:InvokeCommandAction Command="{Binding UserStateChangedCommand}" CommandParameter="{Binding ElementName=UserStateCombobox, Path=SelectedItem}" />
                                        </i:EventTrigger>
                                    </i:Interaction.Triggers>
                                </ComboBox>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>                       
                    </DataGridTemplateColumn>

Der EventTrigger wird nie ausgelöst, weder wenn ich als EventName DropDownClosed noch SelectionChanged nehme. Im Intellisense wird mir Beim Binding des Commands das UserStateChangedCommand angeboten, daher gehe ich mal davon aus, dass es nicht daran liegt, dass hier auf den falschen DataContext geschaut wird. Ich vermute eher, dass es hier eine Besonderheit gibt wegen dem <DataTemplate>. Bei anderen Spalten funktionieren alle Bindings, aber keine davon ist eine DataGridTemplateColumn.

Würde mich über eine Erklärung durch die Experten freuen.

Nein, das wars leider nicht 🙁

Hallo zusammen,

ich habe ein Problem mit dem ich nicht weiter komme und hoffe es kann mir jemand helfen.

Ich habe ein Datagrid in meinem XAML mit einem EventTrigger + InvokeCommandAction


<i:EventTrigger EventName="ColumnReordered">
                        <i:InvokeCommandAction
                            Command="{Binding HistoryColumnsReordered}"
                            CommandParameter="{Binding Columns, UpdateSourceTrigger=PropertyChanged, ElementName=historyGrid, Converter={StaticResource DatagridColumnsToDisplayIndicesConverter}}" />
</i:EventTrigger>

Mein Problem ist, wenn ich einen Breakpoint in den DatagridColumnsToDisplayIndicesConverter setze, kommt er dort nur genau einmal hin (und tut auch was er soll), anschließend wird das Command auch mit dem korrekten Parameter aufgerufen.

Wenn ich jetzt manuell im Datagrid eine Spalte verschiebe, wird zwar das Command aufgerufen, aber der übergebene Parameter ist derselbe wie beim ersten Aufruf und der Converter wird nicht mehr durchlaufen.

Kann sich darauf jemand einen Reim machen?

Ich würde erwarten, dass der Converter jedes Mal durchlaufen wird. Und ich frage mich auch, wenn er nicht durchlaufen wird, woher bekommt das Command im Viewmodel den alten Parameter-Wert immer wieder?

Hier noch der Code des Converters, auch wenn der vermutlich keine Rolle für das Problem spielt:


public class DatagridColumnsToDisplayIndicesConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is Collection<DataGridColumn> columns)
            {
                List<Tuple<int, string>> columnIndices = columns.Select(column => new Tuple<int, string>(column.DisplayIndex, (string)column.Header)).ToList();
                System.Diagnostics.Debug.WriteLine("DatagricColumnsToDisplayIndicesConverter " + string.Join(",", columnIndices.Select(x => x.Item1)));
                return columnIndices;
            }

            throw new ArgumentException("Invalid binding parameters for DatagridColumnsToDisplayIndicesConverter, parameter must be a value of type Collection<DatagridColumn>!");
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new Exception("Invalid call - one way only");
        }
    }

Danke schonmal

Hallo zusammen,

ich beiße mir gerade die Zähne aus an einem kleinen Problem. Es geht um einen Handshake mit einer SPS, eine Art Heartbeat sozusagen.

Dazu habe ich einen Task der in einer Schleife while(_heartbeatActive) läuft und regelmäßig das entsprechende Bit von der SPS liest. Regelmäßig heißt dabei so viel wie am Ende steht ein await Task.Delay(50) um nicht die CPU komplett auszulasten. Wenn der Wert true ist schicke ich asynchron eine Notification ab. Der Empfänger wartet dann 500ms und setzt den Wert wieder auf false, die SPS schreibt dann nach 500ms Wartezeit den Wert wieder auf true zurück usw.

Jetzt ist es so, dass das Ganze teilweise stundenlang funktioniert und plötzlich "verliere" ich eine Wertänderung, wodurch ich dann keine Notification mehr erzeuge, niemand mehr den Wert umtoggled und das Ganze dann stehen bleibt.

Nachdem ich jetzt ewig versucht habe, das Problem zu finden, hab ich es durch Logging (kann nicht debuggen auf dem Zielsystem) soweit eingrenzen können, dass im Fehlerfall die Zeile await Task.Delay(50) plötzlich 900ms oder länger braucht.

Über irgendeine Idee, wie das sein kann, würde ich mich freuen.

Danke, werd ich mir mal anschauen. Ich habs zwar in der Zwischenzeit bereits mit einem Itemscontrol umgesetzt, das bindet aber an eine Collection mit Usercontrols zur Zeit. Wäre sicher schöner, wenn ich das mit der verlinkten Lösung hinbekäme.

Hallo zusammen,

ich habe ewig kein WPF mehr benutzt und muss jetzt eine Visualisierung basteln, allerdings bin ich ziemlich eingerostet, was WPF angeht.

Ich habe folgendes Problem:

Der Bediener kann zur Laufzeit über ein Hauptmenü (verknüpft im ViewModel über Commands) GruppenControls hinzufügen und entfernen. So weit so gut:


public class MainViewModel
{
   //...
   private async Task AddNewGroupCommandAction()
   {
       // Vorab wird über Netzwerk an eine Gegenstelle await ... gemacht
       
       // Dann lege ich mein neuen Gruppen-Usercontrol an und speichere es in einer List
       GroupViewModel vm = new GroupViewModel();
       GroupUserControl ctrl = new GroupUserControl(vm);
       
       // intern wird NotifyPropertyChanged etc. ausgeführt
       AddGroupControlToListProperty(ctrl);
   }

   //...
}

Da es maximal 8 Gruppen sein können, habe ich im MainView ein 4x2 Grid als Hauptelement. Ich würde jetzt gerne die GroupUserControls per Binding and meine GroupControlList binden, so dass die einzelnen UserControls in jeweils einer Zelle im Grid angezeigt werden, falls vorhanden. Also Element 0 der List in Zelle 1,1 usw.


<Page x:Class="Vendor.Pages.GroupView"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:local="clr-namespace:Vendor.Pages"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800"
      d:DataContext="{d:DesignInstance Type=local:MainViewModel, IsDesignTimeCreatable=True}"
      Title="GroupView">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
            <ColumnDefinition Width="1*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="1*" />
            <RowDefinition Height="1*" />
        </Grid.RowDefinitions>
    </Grid>
</Page>

Erste Idee wäre jetzt, jeweils ein ContentControl für jede Zelle einzufügen und dann dessen Content an jeweils einen Eintrag in der List zu binden, aber genau da weiß ich nicht, wie ich an ein bestimmtes Element der Liste binden könnte.

Ist der Ansatz an sich falsch, gibt es einen besseren Weg?

Über einen Schubser in die richtige Richtung würde ich mich freuen.
Danke schonmal.

Hallo zusammen,

ich habe ein borderless Fenster, beim MouseEnter wird die Maus an ein Control innerhalb des Fensters gecaptured, beim MouseLeave soll das Capture gelöst werden.

Das funktioniert auch soweit, es sei denn, man bewegt die Maus schnell, bzw. ruckartig aus dem Fenster raus. Dann wird das MouseLeave Event nicht geworfen.

Ich habe diesen alten Thread hier im Forum gefunden:
MouseLeave Event wird nicht zuverlässig ausgelöst

Dort wird dies als allgemeines Problem beschrieben und vorgeschlagen, einen Timer zu verwenden, der regelmäßig prüft, ob die Maus noch über dem Fenster ist.

Ich habe genau das versucht, und dabei in dem Timer.Tick Handler geprüft, ob die Properties IsMouseOver und IsMouseDirectlyOver noch gesetzt sind.

Zu meiner Überraschung ändern sich aber auch die Werte dieser Properties nicht, wenn die Maus ruckartig aus dem Fenster gezogen wird. IsMouseOver bleibt dann permanent auf true, bis ich einmal außerhalb des Fensters klicke.

Daher meine Frage: Worauf könnte ich im Timer.Tick Handler noch prüfen, um festzustellen, dass die Maus nicht mehr über dem Fenster ist? Muss ich wirklich Mauskoordinaten holen und diese mit der Fensterposition vergleichen? Kann doch eigentlich nicht wahr sein, oder?

Danke schonmal.

03.04.2019 - 16:32 Uhr

Hallo witte,

danke erstmal für die Antwort. Ich habs mal ausprobiert, AllowDrop="True" im popup ändert leider nichts. Auch nicht im ContentControl 😦

03.04.2019 - 12:11 Uhr

Hallo zusammen,


<ComboBox
                        x:Name="DropdownSelection"
                        AllowDrop="True"
                        DragOver="DropdownSelection_DragOver"                        
                        DataContext="{Binding ToolBar.ViewModel}"
                        Style="{StaticResource DropdownMenuStyle}">
                        <ComboBox.ItemTemplate>
                            <DataTemplate>
                                <Image
                                    x:Name="item"
                                    Width="48"
                                    Height="48"
                                    AllowDrop="True"
                                    Drop="item_Drop"
                                    HorizontalAlignment="Center"
                                    Source="{Binding ImgIcon}"
                                    Stretch="Uniform" />
                            </DataTemplate>
                        </ComboBox.ItemTemplate>
                    </ComboBox>


<Style x:Key="DropdownMenuStyle" TargetType="ComboBox">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ComboBox">
                            <Grid x:Name="OuterGrid">

                                <WpfControls:IconToggleButton
                                    x:Name="Expand"  
                                    IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
                                
                                <Popup
                                    Name="Popup"
                                    AllowsTransparency="True"                                    
                                    Focusable="False"
                                    IsOpen="{TemplateBinding IsDropDownOpen}"      
                                    Placement="Bottom"
                                    PlacementTarget="{Binding ElementName=OuterGrid}">
                                    <ContentControl                                        
                                        Content="{Binding ViewModel}"    
                                        ContentTemplate="{StaticResource LayoutViewModel}"/>
                                </Popup>
                            </Grid>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

Mein Problem an der Stelle, welches ich mir absolut nicht erklären kann:

  1. DropDownSelection_DragOver -> dieses Event wird ausgelöst, wenn ich ein Objekt über den IconToggleButton ziehe.

  2. Im Handler des Events setze ich IsDropDownOpen der Combobox auf true, d.h. das Popup mit den Images öffnet sich. So weit so gut.

  3. Jetzt würde ich gerne über item_Drop mitbekommen, wenn das gezogene Objekt über einem der Items (Images) gedroppt wird. Das funktioniert aber nicht. Beim Drop über einem Bild wird kein Event ausgelöst.

Hat jemand eine Erklärung dafür?

Danke

Vielleicht würde es helfen, eine Serveranwendung zu entwickeln, die irgendwo am Standort wo die Access-Datei liegt, läuft.

Die Clients verbinden sich dann zu dieser, und nur die Serveranwendung macht Zugriffe auf die Access-Datei und gibt die Ergebnisse an die Clients zurück.

Dadurch würdest Du den Remote-Dateizugriff sparen und hättest dann nur noch den normalen Kommunikations-Traffic zwischen Client und Serveranwendung, der wohl relativ flüssig laufen dürfte, so lange Du keine riesigen Datenmengen aus der Access-Datei übertragen musst.

Letztlich hängt die Verzögerung aber immer in erster Linie davon ab, wie groß die Datenmenge ist, da hilft dann nur eine bessere Leitung oder eine Verkleinerung der Datenmenge. Um Letzteres zu erreichen, könnte Deine Serveranwendung die Daten nach dem Auslesen aus Access ggf. noch in geeigneter Form komprimieren, bevor sie an den RemoteClient weitergeleitet werden.

Ich kann das jetzt nicht weiter ausführen, aber die Lupen nutzen die IPL um medizinische Aufnahmen zu vergrößern. Da komme ich mit Shader-Effekten leider nicht weit.

Das Thema kann aber zu, ich habe es selbst gelöst, indem ich einen ZOrderManager geschrieben habe, bei dem sich alle relevanten Windows registrieren, und der dann dafür sorgt, dass zu jedem Zeitpunkt die korrekten Windows als Topmost markiert werden.

Ich hätte zwar erwartet, dass WPF da einen einfacheren Weg anbietet (im alten C++ Code ist das ein einfaches integer property), aber seis drum, es funktioniert zumindest jetzt wie es soll.

Naja, ein kleines Fenster, welches einen Ausschnitt aus dem darunter liegenden Fenster vergrößert darstellt halt. Eine Lupe halt.

Spielt es eine Rolle, wofür ich es brauche?

Da magst Du Recht haben, die Herangehensweise ist allerdings vorgegeben, da die Anwendung genau das können muss, was eine alte C++ Anwendung auch macht. Es handelt sich dabei um eine Art Bildschirmlupe, wobei sich die zu vergrößernden Ausschnitte auf verschiedenen, sich situationsabhängig überlappenden Windows befinden.

Die Lupenfenster müssen immer über dem Fenster mit den Originaldaten liegen, diese Fenster müssen aber auch immer übereinander liegen.

Ich hab also bspw. ein Fenster mit Originaldaten, darüber x Lupenfenster, darüber ein weiteres Fenster mit Originaldaten, darüber wieder x Lupenfenster usw.

Weitere Anmerkung: Ich kann aus A auch kein Popup von B machen, da es zum Einen auch möglich sein muss, A aus B "heraus" zu bewegen und zum Anderen A auch an anderer Stelle noch benutzt wird.

Hallo,

ich habe zwei Windows, die Topmost=true gesetzt haben, dabei ist es notwendig, dass eines der Windows (Window A) immer vor dem anderen (Window B) liegt und beide Windows vor allen anderen Windows.

Ist es irgendwie möglich, den ersten Teil der Bedingung umzusetzen?
Derzeit ist es halt so, dass Window A hinter Window B rutscht, sobald man in B rein klickt, genau das soll nicht der Fall sein. Es darf aber auch nicht möglich sein, dass weitere Windows z.B. über die Taskleiste vor Window B rutschen, daher kann ich bei B Topmost auch nicht weg nehmen.

@Abt

Die genannte Einstellung befindet sich im Reiter Kompatibilität unter Einstellungen. Insofern denke ich schon, dass es ein Teil der Kompatibilitäts-Einstellungen ist.

Windows 10 ja, .NET Framework 4.7 nein.

Hallo zusammen,

gibt es einen Weg in C# aus dem Code heraus die Kompatibilitätseinstellungen der eigenen Anwendung vorzudefinieren?

Ich würde gerne die Option "Hohe DPI-Einstellungen ändern -> Hohe DPI Skalierung überschreiben" aktivieren und den Wert "Anwendung" setzen.

Ich hab bisher nur Beispiele über Manifest-Datei gefunden, aber diese haben offenbar keinen Einfluss auf die Kompatibilitätseinstellungen meiner .exe

Danke.

Ich habs selbst gefunden: In den Kompatibilitätseinstellungen der .exe auf "hohe DPI-Einstellungen ändern" klicken und dort den Haken bei "hohe DPI-Skalierung überschreiben" und im Dropdown "Anwendung" auswählen.

Wenn ich jetzt noch herausfinde, wie das mittels Code funktioniert, wäre ich happy.

Danke.

Nein, eigentlich will ich nur, dass nicht umskaliert wird, wenn ich mein Fenster von einem Monitor auf den anderen schiebe.

Falls das nicht möglich sein sollte, gibt es evtl. ein Event, welches ich abfangen könnte, wenn Windows mein Fenster massakriert?

Hallo,

ich habe mehrere Monitore, einer hat Skalierung 100%, die anderen 125%
Wenn ich jetzt ein WPF-Fenster, welches sich standardmäßig auf Monitor 2 (125%) öffnet, von Monitor 2 in Richtung Monitor 1 verschiebe, dann wird, sobald das Fenster zu 50% auf Monitor 1 liegt, automatisch die Größe des Fensters angepasst (also auch von dem Teil, der noch auf Monitor 2 liegt).

Kann man das irgendwie verhindern?

Bisher habe ich schon mit System.Windows.Media.DisableDPIAwareness rumgespielt, aber leider ohne Erfolg.

Danke.

19.05.2015 - 14:51 Uhr

Mein Projektleiter stellt sich eine Anwendung vor, deren Oberfläche so generisch ist, dass man sie mit einem Konfigurator mehr oder weniger einfach und schnell aus User-Sicht selbst zusammen stellen kann.

Gib ihm doch den Visual Studio Form Designer, Problem gelöst.

Ich habe eine neue Idee!

Bei einer fixen Kamera könnte man das Bild (ohne Personen) speichern und dann immer das neue Frame mit dem Standbild vergleichen.

Auf Pixel-Ebene kannst Du das aber voll vergessen. Selbst wenn Du zwei Mal hintereinander dieselbe Szene aufnimmst werden die Pixel-Werte niemals alle identisch sein, bei keiner Kamera der Welt.

Der Ansatz, hier Pixel-Werte zu vergleichen, ist einfach grundlegend falsch. Die Vorposter hier haben Dir schon den Tipp gegeben, mit Abstandsverhältnissen zu arbeiten, das ist ein weit besserer Ansatz um mal anzufangen. Einfach wird es sicher nicht, um das Einlesen in die bestehenden Algorithmen wirst Du nicht drum herum kommen.

Vielleicht die falsche Dll für Deinen Kartenleser?

Zitat SCM-Webseite:

Verwenden Sie die Datei c:\windows\system32\CTPCSCCD.dll bei den Kartenlesern Cloud x700 und die Datei c:\windows\system32\CTPCSC31.dll bei den Kartenlesern SCR3xxx

Sind die betreffenden dlls alle registriert?

Vielleicht Marshalling-Probleme zwischen 32bit und 64bit Systemen?

07.05.2015 - 11:29 Uhr

Gibt es in C# (Visual Studio 2013) einen vernünftigen, gangbaren Weg, eine Ableitung eines typisierten Dataset zu erzeugen, so dass ich im abgeleiteten Dataset auch eine Designer-Ansicht hinbekomme?

Danke

Die einzige Schwierigkeit wird wohl sein zu erkennen, wer sich da wieder verbindet. Wie kannst Du zuordnen, dass eine eingehende Verbindung jetzt wieder Client A ist, der vorher die Verbindung verloren hat?

Statt for(;;) würde ich eher sowas wie while(!shutdown) nehmen, dann kannst du den Server auch gezielt beenden indem du das shutdown flag setzt. Ansonsten passts doch. Der ganze Kram in if (mem.Length > 0) geht auch einfacher, wenn Du einen TcpListener / TcpClient und dazu StreamReader/StreamWriter verwendest.

Überleg dir doch erstmal, was Du überhaupt willst. MySql? MS-SQL? Sind zwei verschiedene Dinge. Wenn Du eine MySQL Datenbank ansprechen willst, brauchst Du keinen MS SQL Server (die Express-Version ist frei).

Es ist halt manchmal doch etwas schwieriger als sich mal eben "irgendein Tutorial" anzuschauen, und schwupps, schon kann man mit Datenbanken umgehen. Vielleicht mal an eine Schulung / Fortbildung gedacht?

Jetzt habe ich eine weitere Klasse und dort initialisiere ich eine Instanz von FTP. Dann bekomme ich folgenden Fehler:

Befindet sich diese weitere Klasse im selben Projekt wie die Klasse FTP? Falls nicht, musst Du sicherstellen, dass auch die "externe DLL" vom Projekt der weiteren Klasse aus verfügbar ist.

Leider insgesamt wenig Infos, aber da du von einer externen Dll sprichst - sicher, dass Du sie nicht registrieren musst? (Stichwort: regsvr32)

Hallo STF-DIR

schau Dir mal den System.Windows.Automation namespace an. Das dürfte Dir evtl. weiter helfen.

Hallo B.Maja,

sorry wegen der späten Antwort.

Ich gehe mal davon aus, dass Deine Methode, die die Aktualisierung der Daten vornimmt, in einem Form, Control oder sonstigen GUI-Element definiert ist.

Sowohl Form als auch Control bringen bereits eine Methode "Invoke" mit, du brauchst als keinen MethodInvoker oder sonstigen Schnickschnack.

So wie in Deinem letzten Post beschrieben, ist es eigentlich in Ordnung. Das Delegate könntest Du Dir noch sparen:


public void DataAvailable(object sender, rfidEventArgs fe)
{
   if(InvokeRequired)
       Invoke(new Action<object, rfidEventArgs>(DataAvailable), new object[] {sender, fe});
   else
   {
       //Aufrufe zum Aktualisieren der Daten
   }
}

Du kannst statt Invoke auch BeginInvoke verwenden, falls Du nicht willst, dass Deine Eventroutine ggf. bis zum Ende der Aktualisierung blockiert.

05.03.2015 - 13:46 Uhr

Frage1: Wie kann ich den Stream (egal den IN oder OUT Stream) parsen ? (Stream to byte[] ??)

Mit Streamreader in einen String lesen - klingt doch nach einer guten Idee, wenn Du den String danach parsen willst.

Frage2: Kann ich je nach Datum mehrere Streamwriter in die jew. Datei anlegen/steuern?

Klar kannst Du mehere Streamwriter anlegen. Du kannst ja auch mehrere Integers anlegen... ein Streamwriter pro Datei dürfte aber wohl ausreíchen.

Das Tooltip-Fenster wird sicher irgendein Control sein, dann eben entsprechend ein DataTemplate dafür anlegen...

Definier in Deiner GUI doch eine Methode


UpdateGuiWithNewData(DataContainer xyz)
{
   textBox1.Text = xyz.Wert1;
   label1.BackColor = xyz.Wert2 > 100 ? Color.Red : Color.Green
   ...
}

In der Methode kannst Du doch alle Aktualisierungen an der GUI vornehmen. Dann reicht ein einzelnes Invoke auf diese eine Methode.

Hier ist noch nUnit im Einsatz, wird aber nach und nach alles auf MSTest umgestellt. Persönlich finde ich nUnit angenehmer.

Hast Du mal versucht, den Z-Index noch zusätzlich zu setzen? Stichwort: SetChildIndex

25.02.2015 - 16:25 Uhr

Was ist denn jetzt genau die Frage? Du hast eine Tabelle mit Name- und mehreren Monatsspalten. Und jetzt?

Hallo Lisko,

danke schonmal für den Hinweis auf Raspberry Pi und Arduino Board, das sieht auf den ersten Blick schonmal so aus, als könnte das was sein. Ich werde mal recherchieren, was es da für Möglichkeiten gibt um externe Audiorekorder anzusprechen und Verbindung ins Netz aufbauen zu können.

Hallo zusammen,

bin nicht ganz sicher, ob ich hier mit meinem Anliegen richtig bin, aber ich versuche es mal.
Ich suche eine Möglichkeit, um eine qualitativ hochwertige Audioaufnahme zu starten, sobald ein gewisser Geräuschpegel überschritten wird. Zumindest im ersten Schritt, später wäre es interessant, die Aufnahme zu starten, wenn Töne in bestimmten Frequenzbereichen vorliegen.

Ein simples PC-Mikro mit einer Onboard-Soundkarte wird dafür kaum ausreichen, daher suche ich geeignete Hardware. Optimal stelle ich mir einen digitalen Audiorekorder vor, der entweder direkt oder über einen angeschlossenen PC per Software gesteuert werden kann. Hilfreich wäre es, wenn ich eigene .NET Anwendungen (Compact Framework) darauf zum Laufen bringen könnte. Absolut perfekt wäre das Ganze, wenn das Gerät auch noch per WLAN oder Surfstick nach außen kommunizieren könnte, um bei bestimmten Frequenzbereichen eine Art Alarmmeldung zu versenden.

Klingt vielleicht etwas ungewöhnlich, und man fragt sich vielleicht, was ich damit vorhabe - nur so viel, nichts Illegales. Es handelt sich um ein wissenschaftliches Projekt auf das ich nicht näher eingehen möchte.

Ich habe schon relativ viel im Internet und bei verschiedenen Herstellern gestöbert, bisher aber nichts gefunden, was alle Anforderungen erfüllt.

Falls jemand hier hilfreiche Tipps hat, bitte ich um Wortmeldungen 😃

Danke schonmal.

Bei der TCP-Kommunikation gibt es eigentlich zwei Möglichkeiten. Entweder Du sendest mit Deinem Paket die Länge des Pakets mit. Der Empfänger liest dann erst die Länge aus (4 byte bei einem Int) und weiß dann, wieviele bytes er für das Paket lesen muss.

In dem Fall liest Du dann in einer Schleife und summierst die Bytecounts auf, bis deine gesamte Paketlänge erreicht ist.

Oder Du benutzt ein Trennzeichen zwischen zwei Paketen. Eine sehr simple Möglichkeit wäre, einen StreamWriter zu verwenden, um Deine Daten zu verschicken. Damit kannst Du mit WriteLine Deine Daten in den Stream schreiben und auf der Gegenseite die Daten mit StreamReader.ReadLine auslesen. Das NewLine der Methoden ist dann quasi das Trennzeichen.
Funktioniert natürlich nur, wenn in Deinem Paket keine weiteren NewLines vorkommen, ansonsten musst Du die vorher escapen.

Wie hast Du denn das Objekt aus Deiner Lib auf .NET Seite deklariert? Ist die Interop DLL selbst geschrieben bzw. generiert worden, oder hast Du die fertig vom Anbieter erhalten?

Falls Letzteres der Fall ist, vergleiche mal die Versionen der Interop-Dll mit den Interop-Dlls, die deine funktionierenden *.exe verwenden. Evtl. brauchst Du für Win7 eine andere Version.

Danke für die Info,

aber: laut MSDN sollte NetworkStream.Read blockieren bis die angegebene Anzahl von Bytes gelesen wurde, oder habe ich das falsch verstanden?

Bei mir tut es das nicht.

Der Server (hier ein Messgerät) schreibt einen Block von z.B. 30.000 Bytes mit einem Schreibzugriff. Dieser Block ist in einer bestimmten Art und Weise formatiert, d.h. die ersten 4 Bytes entsprechen einem Int der die Breite eines Bildes angibt usw.

Daher mache ich nun auf meiner Seite mehrere aufeinander folgende Read-Aufrufe.

Problem ist, wenn ich mit dem Debugger durch gehe, funktioniert alles und meine Daten kommen korrekt an. Lasse ich das Ganze ohne Breakpoint laufen, kommt nach kurzer Zeit nur noch Müll an, d.h. es werden Werte gelesen, die nie abgeschickt wurden. Mit einem initialen Sleep vor dem ersten Lesezugriff funktioniert es auch, was mich zu der Vermutung bringt, dass der Client schneller liest, als der Server rein schreibt.

Das passt aber nicht zu der Aussage, dass NetworkStream.Read blockiert. Denn dann müsste der Client, wenn ich mit Read z.B. die nächsten 10.000 Bytes lesen will, auch erst zurück kommen, wenn er die 10.000 Bytes gelesen hat (und demnach der Server diese auch schon geschrieben hat).

Was aber passiert ist, dass ich sofort 10.000 Bytes bekomme, in den ersten 2000 Bytes stehen noch sinnvolle Werte drin, die restlichen 8000 sind Datenmüll aus dem Nirvana.

Daher die Frage: Gibt es eine andere Möglichkeit, den Stream zu lesen, die auch nur das zurück liefert, was rein geschrieben wurde?

Danke...

Der Threadtitel entspricht schon meiner Frage. Es geht darum, dass ich von einem Messgerät über einen TCP Port bestimmte Daten in Form eines ByteArrays bekomme.

Das ByteArray ist nach einem bestimmten Format angeordnet, die ersten 4 Bytes entsprechen einem Integer X, die nächsten 4 Byte einem Integer Y, danach folgt ein DatenArray der Größe X*Y usw.

Als erste Idee würde ich gerne mit einem TcpClient zuhören und über den NetworkStream die einzelnen Teile nacheinander auslesen, also z.B. X mit


byte[] buffer = new byte[4];
stream.Read(buffer, 0, 4);
int sizeX = BitConverter.ToInt32(buffer, 0);

Die Frage wäre jetzt, ob durch den Read-Vorgang der Positionszeiger im Stream um 4 weiter geschoben wird oder nicht. Muss ich beim anschließenden Lesen von Y dann stream.Read(buffer, 0,4) oder stream.Read(buffer,4,4) angeben?

Die MSDN sagt bei der Read-Methode dazu leider nichts.

Ich würde es ja einfach testen, aber leider hab ich das Messgerät hier momentan nicht zur Hand, so dass ich zunächst mal "blind" programmiere.

Danke..

Hallo herbivore,

Da es oft keinen Mehraufwand gibt, muss ich ihn auch nicht rechtfertigen.

Ich habe auch keine Rechtfertigung verlangt, sondern nur darauf hingewiesen, dass es einen Mehraufwand - wohlgemerkt unter WinForms - praktisch immer gibt. Das willst du nicht einsehen, also lassen wir es dabei.

Einige der Gründe, die gegen modale Dialoge sprechen, habe ich in
>
genannt; weitere - zugegeben verstreut - in diesem Thread hier. Mag sein, dass sie dich vielleicht nicht überzeugen, aber genannt habe ich die Gründe alle schon.

Der einzige "Grund" den du dort aufführst, ist die Tatsache, dass Du das Hauptfenster nicht verschieben kannst, während eine Messagebox angezeigt wird. Der Rest sind deine persönlichen Meinungsäußerungen, die man teilen kann aber nicht muss. Zum Thema "Verschieben des Hauptfensters" ist das auch reine Geschmackssache, ob man das nun schlimm findet oder nicht. Das per Definition als Nachteil zu deklarieren ist jedenfalls in der Diskussion unzulässig. Wird z.B. eine Messagebox angezeigt um eine Bestätigung für eine Aktion einzufordern, bevor diese endgültig ausgeführt wird, dann macht es sogar Sinn, dass das Hauptfenster währenddessen nicht verschoben, minimiert oder sonstwas werden kann, damit man als Bediener auch sieht, worauf sich die Bestätigungsabfrage bezieht.

Abstrakt gesprochen verbessert sich die Bedienbarkeit und Benutzerfreundlichkeit deutlich.

Ich akzeptiere Deine Meinung, halte aber meine Meinung dagegen, dass ich es extrem benutzerunfreundlich finde, wenn sich jede Anwendung anders bedienen lässt. Daher ist meine Meinung dazu gegenteilig. Da es in dem Thread aber nicht darum geht, um Meinungsverschiedenheiten zu streiten, nur noch mal der Hinweis, dass sich aus einer persönlichen Vorliebe keine Tatsachenbehauptungen ableiten lassen.

Das würde dann sogar einen erhöhten Aufwand rechtfertigen, wenn es ihn tatsächlich gäbe. Aber je länger ich darüber nachdenke und je mehr Alternativen ich beschreibe, desto mehr komme ich zu dem Ergebnis, dass der Aufwand (sowohl in Codemenge als auch in Komplexität) nicht höher ist.

Wie gesagt, alleine der Testaufwand für eine vom üblichen Standard abweichende Lösung ist automatisch höher. Als Analogon könnte man auch behaupten, es wäre weniger Aufwand, einen eigenen, von Control abgeleiteten Button zu entwickeln und zu verwenden, statt die bereits bestehende Button-Klasse zu benutzen. Die Aussage wäre genau so falsch.

Hallo herbivore,

meiner Meinung nach sind alle von Dir bisher genannten Alternativen, zumindest auf WinForms-Seite mit mehr Aufwand verbunden, als die Einblendung einer Messagebox. Letzteres dauert ca. 10 Sekunden (eine Zeile + anschließende Auswertung des Dialogresult).

Sämtliche sonstigen Vorschläge erfordern immer eine Art von Prüfung, ob eine bestimmte Aktion X ausgeführt werden darf, bzw. ob die Voraussetzungen dafür gegeben sind, was sicherlich mehr Entwicklungsaufwand und vor Allem Testaufwand bedeutet.

Etwas Besser sieht es mMn bei WPF aus, hier kann man über Execute / CanExecute sicher schon Einiges abdecken.

Darüber hinaus konntest Du für mich nicht hinreichend darlegen, warum dieser Mehraufwand gerechtfertigt wäre, bzw. welcher Vorteil sich dabei gegenüber normalen modalen Dialogen / Messageboxes ergäbe. Generell frage ich mich nach wie vor, was an einem modalen Dialog schlecht sein soll. Ich lese das immer wieder, aber eine wirklich schlüssige Begründung hat dafür bisher noch niemand geliefert. Ist dieser Gedanke also mehr ein "Problem intellektueller Programmierer" ohne Bezug zur Praxis? Bitte nicht falsch verstehen, wenn ich das etwas provokant in den Raum stelle, ist nicht persönlich gemeint.

Kann man nicht mit einem der globalen Exceptionhandler die AbortExceptions wegfangen ? Dann würde es zumindest nicht mehr crashen. ThreadAbortException deutet ja normal auch nicht auf einen Fehler hin, sondern ist eine etwas fragwürdige Methode, einen Thread zu beenden. Die fliegt auch meines Wissens nach nicht von selbst, sondern nur durch explizites Aufrufen von Thread.Abort() - Insofern wäre das Wegfangen und Ignorieren doch zumindest nicht falsch?

Der zusätzliche Aufwand für sowas sei mal dahin gestellt, auf jeden Fall höher als ein MessageBox.Show() ... davon aber mal abgesehen, ich fände so einen Dialog sehr verwirrend. Man hat sich mittlerweile an die Standard-Abfrage "Wollen Sie wirklich überschreiben..." gewöhnt. Ich kenne viele Entwickler die hier schon beim Speichern standardmäßig zwei Mal Enter drücken.

Auf jeden Fall ist mir eine standardisierte Lösung lieber, als bei 20 verschiedenen Softwareprodukten jedes Mal eine andere, individuelle Bedienerlogik zu haben, so dass ich mich ständig umgewöhnen muss. Ganz zu schweigen von Bedienern, die nicht viel mit dem PC zu tun haben. Sollen die ständig neue Bedienkonzepte in teuren Schulungen lernen müssen?

Bei großen Auftraggebern ist daher eine "windows-konforme Bedienlogik" häufig sogar vertraglich gefordert.

Ich verstehe ehrlich gesagt die ganze Diskussion nicht wirklich. Was genau soll eigentlich verwerflich sein an modalen Dialogen?

Für mich sind modale Dialoge eine einfache und intuitive Möglichkeit vom Bediener eine Bestätigung, Eingabe, o.Ä. abzufragen, ohne die das Programm nicht weiter arbeiten kann. Klar kann man das auch immer anders lösen, aber warum den Aufwand betreiben, selbst die falsche Ausführung mit eigenem Code zu verriegeln, wenn es dafür ein seit langem bewährtes Standardwerkzeug gibt?

Mir ist nicht ganz klar, unter welchen Umständen die ThreadAbortException geworfen wird.
Fangen kann man sie zwar, aber dann wird sie anschliessend wieder geworfen. Was mit anderen Exceptions, die auch schon aufgetreten sind, nicht der Fall war.

ThreadAbortException wird geworfen, wenn Thread.Abort() aufgerufen wird. Der Thread wird durch die Methode im Prinzip hart, durch Werfen dieser Exception beendet. Besser ist es, einen Thread sauber und kontrolliert zu beenden. Vielleicht arbeitet Deine Komponente intern mit Thread.Abort, dann wirst Du wenig tun können.

Mal blöd gefragt, kannst Du das nicht als normale CSV-Datei interpretieren mit Leerzeichen als Trenner und die leeren Einträge rauswerfen?
Und wie soll er dann Spalte 2 und 5 korrekt zuordnen können?

Na, die Datei hat doch ein festes Format, da ist es doch kein Problem zu wissen, nach wie vielen Einträgen Spalte X aufhört und Spalte X+1 anfängt. Beispiel, erster numerischer Eintrag ist Spalte 1, zweiter numerischer Eintrag ist Spalte 3, alles dazwischen ist Spalte 2 usw.