Laden...
Avatar #avatar-2329.gif
xxxprod myCSharp.de - Experte
Programmierer Österreich\Wien Dabei seit 13.04.2006 1.378 Beiträge
Benutzerbeschreibung

Forenbeiträge von xxxprod Ingesamt 1.378 Beiträge

04.12.2020 - 17:44 Uhr

Mmmh, die Idee war eigentlich, dass automatisch nach der Sensorhardware gesucht wird und nix eingestellt werden muss. Im Fall der o.g. seriellen Ports eine feste Baudrate, etc. und im Falle eines Wechsel auf direkte USB-Kommunikation gibt's wahrscheinlich auch nix einzustellen.

Ich hab mich dabei auf dein Kommentar bezogen:

Von der GUI zur Logikschicht, also bspw. für die Einstellungen der Sensoren, hier bin ich unschlüssig, wie das aussehen soll

Ich hab eine eigene Klasse für den COM-Port definiert. Hier gibt's ein privates Serialport-Objekt, welches bei Instanzierung nach der Hardware sucht. Öffentlich mache ich nur die o.g. Funktionen über das Interface. Meinst du das mit auslagern und kapseln?

Jap genau das meinte ich... nur nochmals wiederholt um die Wichtigkeit hervorzuheben 😃

Das hatte ich vergessen zu erwähnen, ich bin "klassisch" mit WinForms unterwegs. Ich sehe keine Vorzüge in WPF (wobei ich mich mit tieferen Infos dazu auch nicht weiter beschäftigt habe). Da VS wohl keinen Editor dafür hat und man dafür auch noch XML(?) an der Backe hat, um die GUI zu definieren, war das für mich nicht interessant.

Ich habe auch mit WinForms angefangen und sehe seit WPF keinen Grund mehr das Zeugs jemals wieder anzugreifen 😃
Es ist sicherlich eine Umstellung aber man arbeitet sich glaub ich da schnell ein da es mMn. wesentlich intuitiver ist als WinForms.

Ein Qualitätskriterium für mich ist wie testbar Code ist (weswegen ich ständig vom Testen rede) - ich arbeite nicht immer (eher selten) nach TDD-Regeln aber zumindest schau ich dass ich alles soweit entkopple, dass jeder entscheidende Code-Pfad ohne Nebeneffekte getestet werden kann. Das begingt wie schon mehrmals erwähnt beim Auslagern von Code in eigene Klassen, weiter noch die Abhängigkeiten der Klassen untereinander durch Interfaces definieren, sodass am Ende jede Klasse beispielsweise nur mit "Fake-Instanzen" getestet werden kann.

04.12.2020 - 12:09 Uhr

Hallo Locutus,

das ist schon mal ein guter Ansatz den du da vorgeschlagen hast und einiges bei der Implementierung ist mMn. wirklich Geschmackssache und solche Vorgehensmodelle sollen dabei helfen die Komplexität zu reduzieren sowie Test- und Wartbarkeit verbessern.

Ich würde auch so Anfangen die externen Resourcen zu kapseln. Die verschiedenen Hardware-Schnittstellen zB. durch ein gemeinsames Interface kann für gewisse Consumer im Code Sinn machen um einheitlich mit den Schnittstellen zu kommunizieren aber speziell die Konfiguration der unterschiedlichen Hardware-Schnittstellen wird sich mit einem allgemeinem Interace nicht abbilden lassen und somit wird man vermutlich Richtung GUI konkretere Interfaces pro Hardware-Schnittstelle brauchen.

Mal abgesehen von den Interfaces die man dafür definiert, der Zugriff sollte ausgelagert und gekapselt sein, was das Testen dieser Schnittstellen erst ermöglicht.

Eine Logik-Klasse kann wahlweise entweder alle Schnittstellen kennen und bedienen oder noch einmal separat pro Schnittstelle existieren - und vlt. noch eine Logik-Klasse darüber haben die diese wieder vereint... Auch wieder aus dem selben Aspekt der Test-und Wartbarkeit. Wenn die Logik sich pro Hardware-Schnittstelle gravierend unterscheidet würd ich teilen, ansonsten reichts wsl. in einer.

Die Logic-Klasse kann wie du vorgeschlagen hast per Calls und Events mit den Hardware-Schnittstellen-Klassen kommunizieren und selbst seine Zugriffe auch wieder durch Funktionen und Events öffentlich machen.

Richtung GUI (angenommen du verwendest WPF) hast du dann ein ViewModel pro View die du darstellen willst, welche die notwendigen Properties (für die View) im Sinne von MVVM an die Gui-Elemente bindet. Die ViewModels sind dann für die Interaktion mit den Logics verantwortlich.

Dein Beispiel mit GetPorts(): Das ViewModel ruft zB. bei der Initialisierung (oder auf Abruf per ICommand von der View getriggert) die Funktion der Logic.GetPorts() auf und setzt das Result einem "Port[] Ports{get;set;}" Property, welches durch INotifyPropertyChanged die GUI benachrichtig, dass diese sich aktualisieren und neue Werte darstellen soll.
Das ViewModel hat quasi die Aufgabe, die Logics für die View besser konsumierbar zu machen.

