Binäruhr

    • C#
    • .NET (FX) 4.5–4.8

    Es gibt 32 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

      jo, das mittm .Zip ist fein, aber recht advanced (Extensions, anonyme Methode, Linq, anonyme Klasse).
      also Zip vereinigt 2 Auflistungen zu einer, deren nun Elemente aus Properties der beiden anneren zusammengesetzt sein können.
      Wenn du genau guckst: das erste Argument ist die eine Auflistung, das 2 ist die annere Auflistung, und das 3. Argument ist eine anonyme Methode, die Objekte eines anonymen Datentypen erstellt, wo jeweils von den beiden Auflistungen je ein Element enthalten ist.
      Achso - weil .Zip eine Extension-Methode ist kommt sie in Syntax einer Objekt-Methode daher. Was ich also als "erstes Argument" bezeichne, erscheint im Code als Objekt, von dem die Zip-Methode aufgerufen wird (konkret: _TimeLists ist das erste Argument der Zip-Methode)

      Also die neue Auflistung enthält Objekte eines anonymen Datentyps mit den Properties ObservableCollection<bool> lst und int value
      Also son anonymes Objekt verknüppert die richtige OC mit dem richtigen Datum-Anteil (Sekunde, Minute, Stunde).
      Der Datum-Anteil ist ja int, und wird den genannten bitweisen Operationen unterzogen, um die bools der OC erforderlichenfalls richtig zu setzen.

      Ist nicht optimal benamt, "timePart" wäre sinniger gewesen als "value"
      und "boolList" sinniger als "lst"

      Weißt du wie du die Zip-Methode auf Msdn dokumentiert kriegst? VisualStudio richtig nutzen (Google ist nicht deine Mami)

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Danke, hab mir das Video mal angeschaut. Einiges davon wusste ich schon, aber das mit dem Objektkatalog wusste ich noch nicht. Super erklärt, bis auf das ding mit F2 was ich in deinem Forenpost dann gelesen habe :D
      Ich werde mir mal bei gelegenheit 'zip' angucken und ein bisschen basteln :D
      So, wiedermal eine Verbesserung von mir.
      Habe nicht mit dem Zip befehl gearbeitet, weil ich da noch nicht so durchgestiegen bin :D

      Converter.cs

      C#-Quellcode

      1. using System;
      2. using System.Globalization;
      3. using System.Windows.Data;
      4. using System.Windows.Media;
      5. namespace BinaerUhrMVVM.Converters
      6. {
      7. [ValueConversion(typeof(bool),typeof(Brush))]
      8. public class Converter : IValueConverter
      9. {
      10. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
      11. {
      12. if ((bool)value)
      13. return Brushes.Red;
      14. return Brushes.LightGray;
      15. }
      16. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
      17. {
      18. throw new NotImplementedException();
      19. }
      20. }
      21. }



      TimeElement.cs

      C#-Quellcode

      1. using System;
      2. using System.ComponentModel;
      3. namespace BinaerUhrMVVM
      4. {
      5. public class TimeElement : INotifyPropertyChanged
      6. {
      7. private int _bit;
      8. public int bit
      9. {
      10. get { return _bit; }
      11. set
      12. {
      13. _bit = value;
      14. OnPropertyChanged("bit");
      15. }
      16. }
      17. private bool _h;
      18. public bool h
      19. {
      20. get { return _h; }
      21. set
      22. {
      23. _h = value;
      24. OnPropertyChanged("h");
      25. }
      26. }
      27. private bool _m;
      28. public bool m
      29. {
      30. get { return _m; }
      31. set
      32. {
      33. _m = value;
      34. OnPropertyChanged("m");
      35. }
      36. }
      37. private bool _s;
      38. public bool s
      39. {
      40. get { return _s; }
      41. set
      42. {
      43. _s = value;
      44. OnPropertyChanged("s");
      45. }
      46. }
      47. public TimeElement(int bit, bool h = false, bool m = false, bool s = false)
      48. {
      49. this.bit = bit;
      50. this.h = h;
      51. this.m = m;
      52. this.s = s;
      53. }
      54. #region INotifyPropertyChanged Members
      55. public event PropertyChangedEventHandler PropertyChanged;
      56. private void OnPropertyChanged(string propertyName)
      57. {
      58. PropertyChangedEventHandler handler = PropertyChanged;
      59. if (handler != null)
      60. {
      61. handler(this, new PropertyChangedEventArgs(propertyName));
      62. }
      63. }
      64. #endregion
      65. }
      66. }


      "Speichert" eine "Zeit-Zeile"


      TimeList.cs

      C#-Quellcode

      1. using System;
      2. using System.Collections.Generic;
      3. using System.Collections.ObjectModel;
      4. namespace BinaerUhrMVVM
      5. {
      6. public class TimeList : ObservableCollection<TimeElement>
      7. {
      8. public TimeList()
      9. {
      10. this.Add(new TimeElement(1));
      11. this.Add(new TimeElement(2));
      12. this.Add(new TimeElement(4));
      13. this.Add(new TimeElement(8));
      14. this.Add(new TimeElement(16));
      15. this.Add(new TimeElement(32));
      16. }
      17. public void setTime(String h, String m, String s)
      18. {
      19. for(int i = 0; i < 6; i++)
      20. {
      21. this[i].h = h[i] == '1' ? true : false;
      22. this[i].m = m[i] == '1' ? true : false;
      23. this[i].s = s[i] == '1' ? true : false;
      24. }
      25. }
      26. public String toBinary(int time)
      27. {
      28. String tempF = Convert.ToString(time, 2).PadLeft(6, '0');
      29. String tempR = "";
      30. for (int i = tempF.Length - 1; i >= 0; i--)
      31. tempR += tempF[i].ToString();
      32. return tempR;
      33. }
      34. public void act(DateTime time)
      35. {
      36. setTime(toBinary(time.Hour), toBinary(time.Minute), toBinary(time.Second));
      37. }
      38. }
      39. }



      UhrModel.cs

      C#-Quellcode

      1. using System;
      2. using System.Windows;
      3. using System.Windows.Threading;
      4. namespace BinaerUhrMVVM.ViewModel
      5. {
      6. internal class UhrModel
      7. {
      8. public UhrModel()
      9. {
      10. _time = new TimeList();
      11. timer = new DispatcherTimer();
      12. timer.Interval = new TimeSpan(0, 0, 0, 0, 100);
      13. timer.Tick += timer_Tick;
      14. timer.Start();
      15. }
      16. private TimeList _time;
      17. public TimeList time
      18. {
      19. get { return _time; }
      20. }
      21. private DispatcherTimer timer;
      22. void timer_Tick(object sender, EventArgs e)
      23. {
      24. _time.act(DateTime.Now);
      25. }
      26. }
      27. }



      Uhr.xaml

      XML-Quellcode

      1. <Window x:Class="BinaerUhrMVVM.MainWindow"
      2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      4. xmlns:vm="clr-namespace:BinaerUhrMVVM.ViewModel"
      5. xmlns:cnv="clr-namespace:BinaerUhrMVVM.Converters"
      6. Title="Binär-Uhr" Height="220" Width="140" KeyboardNavigation.TabNavigation="None" MinWidth="140" MinHeight="220" WindowStyle="ToolWindow" ResizeMode="NoResize" >
      7. <Window.Resources>
      8. <vm:UhrModel x:Key="uhr" />
      9. <cnv:Converter x:Key="boolToBrushConverter" />
      10. </Window.Resources>
      11. <StackPanel Orientation="Vertical" DataContext="{StaticResource uhr}" Width="110">
      12. <Grid Height="25">
      13. <Grid.ColumnDefinitions>
      14. <ColumnDefinition Width="*" />
      15. <ColumnDefinition Width="*" />
      16. <ColumnDefinition Width="*" />
      17. <ColumnDefinition Width="*" />
      18. </Grid.ColumnDefinitions>
      19. <TextBlock Grid.Column="1" Text="h" TextAlignment="Center" VerticalAlignment="Bottom"/>
      20. <TextBlock Grid.Column="2" Text="m" TextAlignment="Center" VerticalAlignment="Bottom"/>
      21. <TextBlock Grid.Column="3" Text="s" TextAlignment="Center" VerticalAlignment="Bottom"/>
      22. </Grid>
      23. <ItemsControl ItemsSource="{Binding time}" Background="{x:Null}" BorderBrush="{x:Null}" Focusable="False" >
      24. <ItemsControl.ItemTemplate>
      25. <DataTemplate>
      26. <Grid>
      27. <Grid.ColumnDefinitions>
      28. <ColumnDefinition Width="25" />
      29. <ColumnDefinition Width="*" />
      30. <ColumnDefinition Width="*" />
      31. <ColumnDefinition Width="*" />
      32. </Grid.ColumnDefinitions>
      33. <Border Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Stretch" Padding="4">
      34. <TextBlock Text="{Binding bit}" TextAlignment="Right"/>
      35. </Border>
      36. <Border Grid.Column="1" Height="{Binding Width, RelativeSource={RelativeSource Self}}" Width="25" HorizontalAlignment="Stretch" Padding="4">
      37. <Border Background="{Binding h, Converter={StaticResource boolToBrushConverter}}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
      38. </Border>
      39. <Border Grid.Column="2" Height="{Binding Width, RelativeSource={RelativeSource Self}}" Width="25" HorizontalAlignment="Stretch" Padding="4">
      40. <Border Background="{Binding m, Converter={StaticResource boolToBrushConverter}}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
      41. </Border>
      42. <Border Grid.Column="3" Height="{Binding Width, RelativeSource={RelativeSource Self}}" Width="25" HorizontalAlignment="Stretch" Padding="4">
      43. <Border Background="{Binding s, Converter={StaticResource boolToBrushConverter}}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
      44. </Border>
      45. </Grid>
      46. </DataTemplate>
      47. </ItemsControl.ItemTemplate>
      48. </ItemsControl>
      49. </StackPanel>
      50. </Window>



      Also aus meiner Sicht habe ich das jetzt krass verbessert. Wie seht ihr das?

      mfg nxtman
      hmm - ich finds schlechter.
      Ist mehr Code, ist unübersichtlicher.
      Wo ich's ganz simpel löse mit ObservableCollection<bool>, dies schon gibt, da erfindest du TimeElemente und TimeListen, mit Interfaces und pipapo.

      Jo, und bei mir ists in einer 40 Zeilen-Klasse komplett abgehandelt, wo du mit 4 Klassen unterwegs bist.

      Verbesserungen sollten Code verringern, nicht vermehren.
      Guckma, was ich mittm Zeitspeicher deiner ersten Lösung gemacht hab - wie effizient man in c# initialisieren kann:

      C#-Quellcode

      1. using System;
      2. using System.ComponentModel;
      3. using System.Collections.ObjectModel;
      4. using System.Linq;
      5. namespace BinaerUhrMVVM {
      6. public class ZeitSpeicher {
      7. public ObservableCollection<bool> listH { get; private set; }
      8. public ObservableCollection<bool> listM { get; private set; }
      9. public ObservableCollection<bool> listS { get; private set; }
      10. private ObservableCollection<bool>[] _TimeLists;
      11. public ZeitSpeicher() {
      12. listH = new ObservableCollection<bool>(new bool[5]);
      13. listM = new ObservableCollection<bool>(new bool[6]);
      14. listS = new ObservableCollection<bool>(new bool[6]);
      15. _TimeLists = new ObservableCollection<bool>[] { listS, listM, listH };
      16. }
      17. public void SetTime() {
      18. DateTime time = DateTime.Now;
      19. var items = _TimeLists.Zip(new int[] { time.Second, time.Minute, time.Hour }, (boolList, timePart) => new { boolList,timePart });
      20. foreach (var itm in items) {
      21. for (var i = 0; i <= itm.boolList.Count - 1; i++) {
      22. var bit = (itm.timePart & (1 << i)) > 0;
      23. if (itm.boolList[i] != bit) itm.boolList[i] = bit;
      24. }
      25. }
      26. }
      27. }
      28. }
      Und das int2Binary über eine string-Umwandlung laufen zu lassen ist eiglich ziemlich krank. Man muss sich die bitweise Logik richtig überlegen, dann wird das effizient und gleichzeitig auch leicht verständlich.
      Statt der zipperei kann man übrigens auch eine for i - Schleife nehmen, die 2 Arrays parallel durchschleift. Dann fuhrwerkt man da zwar mit zweierlei Indizees herum, also viele Klammern und so, aber sterben tut man da auch nicht von.

      Übrigens sollten public Classmember ausnahmslos Gross geschrieben werden, ob nun Methode, Property oder Event.

      Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „ErfinderDesRades“ ()

      Ich denke vielleicht manchmal ein bisschen zu kompliziert ^^

      Hier die "Erneuerung":

      ZeitSpeicher.cs

      C#-Quellcode

      1. public class ZeitSpeicher
      2. {
      3. private ObservableCollection<bool> h;
      4. private ObservableCollection<bool> m;
      5. private ObservableCollection<bool> s;
      6. public ObservableCollection<bool> H
      7. {
      8. get { return h; }
      9. }
      10. public ObservableCollection<bool> M
      11. {
      12. get { return m; }
      13. }
      14. public ObservableCollection<bool> S
      15. {
      16. get { return s; }
      17. }
      18. public ZeitSpeicher()
      19. {
      20. h = new ObservableCollection<bool>(new bool[5]);
      21. m = new ObservableCollection<bool>(new bool[6]);
      22. s = new ObservableCollection<bool>(new bool[6]);
      23. }
      24. public void setTime(bool[] h, bool[] m, bool[] s)
      25. {
      26. for (int i = 0; i < 6; i++)
      27. {
      28. this.h[i] = h[i];
      29. this.m[i] = m[i];
      30. this.s[i] = s[i];
      31. }
      32. }
      33. public bool[] toBinary(int time)
      34. {
      35. int tempTime = time;
      36. bool[] bits = new bool[6];
      37. for (int i = 0; i < 6; i++)
      38. {
      39. if ((tempTime / (1 << (5 - i))) == 1)
      40. {
      41. bits[i] = true;
      42. tempTime -= (1 << (5 - i));
      43. }
      44. else
      45. bits[i] = false;
      46. }
      47. Array.Reverse(bits);
      48. return bits;
      49. }
      50. public void act(DateTime time)
      51. {
      52. setTime(toBinary(time.Hour), toBinary(time.Minute), toBinary(time.Second));
      53. }
      54. }



      hab die Klasse wieder anders benannt weil der Name doch besser passt ^^
      Wenn du in einer Property nichts machst, außer zurückgeben, dann vereinfache sie:

      C#-Quellcode

      1. public ObservableCollection<bool> H { get; private set; }
      2. public ObservableCollection<bool> M { get; private set; }
      3. public ObservableCollection<bool> S { get; private set; }
      4. public ZeitSpeicher()
      5. {
      6. this.H = new ObservableCollection<bool>(new bool[5]);
      7. this.M = new ObservableCollection<bool>(new bool[6]);
      8. this.S = new ObservableCollection<bool>(new bool[6]);
      9. }
      »There's no need to "teach" atheism. It's the natural result of education without indoctrination.« — Ricky Gervais
      Ja, so ist doch schon ziemlich schick.
      Nur wird das nicht failen, wenn der setTime-Zähler bis 6 zählt, die H-Collection aber nur 5 Elemente enthält?
      Und beguck dir nochmal genau, wie ich die public Properties formuliert hab: public get; private set; und gut ist.
      Dein BackingField ist einfach derselbe Buchstabe wie die Property, nur klein geschrieben. Solch ist nicht nett zu Code-Convertern, die das etwa nach vb übersetzen wollen, wo klein/groß-Schreibung gar kein Unterschied ist.
      Guck dir auch meine Bit-Operationen an: Ich benötige keine Teilung - ich checke einfach, obs > 0 ist oder nicht, und das ist ja bereits eine boolsche aussage (oder nicht? ;) )
      Also dann hat der Thread ja seinen Dienst getan ^^

      für alle die gerne den Sourcecode hätten, die Projektmappe ist im Anhang.
      Ich werde das ganze dann auch bei gelegenheit für Windows (Phone) umsetzen, eventuell als Lockscreen-App oder so :D

      mfg nxtman
      Dateien
      • BinaerUhrMVVM.rar

        (120,11 kB, 76 mal heruntergeladen, zuletzt: )
      wie gesagt: ist nicht schick, dasselbe ItemTemplate 3 mal zu notieren. Pack das in die Resource, und lass die Listboxen drauf verweisen - bei mir sind die Listboxen jeweils nur ein Einzeiler im Xaml:

      XML-Quellcode

      1. <ItemsControl hlp:GridEx.Range="c2" ItemsSource="{Binding Path=Minutes}" ItemTemplate="{StaticResource BitItem}" />
      Jep, danke für die Erinnerung :)

      Uhr.xaml

      XML-Quellcode

      1. <Window x:Class="BinaerUhrMVVM.MainWindow"
      2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      4. xmlns:vm="clr-namespace:BinaerUhrMVVM.ViewModel"
      5. xmlns:cnv="clr-namespace:BinaerUhrMVVM.Converters"
      6. Title="Binär-Uhr" Height="220" Width="140" KeyboardNavigation.TabNavigation="None" MinWidth="140" MinHeight="220" WindowStyle="ToolWindow" ResizeMode="NoResize" >
      7. <Window.Resources>
      8. <vm:UhrModel x:Key="uhr" />
      9. <cnv:Converter x:Key="boolToBrushConverter" />
      10. <DataTemplate x:Key="dataTemplate">
      11. <Border Height="{Binding Width, RelativeSource={RelativeSource Self}}" Width="25" HorizontalAlignment="Stretch" Padding="4">
      12. <Border Background="{Binding BindsDirectlyToSource=True, Converter={StaticResource boolToBrushConverter}}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
      13. </Border>
      14. </DataTemplate>
      15. </Window.Resources>
      16. <StackPanel Orientation="Vertical" DataContext="{StaticResource uhr}" Width="110">
      17. <Grid Height="25">
      18. <Grid.ColumnDefinitions>
      19. <ColumnDefinition Width="25" />
      20. <ColumnDefinition Width="*" />
      21. <ColumnDefinition Width="*" />
      22. <ColumnDefinition Width="*" />
      23. </Grid.ColumnDefinitions>
      24. <TextBlock Grid.Column="1" Text="h" TextAlignment="Center" VerticalAlignment="Bottom"/>
      25. <TextBlock Grid.Column="2" Text="m" TextAlignment="Center" VerticalAlignment="Bottom"/>
      26. <TextBlock Grid.Column="3" Text="s" TextAlignment="Center" VerticalAlignment="Bottom"/>
      27. </Grid>
      28. <Grid>
      29. <Grid.ColumnDefinitions>
      30. <ColumnDefinition Width="25" />
      31. <ColumnDefinition Width="*" />
      32. <ColumnDefinition Width="*" />
      33. <ColumnDefinition Width="*" />
      34. </Grid.ColumnDefinitions>
      35. <ItemsControl Background="{x:Null}" BorderBrush="{x:Null}">
      36. <Label Content="1" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Height="25"/>
      37. <Label Content="2" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Height="25"/>
      38. <Label Content="4" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Height="25"/>
      39. <Label Content="8" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Height="25"/>
      40. <Label Content="16" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Height="25"/>
      41. <Label Content="32" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Height="25"/>
      42. </ItemsControl>
      43. <ItemsControl Grid.Column="1" ItemsSource="{Binding time.H}" Background="{x:Null}" BorderBrush="{x:Null}" ItemTemplate="{StaticResource dataTemplate}" />
      44. <ItemsControl Grid.Column="2" ItemsSource="{Binding time.M}" Background="{x:Null}" BorderBrush="{x:Null}" ItemTemplate="{StaticResource dataTemplate}" />
      45. <ItemsControl Grid.Column="3" ItemsSource="{Binding time.S}" Background="{x:Null}" BorderBrush="{x:Null}" ItemTemplate="{StaticResource dataTemplate}" />
      46. </Grid>
      47. </StackPanel>
      48. </Window>

      dem DataTemplate noch den Datentyp mitteilen, sonst ist MVVM: "Binding-Picking" im Xaml-Editor nicht verfügbar.

      Und noch eine schöne Übung wäre, wenn du auch die DataTrigger-Variante umsetzen tätest.
      Hier sogar besonders vorteilhaft, dann kannste nämlich deinen BoolBrushConverter wieder abschaffen - das wäre eine deutliche Vereinfachung.
      Ist eh nicht so schön, dass die Farben nicht im Xaml ersichtlich sind, sondern in diesem SpezialConverter versteckt.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()