Auch in den Views und ViewModels: Wenn du die Hardware-Schnittstellen per View Konfigurieren willst, brauchst du wsl. spezifische Views pro Hardware-Schnittstelle (da wsl. unterschiedliche Parameter konfiguriert werden) und dazu spezifische ViewModels, welche diese dann den Logics order Hardware-Schnittstellen-Klassen weiterleiten können.

Also zusammengefasst schaut dein Ansatz unterhalb der GUI schon ordentlich aus und Richtung GUI schau dir [Artikel] MVVM und DataBinding an und auch den WPF Example Code von OxyPlot an.

Da du durch das Auslagern des Codes in verschiedene Komponenten wsl. viele Klassen inkl. Interfaces erzeugen wirst empfiehlt sich Dependency Injection einzusetzen um die Abhängigkeiten zu reduzieren, das Kompositionieren der Services zu vereinfachen und vor allem um den Code testbarer zu machen.

LG, XXX

27.11.2020 - 12:39 Uhr

Hallo Mattes80,

DataContext kann nur ein Objekt zugewiesen werden. Normalerweise hat das Fenster ein MainViewModel, und die einzelnen Unterbereiche im Fenster dann spezielle Unter-ViewModels, welche als Eigenschaften im MainViewModel liegen. Das kann beliebig verschachtelt werden.

Nach dem Schema würde ich auch vorgehen und du könntest es dann zB so schachteln:

MainViewModel
-> SprachViewModel
-> DatenbankViewModel
-> FunktionsViewModel

Die Struktur kannst du auch in Form von verschachtelten Views wiederspiegeln und zB eine ähnliche Struktur in den Views anlegen:

MainView
-> SprachView
-> DatenbankView
-> FunktionsView

Das Hauptfenster bekommt als DataContext dann das MainViewModel und alles weitere ergibt sich rein aus den Bindings:


<Window x:Class="WpfApp1.MainWindow"
        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"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.DataContext>
        <local:MainViewModel></local:MainViewModel>
    </Window.DataContext>

	<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <local:SprachView Grid.Column="0" DataContext="{Binding Path=SprachViewModel}"></local:SprachView>
        <local:DatenbankView Grid.Column="1" DataContext="{Binding Path=DatenbankViewModel}"></local:DatenbankView>
        <local:FunktionsView Grid.Column="2" DataContext="{Binding Path=FunktionsViewModel}"></local:FunktionsView>

	</Grid>
</Window>

<UserControl x:Class="WpfApp1.SprachView"
             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:wpfApp1="clr-namespace:WpfApp1"
             mc:Ignorable="d"
             d:DesignHeight="450" d:DesignWidth="800" 
             d:DataContext="{d:DesignInstance wpfApp1:SprachViewModel}">
	<Grid>
		<ListView ItemsSource="{Binding Sprachen}" />
	</Grid>
</UserControl>

und die entsprechenden ViewModels stark vereinfacht:


	public class MainViewModel
	{
		public SprachViewModel SprachViewModel { get; set; } = new SprachViewModel();
		public DatenbankViewModel DatenbankViewModel { get; set; } = new DatenbankViewModel();
		public FunktionsViewModel FunktionsViewModel { get; set; } = new FunktionsViewModel();
	}

	public class SprachViewModel
	{
		public List<string> Sprachen { get; set; } = new List<string> {"Deutsch", "Englisch"};
	}

	public class DatenbankViewModel
	{
		public List<string> Datenbanken { get; set; } = new List<string> {"DbA", "DbB"};
	}

	public class FunktionsViewModel
	{
		public List<string> Funktionen { get; set; } = new List<string> {"DoSomething", "DoSomethingElse"};
	}

Lg, XXX

19.11.2015 - 10:39 Uhr

Ich hab die Fragen auch unglücklich formuliert gefunden. Danke jedenfalls für das Feedback - das wird ihm hoffentlich auch weiterhelfen. 😃

18.11.2015 - 21:05 Uhr

Hallo,

ein Kollege in der FH hat im Rahmen seiner Bac-Arbeit eine Umfrage gestartet und gebeten, diese auch an andere weiterzuleiten. Sind 21 Fragen die vielleicht etwas klarer formuliert sein könnten aber trotzdem wärs nett, wenn sich der eine oder andere dafür opfert: Hier gehts zur Umfrage

Danke,
XXX

28.07.2015 - 12:42 Uhr

Ich kanns nicht erklären warum "Path=." den Wert nicht mehr zurückschreibt aber es ist nunmal so: Man kann nur die Eigenschaften des Context verändern, nicht aber den Context selbst.

Hier ein Beispiel zum Veranschaulichen:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
   <StackPanel Orientation="Vertical">

      <TextBox Text="{Binding TextProp1, UpdateSourceTrigger=PropertyChanged}"></TextBox>
      <TextBox DataContext="{Binding TextProp2, UpdateSourceTrigger=PropertyChanged}"
               Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged}"></TextBox>

   </StackPanel>
</Window>


   public partial class MainWindow : Window
   {
      private string _textProp1;
      private string _textProp2;

      public MainWindow()
      {
         InitializeComponent();

         DataContext = this;

         TextProp1 = "Text1";
         TextProp2 = "Text2";
      }

      public string TextProp1
      {
         get { return _textProp1; }
         set { _textProp1 = value; }
      }

      public string TextProp2
      {
         get { return _textProp2; }
         set { _textProp2 = value; }
      }
   }

TextBox1.Text ist an DataContext.TextProp1 gebunden
TextBox2.Text ist an DataContext gebunden, welcher selbst auf DataContext.TextProp2 geändert wurde.

Wenn du nun einen Breakpoint bei beiden Settern setzt, siehst du das (1) verändert wird aber (2) nicht.

Lg, XXX

//Edit: Um meinen vorigen Vorschlag nochmal zu verdeutlichen: Deine Items in der Listbox müssen in einem Wrapper-Objekt sein, damit du eine Property hast die du verändern kannst. Du kannst nicht den Kontext selbst ändern aber die Eigenschaften sehrwohl.

28.07.2015 - 12:32 Uhr

Hallo Palin,

wie hast du denn das SQL der Statements extrahiert? Per SQL-Profiler? Falls nicht würde ich das nochmal probieren: Die komplette Abfrage (nicht nur die einzelnen separiert) im Profiler loggen lassen und dann gemeinsam im SSMS ausführen lassen um zu sehen obs dort funktioniert.

Weiters kann es sein (und hatte ich schonmal), dass Sachen im SSMS funktionieren, die aber im PGM nicht funktionierten. Ich kann mich nur mehr grob daran erinnern, dass "SET ARITHABORT OFF/ON" da teilweise geholfen hat bzw. kann es auch Probleme mit dem Ausführungsplänen im SQL Server geben. Evt. mal die irgendwo resetten probieren.

Wie schauts aus, wenn du das Timeout anhebst? Wird die anfrage dann fertig oder nicht?

Lg, XXX

28.07.2015 - 11:19 Uhr

Also um es zum Verständnis zu vervollständigen:

  1. Du hast eine ListBox in der die "ausgewählten Produkte" dargestellt werden
  2. Irgendwo (extern) fügst du dann ein neues "Produkt" deiner Liste hinzu, welches vermutlich am Anfang leer sein wird.
  3. Jeder Eintrag in der ListBox wird durch eine ComboBox dargestellt, welche selbst widerum alle Produkte zur Auswahl hat.
  4. Dadurch kann man dann in der Liste der ausgewählten Produkte diese noch verändern, was sich klarerweise auch in der Liste der ausgewählten Produkte widerspiegeln soll.
  5. (später soll neben jedem Item in der Liste noch ein Button zum Entfernen hinzukommen)

Ich vermute mal das das Problem bei der Art des Bindings des SelectedItems zu suchen ist.

  • Mein erster Versuch wäre, die ListBox-Produkte in eine Wrapper-Klasse "ObservableList<SelectedProduct>" zu stecken. SelectedProduct ist in dem Fall ein ViewModel, welches das Binding erleichtern soll und selbst nur ein Property "Product" (inkl. NotifyPropertyChanged) hat.

  • Das Binding auf SelectedItem würde dann nicht auf "Path=." sondern "Path=Product" in SelectedProduct schauen und jede Manipulation würde dann wieder ordentlich in alle Richtungen durchschlagen.

Lg, XXX

28.07.2015 - 10:59 Uhr

In dem Link von mir macht einer einen Vorschlag wie er denkt das es gehen könnte. Eine eigene ComboBox basteln ist aber auch nicht so schlimm...

Vielleicht hilft dir aber auch eine sogenannte "AutoCompleteTextBox" weiter. Dazu gibts ein paar Projekte auf CodePlex zB.

Lg, XXX

27.07.2015 - 13:01 Uhr

Hallo Christel,

  • kommt der Freeze immer zur selben Zeit/bei der selben Aktion?
  • kannst du das Verhalten beim Debuggen auch nachvollziehen?
  • wenn die App gerade eingefroren ist, sieht man dann im TaskManager ungewöhnliche CPU-Last und/oder Festplattennutzung?

Lg, XXX

22.07.2015 - 11:02 Uhr

Hallo sth_Weird,

laut Combobox filter text lost when I type the latest inputs with some delay ist dieses Verhalten hard-coded und nicht veränderbar, jedoch hängt es direkt zusammen mit der Doppel-klick Gewschwindigkeit die man in Windows einstellen kann. Habs gerade getestet und es stimmt. Leider hat man aber hier auch nicht sehr viel Spielraum aber vielleicht hilfts ja schon.

Lg, XXX

22.07.2015 - 10:51 Uhr

Hallo deinChef,

ich kenn mich zwar mit Animations in WPF nicht all zu sehr aus, konnte aber dein Beispiel soweit anpassen, dass es glaub ich das tut, was du willst:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" xmlns:local="clr-namespace:WPFTestApp" x:Class="WpfApplication1.MainWindow"
        Title="MainWindow" Height="350" Width="525">
   <Window.DataContext>
      <local:MainViewModel/>
   </Window.DataContext>
   <DockPanel>
      <Border x:Name="LeftMenuBorder" Background="WhiteSmoke" DockPanel.Dock="Left" CornerRadius="0,5,5,0">
         <Border.Style>
            <Style TargetType="{x:Type Border}">
               <Setter Property="Width" Value="230"/>
               <Style.Triggers>
                  <DataTrigger Binding="{Binding LeftMenuVisible}" Value="True">
                     <DataTrigger.EnterActions>
                        <BeginStoryboard Name="growStoryBoard">
                           <Storyboard>
                              <DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="Width" From="0" To="230" />
                           </Storyboard>
                        </BeginStoryboard>
                     </DataTrigger.EnterActions>
                     <DataTrigger.ExitActions>
                        <RemoveStoryboard BeginStoryboardName="growStoryBoard"></RemoveStoryboard>
                     </DataTrigger.ExitActions>
                  </DataTrigger>
                  <DataTrigger Binding="{Binding LeftMenuVisible}" Value="False">
                     <DataTrigger.EnterActions>
                        <BeginStoryboard Name="shrinkStoryBoard">
                           <Storyboard>
                              <DoubleAnimation Duration="0:0:1" Storyboard.TargetProperty="Width" To="0" />
                           </Storyboard>
                        </BeginStoryboard>
                     </DataTrigger.EnterActions>
                     <DataTrigger.ExitActions>
                        <RemoveStoryboard BeginStoryboardName="shrinkStoryBoard"></RemoveStoryboard>
                     </DataTrigger.ExitActions>
                  </DataTrigger>
               </Style.Triggers>
            </Style>
         </Border.Style>
         <TextBlock TextWrapping="Wrap" Text="{Binding LeftMenuVisible}"/>
      </Border>
      <Border Width="10" Background="Gray">
         <i:Interaction.Triggers>
            <i:EventTrigger EventName="MouseLeftButtonDown">
               <ei:CallMethodAction TargetObject="{Binding}" MethodName="ChangeVisible"/>
            </i:EventTrigger>
         </i:Interaction.Triggers>
      </Border>
      <Grid/>
   </DockPanel>
</Window>

Wesentliche Änderungen:

  • DataTrigger.ExitActions definiert
  • Bei der Vergrößern Animation noch ein "from" eingebaut, da beim Reset des vorigen Triggers die Breite wieder den Ursprungswert von 230 hat und somit nichts mehr zu tun ist.

Lg, XXX

14.07.2015 - 21:24 Uhr

Hallo Quaneu,

wenn dein Matrixcontrol nur ein Layout-Container sein soll, dann wärs schöner, wenn er sich nur ums Layout kümmert. Die Visuelle Darstellung würde ich dann entweder per DataTemplates ganz ausserhalb oder in einer Zwischenschicht realisieren.

Bsp:

MatrixLayout wie im Beispiel hier beschrieben: How to create a Custom Layout Panel in WPF

Darüber ein MatrixControl, welches dann aus einem ItemsControl mit MatrixLayout als ItemsPanelTemplate verwendet sowie aus einem custom ItemTemplate besteht. Passend dazu brauchst du dann natürlich attached Properties (wie Grid.Row) um den Child-Elementen die richtige Zeile/Spalte zuzuweisen (oder halt irgendwie automatisch setzen), welche dann vom MatrixLayout verwendet wird um die richtigen Controls zu platzieren.

Aja bzgl. Virtualisierung die in Listbox oder DataGrid stattfindet, hier ein Beispiel: WPF: Custom Virtualizing Panel For TreeView

Du müsstest dein MatrixLayout also von VirtualizingPanel erben lassen.

Lg, XXX

08.07.2015 - 13:47 Uhr

Und wenn du das komplett über das ViewModel abbildest?

Ist sicherlich die schönste Lösung... Einfach die Checkboxen an ein Property binden und dort die Logik abbilden die du erreichen willst.

08.07.2015 - 10:56 Uhr

Hallo sth_Weird,

als Property im Setter muss natürlich das Ziel-Property (IsChecked) angegeben werden und im Valuebereich kommt dann das Binding inkl. Converter rein:

<Setter Property="IsChecked" Value="{Binding Path=MyFlags, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource FlagsToBoolConverter}, ConverterParameter=FlagXYZ}"></Setter>

Lg, XXX

07.07.2015 - 14:26 Uhr
  • Die System.Windows.Interactivity.dll mal aus dem Zielverzeichnis löschen und schauen ob das Service noch immer läuft.

  • Eventuell benötigt eine verwendete Bibliothek diese quasi indirekt?

  • Wenn du das Zielverzeichnis cleanst und nur Service-Relevante Projekte kompilierst, wird die System.Windows.Interactivity.dll dann auch rein kopiert?

  • Wenn es sich garnicht beheben lässt, könntest du CopyLocal deaktivieren und das File manuell per PostBuild Script ins Zielverzeichnis kopieren (nur wenn unterschiedlich)

Lg, XXX

//Edit:

laut Does Visual Studio 2010 copy assemblies with “Copy Local = true” on every build? sollte die Assembly ohnehin nur kopiert werden, wenn sie neuer ist. - Trifft dies bei dir zu? Haben die teilweise unterschiedliche Versionen?

07.07.2015 - 14:17 Uhr

Wie wärs mit einem Singleton der ThreadLocal im Hintergrund verwendet? ThreadLocal hat ja die Eigenschaft IsValueCreated, mit der du im Singleton dann prüfen könntest, ob es sich um einen neuen Thread handlet und ihn gleich dort initialisieren.

Lg, XXX

07.07.2015 - 14:09 Uhr

Nimm mal bei

das

IsChecked="False"   

raus.

Das wird es wohl sein. Ein Style-Setter kann keine manuell gesetzten Properties überschreiben. Wenn du aus irgendeinem Grund ein Property vom Start weg setzen willst, mach dies ebenfalls im Style per Setter.

Lg, XXX

07.07.2015 - 12:46 Uhr

Wenn mehrere benutzer auf die gleichen Daten zugreifen, musst du die Daten entweder vorher sperren, oder sie mit einem Timestamp versehen und vor dem Update prüfen ob sie sich verändert haben und entsprechend darauf reagieren.

Lg, XXX

07.07.2015 - 11:52 Uhr

Hallo Tam0r,

das was du gepostet hast sollte eh schon funktionieren, wenn du die richtigen Tabellenbezeichnungen/Aliase verwendest.

SELECT
Kunden.Nr,
    (SELECT SUM(Umsätze.Höhe) FROM Umsätze WHERE Umsätze.KundenNr = Kunden.Nr)

FROM Kundenliste Kunden

Lg, XXX

06.07.2015 - 17:06 Uhr

Hallo DerPete,

hach, da hat sich ein Tippfehler sowie ein Bedingungsfehler eingeschlichen. Wenn du dich ganz fest anstrengst kommst du vielleicht auch selber drauf.

Lg, XXX

06.07.2015 - 15:35 Uhr

Hallo DerPete,

Danke!

Ich schicke immer "#" vorraus.

Die Anwendung häng sich aber immer auf wenn ich das so ausführe!

was auch auf den ersten Blick klar ist, wenn man sich den Code ansieht.

Mit einer Raute als Löschzeichen könntest du es so probieren:


        private void timer1_Tick(object sender, EventArgs e)
        {
            String input = serialPort1.ReadExisting();

            int i = input.IndexOf("#");

            if(i >= 0)
            {
               richTextBox1.Clear();
            }            

            if(i + 1 > input.Length)
            {
               richTextBox1.AppendText(input.SubString(i + 1));
            }

        }

Lg, XXX

06.07.2015 - 12:28 Uhr

Hallo ClaRaCapitano,

anstatt beim Checked Event den String zu erweitern, würde ich den Inhalt der Textbox bei jeder Änderung komplett generieren lassen. (Anhand der ausgewählten Optionen)

Die Textbox selbst darf dann natürlich nicht mehr editierbar sein und etwaige zusatzeingaben müssen über entsprechende Formularfelder (bei den Checkboxen) eingetragen werden.

Dies hat zur Folge, dass ganz unabhängig ob etwas an- oder abgehackt wird, immer der richtige Command erzeugt wird.

Lg, XXX

//Edit: Ja prinzipiell eh das selbe was Coffeebean gesagt hat... 😛

11.08.2014 - 13:52 Uhr

Hallo Hobelschlunze

was war daran erfolglos? Hast du das Beispiel probiert?

Lg, XXX

07.08.2014 - 10:48 Uhr

@Th69: weil er als Value im Property nur eine Art ID hat und dafür aber einen anderen Wert anzeigen lassen will.

@rokohl: Du kannst einem Binding einen Converter vom Typ IValueConverter oder IMultiValueConverter übergeben, der dann die Konvertierung für dich vornimmt.

Lg, XXX

30.07.2014 - 11:02 Uhr

Hallo SenseLi,

du kannst entweder den FullQualifiedName der Convert Klasse probieren: System.Convert.ToDouble()

oder du prüfst bevor du konvertierst um welchen QuellTyp es sich handelt und reagierst darauf entsprechend:

in deinem Fall kommt vermutlich ein String "10" den du mit double.Parse() umwandeln könntest.

Lg, XXX

28.07.2014 - 23:25 Uhr

Hallo Exis,

es gilt nach wie vor: Wenn du nicht ordentlich erklärst was du überhaupt erreichen willst, kann dir hier auch niemand helfen.

Du postest einen Codeauschnitt mit einem DockingPanel und einem TabControl als Child und erwähnst nicht das du noch andere Controls darin platzieren willst. Welche, Wieviel und Wohin sollen die denn kommen? Das können wir nicht erraten.

Der Einwand von Lando ist gerechtfertigt: Solange du Width gesetzt hast, wird dein TabControl sich nicht in der Breite automatisch anpassen können.

Den Begriff "Anchor" gibt es im WPF meines Wissens nach nicht mehr. Was stattdessen eben verwendet wird sind automatische (also nicht gesetzte) Breiten & Höhen inkl. passenden Margins und/oder Paddings.

Lg, XXX

28.07.2014 - 11:54 Uhr

Hallo flacker,

vielleicht erklärst du noch ein wenig, was du eigentlich vor hast. Wieso willst du, dass Width & Height gesetzt ist, wenn du dann eh nur die Breite und Höhe des Parents übernimmst?

Du kannst auf jeden Fall immer die aktuelle Breite und Höhe mit den Properties ActualWidth und ActualHeight auslesen. Das Setzen der eigentlichen Breite und Höhe sollte man eigentlich vermeiden und mit LayoutContainern arbeiten außer es gibt spezielle Gründe dafür.

Lg, XXX

PS: ActualWidth und ActualHeight werden auch beim Maximieren gesetzt.

28.07.2014 - 11:41 Uhr

Hallo Christian1983,

also eine rudimentäre Lösung zu Problem 1 wäre ein Script in den Autostart Folder zu legen das sich selbst nach dem ersten run löscht. In dem Script kannst du dann die restlichen Aufräumarbeiten erledigen die ersten nach dem ersten Login anfallen.

Lg, XXX

28.07.2014 - 11:34 Uhr

Hallo Create,

DataGrids haben selbst einen ScrollViewer, weswegen sie MouseWheel Events schlucken sobald sie den Fokus haben (Vermutung).

Hier wird das Problem ebenfalls besprochen und ein manuelles (im Code) Scrollen vorgeschlagen:

<StackPanel x:Name="ResultStackPanel" PreviewMouseWheel="ScrollViewer_PreviewMouseWheel">


    private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        ScrollViewer scv = (ScrollViewer)sender;
        scv.ScrollToVerticalOffset(scv.VerticalOffset - e.Delta);
        e.Handled = true;
    }

Lg, XXX

25.07.2014 - 11:23 Uhr

Hallo trib,

vielleicht hilfts die ListView im VirtualMode laufen zu lassen.

Lg, XXX

25.07.2014 - 11:08 Uhr

Hallo ProGamer,

wie soll ein FlowLayoutPanel helfen um die Veränderung der Größe des Controls mitzubekommen? Er verwendet ja bereits ein TableLayoutPanel um seine Controls zu organisieren.

Um die Größenveränderung in einem Control mitzubekommen gibt es Events:

Lg, XXX

24.07.2014 - 17:24 Uhr

Hallo JanLehmL,

im OnPaint die MessageBox aufzurufen (selbst für Debuggingzwecke) tut weh anzusehen^^. Du kannst ja auch mit Debug.WriteLine zB die Werte in die Console rausschreiben.

Wofür brauchst du denn die gespeicherten Werte überhaupt? Reichts nicht, wenn du die Breite und Höhe wie im OnPaint on-the-fly berechnest?

Und wenn Control.Width bei dir 200 anzeigt heißt dass, dass das Control 200 breit ist. Hier ist kann nichts falsch sein außer dein Control wurde fälschlicherweise resized.

Ich kann aber nicht von der protected Funktion aus eine Globale Variable füllen. <- Das ist leider mein Problem.

Die Variable wird auf jeden Fall gesetzt. Zwei Möglichkeiten für dein Problem gibt es:

  1. Die Variablen und die ControlSize wird von einer anderen Stelle zwischen OnPaint aufruf und messageTheWidth verändert. (unwahrscheinlich)

  2. Du hast unabsichtlich zwei Graphicpanels instantiiert die du fälschlicherweise für das Selbe haltest. D.h. in einem setzt du im OnPaint die Breite/Höhe und im Anderen schaust du den Wert nach.
    Um herauszufinden ob es sich um das gleiche oder unterschiedliche Panels handelt kannst du zB im OnPaint und in messageTheWidth zusätzlich "this.GetHashCode()" ausgeben und die Werte vergleichen. Wenn sich der Wert ändert, hast du mehrere Objekte angelegt oder in Verwendung.

Lg, XXX

23.07.2014 - 11:03 Uhr

bissi herumexperimentieren, dann sollte es gehen:



         //DataSet1 dataSet1 = new DataSet1();
         //dataSet1.Tables.Add(new DataView(table) { RowFilter = filter }.ToTable());
         //ConsoleApplication1.DataSet1.DataTable1DataTable table2 = (DataSet1.DataTable1DataTable) dataSet1.Tables[0];


         DataSet ds = new DataSet();
         ds.Tables.Add(new DataView(table) { RowFilter = filter }.ToTable());

         DataSet1.DataTable2DataTable table2 = new DataSet1.DataTable2DataTable(ds.Tables[0]);


Lg, XXX

//Edit: So sollte es funktionieren

23.07.2014 - 10:54 Uhr

Achso du hast ein typisiertes DT.

Probier mal folgendes stattdessen:


dataTable.DefaultView.RowFilter = filter;

dataTable = dataTable.DefaultView.ToTable();

Lg, XXX

//EDIT: Scheint nicht zu funktionieren. 😕

23.07.2014 - 10:40 Uhr

Hallo Guidol,

das neue Erstellen einer neuen DataTable aus den gefilterten Rows wäre vermutlich auch etwas schneller:

DataTable table2 = new DataView(table) { RowFilter = filter }.ToTable();

Lg, XXX

23.04.2014 - 12:22 Uhr

Hallo esparki,

wenn du in deiner Methode "wartest", blockierst du damit vermutlich auch den Aufrufer, der dadurch nicht auf deine Aktion reagieren kann.

Evt. hilfts wenn du die Methode Asynchron gestaltest.

Lg, XXX

10.04.2014 - 16:29 Uhr

Datenbankabfragen kann man, soweit ich mich vor kurzem darüber informiert hab, nur durch ein Thread.Abort abbrechen.

Lg, XXX

PS: Ich mach in meinem Programm dasselbe. Zuerst warte ich zwischen 100 und 400ms mittels Timer die eingaben des Users ab, sodass nicht alle anfragen versendet werden und unterbreche mittels Thread.Abort falls während einer Abfrage was dazwischen kommt.

03.02.2014 - 14:27 Uhr

Hallo Astinels,

soll denn der "Kern" selbstständig lauffähig sein oder nur als Bibliothek eingebunden sein? Im letzteren Fall brauchst du eig. nichts großartiges zu berücksichtigen. Du erstellst einfach deine WPF Applikation, fügst noch eine Bibliothek dazu und lässt alle GUI-Elemente und GUI-relevanten Klassen im "Hauptprogramm" und die "Kern"-Klassen lagerst du in deine zweite Bibliothek aus.

Lg, XXX

11.10.2013 - 16:43 Uhr

Hallo KnutBerlin,

evt. so:

  • DataTrigger
    • MultiDataBinding mit Value und MaxValue als Bindings
    • MultiValueConverter der die zwei Werte vergleicht und entsprechend true oder false zurück gibt

Lg, XXX

13.09.2013 - 16:19 Uhr

Dann möcht ich meine unleserliche Version hier auch posten... 😃


        public static bool Contains<T>(this IEnumerable<T> enumerable, IEnumerable<T> items, IEqualityComparer<T> comparer)
        {
            T[] arr1 = enumerable.ToArray();
            T[] arr2 = items.ToArray();

            int i = 0, i2, j;
            do
            {
                for (j = 0; i < arr1.Length && arr2.Length > 0 && !comparer.Equals(arr1[i], arr2[0]); i++) ;
                for (i2 = i; i2 < arr1.Length && j < arr2.Length && comparer.Equals(arr1[i2], arr2[j]); i2++, j++) ;

            } while (i++ < arr1.Length && j != arr2.Length);

            return j == arr2.Length;
        }

//Edit: Und weils so lustig war noch eine ultrakurz version 😄


        public static bool Contains2<T>(this IEnumerable<T> x, IEnumerable<T> y, IEqualityComparer<T> c)
        {
            T[] a = x.ToArray(), b = y.ToArray();
            for (int i = 0, l, k, n = a.Length, m = b.Length; i < n; i++)
            {
                for (k = 0; i < n && m > 0 && !c.Equals(a[i], b[0]); i++) ;
                for (l = i; l < n && k < m && c.Equals(a[l], b[k]); l++, k++) ;
                if (k == m) return true;
            }
            return false;
        }

Lg, XXX

03.07.2013 - 13:38 Uhr

Meine Vermutung steckt wie vorhin angedeutet in der Erzeugung und Verwendung unterschiedlicher ViewModels.

Wenns leicht geht, stell hier mal ein komplettes Minimalbeispiel rauf. Würd mich interessieren worans scheitert.

Lg, XXX

02.07.2013 - 10:42 Uhr

Hallo irgendwas,

mir fallen da ein paar Sachen an deinem Code unangenehm auf:

  • Für Listen im ViewModel verwendet man eher eine ObservableCollection, welche man nicht bei jeder Änderung komplett leert und neu befüllt sondern nur gezielt die Elemente rausnimmt und einfügt die sich geändert haben.

  • Die generierten ObjektViewModels würde ich nur bei einem "Notify" aufruf neu erzeugen und nicht bei jedem Propertyzugriff. (Ich vermute hier auch irgendwo dein Problem)

  • In einer Klasse die INotifyPropertyChanged implementiert macht es nur Sinn die eigenen PropertyChanges zu feuern. Der Aufruf _o.PropertyChanged += RaisePropertyChanged ist daher quatsch, auch wenn es in dem Fall nicht auffällt, da in ObjectViewModel und im SomeObject beide Male das selbe Property Name gibt. Heißt aber das Property im SomeObject zB Vorname und Nachname und im ObjectViewModel einfach nur Name, wird die View nie davon benachrichtigt werden, dass Name sich verändert hat wenn Vor oder Nachname sich geändert haben. -> Hier gehört PropertyChanged genauso implementiert wie bei ListViewModel.

  • Bei Setter, die PropertyChanged aufrufen, würde ich ein if(value != oldValue) einbauen um unnötige Aufrufe zu minimieren.

  • Und um etwas Redundanz zu sparen würde ich NotifyPropertyChanged noch einmal eine Stufe höher ansiedeln.

Hier meine Vorschläge dazu eingearbeitet:



    public class ListViewModel : ViewModelBase
    {
        public ListViewModel()
        {
            ChildObjects = new ObservableCollection<ObjectViewModel>();
            SomeDataProvier.PropertyChanged += new PropertyChangedEventHandler(Notify);
        }

        public ObservableCollection<ObjectViewModel> ChildObjects { get; private set; }

        private void Notify(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName.Equals("SomeObjectList"))
            {
                //hier kannst du auch gezielt Items entfernen und hinzufügen

                //ChildObjects.Clear();

                //foreach (SomeObject o in SomeDataProvider.SomeObjectList)
                //{
                //    ChildObjects.Add(new ObjectViewModel(o));
                //}
            }
        }
    }

    public class ObjectViewModel : ViewModelBase
    {
        private SomeObject _o;

        public ObjectViewModel(SomeObject o)
        {
            _o = o;
            _o.PropertyChanged += SomeObjectPropertyChanged;
        }

        private void SomeObjectPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Name")
                RaisePropertyChanged("Name");
        }

        public string Name
        {
            get { return _o.Name; }
            set { _o.Name = value; }
        }
    }

    public class SomeObject : ModelBase
    {
        private string _name;

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                {
                    _name = value;
                    RaisePropertyChanged("Name");
                }
            }
        }
    }

    public abstract class ModelBase : ObjectBase { }

    public abstract class ViewModelBase : ObjectBase { }

    public abstract class ObjectBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion

        protected virtual void RaisePropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Lg, XXX

01.07.2013 - 16:16 Uhr

Hallo Quaneu,

vielleicht hilft dir die Antwort bei Creating threads - Task.Factory.StartNew vs new Thread() ja weiter. TaskFactory entscheidet offenbar selbstständig ob ein Task einen neuen Thread erstellen soll oder nicht sofern das nicht explizit angegeben wird.

Lg, XXX

PS: Das Verhalten nennt sich offenbar Task-Inlining: Task Schedulers

18.04.2013 - 11:32 Uhr

Ich hatte einmal auch ein Panel geschrieben, welches einen Border hatte und die ChildControls sollten in der Mitte platziert sein. Ich hab das damals so gelöst, dass ich beim ControlAdded Event mich an SizeChanged, LocationChanged und VisibleChanged rangehängt habe um bei Änderungen die Größe bzw. evt. deren Positionen neu zu berechnen. Ist halt eine wacklige Geschichte wenn man dann gegen Dock.Fill oder Anchoring ankämpfen will/muss. 😛

05.04.2013 - 14:20 Uhr

Es gibt mMn. nur dann Probleme wenn die Lambda Expression nicht sofort in dem Block ausgeführt wird sondern erst später:

Hier zB schreit ReSharper obwohl es keine Probleme geben wird:


            for (int i = 0; i < 10; i++)
            {
                Action action = () => Console.WriteLine(i);

                action();
            }

Ausgabe:


0
1
2
3
4
5
6
7
8
9

Hier allerdings wird die Ausgabe nicht das gewünschte Ergebnis erzielen.


            List<Action> actions = new List<Action>();
            for (int i = 0; i < 10; i++)
            {
                Action action = () => Console.WriteLine(i);

                actions.Add(action);
            }
            foreach (Action action in actions)
                action();

Ausgabe:


10
10
10
10
10
10
10
10
10
10

Lg, XXX

//Edit: Bevor Herbivore seine Antwort abschickt revidier ich mal meine Aussage: Bei meinem Beispiel gehts um die "Access to modified closure" Meldung. 😛

05.04.2013 - 11:02 Uhr

Hier hab ich einen interessanten Thread dazu gefunden: WPF TemplateBinding vs RelativeSource TemplatedParent

Speziell diese Erklärung dazu gefällt mir:

TemplateBinding - More limiting than using regular Binding

More efficient than a Binding but it has less functionality  
Only works inside a ControlTemplate&#39;s visual tree  
**Doesn&#39;t work with properties on Freezables**  
Doesn&#39;t work within a ControlTemplate&#39;s Trigger  
Provides a shortcut in setting properties(not as verbose),e.g. {TemplateBinding targetProperty}  

Regular Binding - Does not have above limitations of TemplateBinding

Respects Parent Properties  
Resets Target Values to clear out any explicitly set values  
Example: &lt;Ellipse Fill=&quot;{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}&quot;/&gt;
25.03.2013 - 13:54 Uhr

Wenn der Debugger bei der Fehlermeldung stehenbleibt mach einmal die "InnerException" auf und schau was dort drinnen steht. Oft steht dort dann was den Fehler ausgelöst hat.

Und eine XamlParseException wird meist dann geworfen, wenn am Xaml Code irgendwas nicht stimmt. Dies kannst du einfach prüfen indem du das Formular Schritt für Schritt (in einem Testprojekt) nachbaust und schaust ab wann der Fehler auftritt.(Solltest du überhaupt keine Ahnung haben).

Siehe dazu auch: FAQ/Entwurf: Vertrackte Fehler durch Vergleich von echtem Projekt mit minimalem Testprojekt finden

Lg, XXX

20.03.2013 - 14:37 Uhr

Hallo MillionsterNutzer,

du hast ja geschrieben, dass in einem "sterilem" Szenario in einem neuen Projekt keine merkmalen oder gravierenden Unterschiede zwischen der Ausführung mit oder ohne Thread existieren. Das heißt, dass der Hund nicht dort sondern in einem anderen Teil deines Programms liegt, welche unter Umständen mit diesem interagiert.

Für solche Fälle gibt es mMn. nur eine Lösung um auf das Problem zu kommen und diese ist hier beschrieben: [Tutorial] Vertrackte Fehler durch Vergleich von echtem Projekt mit minimalem Testprojekt finden

Lg, XXX