Laden...

Forenbeiträge von NOFX Ingesamt 42 Beiträge

20.07.2020 - 17:34 Uhr

Hi, danke für die schnelle Antwort. Die Klasse und als welche Collection oder List es gecastet wird, ist eigentlich egal. Hauptsache wird kommen auf die einzelnen Objekte und können über den Property-Namen auf die Werte der einzelnen Felder zugreifen.

20.07.2020 - 16:05 Uhr

Hi, ich hoffe ihr könnt mir bei meinem Problem helfen:

Wir entwickeln gerade ein UserControl, dass eine ObservableCollection einer beliebigen Klasse als DP bekommt und zugehörig dazu - ebenfalls als DP - eine Liste, welche Properties (als Strings) der Klassenobjekte jeweils dargestellt werden sollen.

Das Problem, dass wir jetzt haben, wie die DP gestaltet sein soll, um alle verschiedenen Klassen zu akzeptieren. Wir nutzenaktuell ein object, dass dann in eine ObservableCollection gecastet werden muss und verzweifeln da gerade dran.

        public object Data
        {
            get { return ((object)GetValue(DataProperty)); }
            set { SetValue(DataProperty, value); }
        }

        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(TestControl), new PropertyMetadata(null, new PropertyChangedCallback(DataChanged)));

        private static void DataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var tmp = ((TestControl)d).Data;
        }

Gibt es dafür eine einfache Lösung oder macht eine ganz andere Herangehensweise?

18.06.2018 - 11:24 Uhr

Danke für die Antwort! Ich habe die Bildchen jetzt als DataTemplates (mit dem Grid jeweils drin) angelegt und gehe über den DataTrigger im Style und ändere das ContentTemplate:

<ItemsControl ItemsSource="{Binding Geometrien}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding}">
                <ContentControl.Style>
                    <Style TargetType="{x:Type ContentControl}">
                        <Setter Property="ContentTemplate" Value="{StaticResource KreisBild}"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=CoolStripZoneType}" Value="1">
                                <Setter Property="ContentTemplate" Value="{StaticResource RechteckBild}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentControl.Style>
            </ContentControl>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
15.06.2018 - 14:06 Uhr

Hi MrSparkle,

danke schonmal für die schnelle Antwort!

Sowohl Namen als auch der Sinn der Klasse sind nur beispielhaft und ergeben nicht unbedingt Sinn. 😃

Eine Unterscheidung durch unterschiedliche Klassen ist nicht möglich.

D.h. der DataTrigger wäre wohl der richtige. Ich kenne den nur in Kombination mit Styles. Hier möchte ich ja das DataTemplate komplett ändern bzw. eben ein WPF-Bildchen (als Grid gekapselt) anzeigen.

D.h. ich habe eigentlich zwei Fragen, wie kriege ich überhaupt ein Grid (x:Key="KreisBild",...) aus den Resources angezeigt (wie das sonst mit Styles geht ist mir klar) und wie mache ich das in Kombination mit einem DataTrigger.

15.06.2018 - 12:03 Uhr

Ich habe eine Liste mit Elementen, die eine Eigenschaft vom Typ int/enum besitzen. Also vereinfacht z.B. sowas:


    public enum Typen
    {
        Kreis= 0,
        Rechteck = 1,
        Dreieck = 2
    }

Die Liste sieht dann so aus:


        private List<Geometrie> _Geometrien;
        ...

        public List<Geometrie> Geometrien
        {
            get { return _Geometrien; }
            set { _Geometrien = value; RaisePropertyChangedEvent("Geometrien"); }
        }
        ...
    }

Und die zugehörige Klasse:

    
    public class Geometrie : ObservableObject
    {
        private Typen _Typ;
        ...

        public Typen Typ
        {
            get { return _Typ; }
            set { _Typ = value; RaisePropertyChangedEvent("Typ"); }
        }
        ...
    }

Ich möchte jetzt in meiner Oberfläche diese Geometrien nebeneinander anzeigen und haben mir ein Dictionary mit passenden "Bildchen" (x:Key="KreisBild",...) als Grids angelegt. Meine Idee war das Ganze über ein ItemsControl zu machen, das eine horizontale StackPanel besitzt:


                        <ItemsControl ItemsSource="{Binding Geometrien}">
                            <ItemsControl.ItemsPanel>
                                <ItemsPanelTemplate>
                                    <StackPanel Orientation="Horizontal" />
                                </ItemsPanelTemplate>
                            </ItemsControl.ItemsPanel>
                            <ItemsControl.ItemTemplate>
                                <DataTemplate>
                                    <Rectangle Height="20" Width="20" Stroke="Black" />
                                </DataTemplate>
                            </ItemsControl.ItemTemplate>
                        </ItemsControl>

Wie bekomme ich jetzt hin, dass passend zum Typ des Objekts das entsprechend Bild eingebunden wird? Ich habe schon mit DataType im DataTemplate gearbeitet aber hier sind ja alle Objekte vom gleichen Typ und sollen anhand des Eigenschaftswertes unterschieden werden.

06.06.2018 - 10:40 Uhr

Es werden nicht immer alle Properties der Klasse genutzt und teilweise die gleiche Methode später noch mal aufgerufen, daher wird das per Reflections wohl nicht so schön.

Ein weitere Vorteil ist für mich speziell, da es sich fast durchgängig um double-Werte handelt, dass eine teilweise notwendige Skalierung direkt mit im Aufruf ersichtlich wird (so wie es aktuell beim erzeugen der temporären Listen auch ist). Via Reflections müsste diese dann ja zusätzlich übergeben werden.

Auf jeden Fall allen schon mal einen herzlichen Dank für die schnellen Antworten und konstruktive Diskussiopn! 👍

05.06.2018 - 08:17 Uhr
List<string> names = listA.Select(ca => ca.Name);  

Das wird so nicht funktionieren, die Select-Methode gibt ein IEnumerable zurück 😛
Da wird also auch nichts kopiert oder eine neue Liste erstellt. Hast Du hier ein ToList vergessen? Das brauchst Du nicht, wenn Du direkt IEnumerable verwendest.

Ja, das habe ich vergessen. Aber direkt IEnumerable zu nutzen macht Sinn.

Warum willst Du das denn in die Methode rein ziehen? Sind vor dem Select noch andere LINQ-Aufrufe (z.B. Where) nötig, die sich immer wiederholen?
Wenn nicht, würde ich das so lassen, Du baust dir sonst auf lange Sicht nur eine hässlichere Variante von LINQ nach.

Aber wenn Du das aber unbedingt haben willst:

var tmp = DoSomething(listA, a => a.Name);  
  
object DoSomething<TSource, TValue>(IEnumerable<TSource> source, Func<TSource, TValue> getValue)  
{  
    var data = source.Select(getValue);  
  
    // ...  
}  

Danke! Genau sowas habe ich gesucht, Func zu nutzen statt über die PorpertyInfo zu gehen.

Mir wäre es so lieber, damit bin ich flexibler:

var tmp = DoSomething(listA.Select(a => a.Name));  
  
object DoSomething<T>(IEnumerable<T> source)  
{  
    // ...  
}  

Meine erste Frage wäre, was ist der Zweck des Ganzen?
Willst du dir Tipparbeit ersparen oder soll hier ein spezifischer Zweck abgedeckt werden?
Mit Reflections sollte man arbeiten, wenn man weiß was man macht.

Mir ist auch nicht klar, in wie weit der gewünschter Ansatz den Code lesbar machen soll.
Damit würdest du die Funktion deines Codes mehr verschleiern als es nützt.
Deine Daten in einer Klasse zu kapseln ist absolut im Sinne der OOP.
Dies zu verwerfen würde die Lesbarkeitverschlechtern, da niemand außer dir verstehen kann warum dort der Code umgesetzt ist wie er aktuell ist.
Wenn du den Code in 1-2 Jahren oder gar Monaten mal wieder verstehen willst, machst du es dir damit extra schwer.

Es sind viele Properties (ca. 50) die jeweils in zwei Listen des gleichen Typs vorhanden sind und auf die die Methode angewandt wird.

Real sieht das dann eher so aus:


List<ClassA> valuesForward0 = listAForward.Select(ca => ca.Property0).ToList();
List<ClassA> valuesBackward0 = listABackward.Select(ca => ca.Property0).ToList();

result0 = DoSomething(valuesForward0, valuesBackward0, defaultValue0);

Das 5 zig mal ist nicht unbedingt übersichtlich und jedesmal die temporären Listen zu erstellen ist imho auch nicht sehr übersichtlich. Da ist die Variante doch deutlich angenehmer:


result0 = DoSomething(listAForward, listABackward, ca => ca.Property0, defaultValue0);

04.06.2018 - 14:49 Uhr

Hi, wahrscheinlich tue ich mich gerade einfach viel zu schwer für dieses einfache Problem:

Ich möchte Daten aus Listen verarbeiten, die in verschiedenen Listeneinträgen abgelegt sind. Die bisherige Lösung ist aktuell, dass ich per LinQ und Select zuerst einmal die einzelnen Eigenschaften in eine Liste packe und die an meine Methode übergebe. Also so in etwa:


class Class A
{
    public string Name { get; set;}
    ...
}


List<ClassA> listA = new List<ClassA>() { new ClassA() {....},...};

List<string> names = listA.Select(ca => ca.Name);
var tmp = DoSomething(names);

Mein Wunsch wäre jetzt das Ganze universeller und ohne die temporären Listen machen zu können also in etwa so:


List<ClassA> listA = new List<ClassA>() { new ClassA() {....},...};

var tmp = DoSomething( listA, "Name");

Wenn ich Reflections nutzen wollen würde wäre das machbar und man findet einige Lösungen dazu aber das muss doch auch eleganter und performanter machbar sein.

23.02.2018 - 10:21 Uhr

Ich würde das mit einer einzigen Collection machen, in der alle Properties drin sind.

Dann würde ich die ItemSource der zweiten ComboBox an das SelectedItem der ersten binden und einen Converter bauen, der die auf dieser Basis die Elemente für die zweite filtert (z.B. per LINQ).

25.01.2018 - 09:03 Uhr

Ich würde gerne in einem DataGrid mit gruppierten Daten in den Untergruppen erstellen also kaskadiert zuerst nach der erster Eigenschaft gruppiert und dann nach der zweiten. Wie ich Summen einzelner Spalten und Gruppen bekomme, habe ich mittels Konverter gelöst und das passt auch. Orientierthabe ich mich hieran: https://docs.microsoft.com/de-de/dotnet/framework/wpf/controls/how-to-group-sort-and-filter-data-in-the-datagrid-control für die Template der Ober- und Untergruppen.

Meine Frage ist jetzt: Wie kann den in dem Beispiel gezeigten hellblauen Header der Untergruppe unter die Elemente platzieren?

Ich habe versucht hier ebenfalls einen Expander zu platzieren oder ein Dockpanel, in dem ich den Header an den Bottom fixiere aber all das geht im DataTemplate des HeaderTemplate nicht.

Wahrscheinlich ist das ganz einfach aber ich stehe da auf dem Schlauch...

Deshalb schon jetzt Danke für die Antworten!

26.07.2017 - 11:02 Uhr

Hallo,

für eine Standalone-Anwendung entwickele ich gerade auf Basis von UWP eine App für Windows IoT auf einem Minnowboard, die über den UART und einem Pegelwandler RS485 zur Kommunikation nutzen soll.

Wenn ich in der App direkt Windows.Devices.Enumeration und Windows.Devices.SerialCommunication einbinde kann ich mit dem folgenden Code auf die seriellen Ports zugreifen, wenn ich diesen Codeabschnitt jedoch in einen Klassenbibliothek verschiebe, geht dies nicht mehr.

        public async void Connect()
        {
            string aqs = SerialDevice.GetDeviceSelector();
            DeviceInformationCollection dis = await DeviceInformation.FindAllAsync(aqs);
            var comPorts = new List<SerialDevice>();
            foreach (DeviceInformation di in dis)
            {
                comPorts.Add(await SerialDevice.FromIdAsync(di.Id));
            }
        }

Dieses Verhalten liegt wohl an den Capabilites, die ich für die App gesetzt habe, die jedoch nicht in die Klassenbibliothek weitergereicht werden:

  <Capabilities>
    <DeviceCapability Name="serialcommunication">
      <Device Id="any">
        <Function Type="name:serialPort" />
      </Device>
    </DeviceCapability>
  </Capabilities>

Hat hier vielleicht schon jemand mit dem selben Problem zu tun gehabt und ein passende Lösung?

03.01.2017 - 10:11 Uhr

Danke! Das hat perfekt funktioniert mit der RelativeSource:

<Surface:Surface2D Maximum="{Binding DataContext.MaximumMVW, BindsDirectlyToSource=True, FallbackValue=30, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ViewModel:MainWindow}}}"/>
03.01.2017 - 09:13 Uhr

Ok, ich habe das jetzt auf ein View mit CodeBehind begrenzt und kein ViewModel mehr. Dadurch habe ich das Problem mit dem Updaten des ViewModels aus dem CodeBehind beim Setzen der DPs nicht mehr.

Allerdings kriege ich bei dem Binding im MainWindow das Problem, dass das UserControl seinen eigenen DataContext besitzt und ich gerade auf dem Schlauch stehe, wie ich beim Binding auf das ViewModel des MainWindows zugreife. Hier der XAML Code:

<Surface:Surface2D Maximum="{Binding MaximumMVW, BindsDirectlyToSource=True, FallbackValue=30}"/>

MaximumMVW ist die Maximum Property im MainViewModel, es wird aber der DataContext des UserCOntrols verwendet, indem diese Property natürlich nicht definiert ist.

30.12.2016 - 14:22 Uhr

Mein ViewModel hat keine DPs, das möchte ich auch nicht. Ich registriere die DPs in der xaml.cs, möchte nur eben die Werte auch im ViewModel verwenden können.

Kann ich auf die Werte sauber zugreifen? Vom ViewModel aus ist ja die View nicht bekannt, worin die DPs registriert wurden.

Als Workaround habe ich das so gelöst, dass ich im ViewModel eine gleichlautende Property zu jeder DP im View erstellt habe und über den PropertyChangedCallback die Werte im VM aktualisiere. Das ist aber nicht wirklich sauber:

        public double Maximum
        {
            get { return (double)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }

        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(double), typeof(Surface2D));//, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnPropertyChanged)));

        private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            ((Surface2DViewModel)((Surface2D)sender).DataContext).GetType().GetProperty(args.Property.Name).SetValue(((Surface2DViewModel)((Surface2D)sender).DataContext), ((Surface2D)sender).GetValue(args.Property));
        }
30.12.2016 - 11:36 Uhr

Mir geht es nicht primär um die Dependancy Properties; davon habe ich gerne mehrere, die optional übergeben werden.

Nur wo packe ich die DP am besten hin (geht ja wohl nur im xalm.cs??) und wie mache ich die die saubere Kommunikation mit dem ViewModel? Im xaml.cs komme ich ja über den DataContext an das ViewModel aber ist das sauber und komme ich irgendwie sauber an die Daten der DPs aus dem ViewModel?

29.12.2016 - 11:49 Uhr

Hallo,

ich möchte zum darstellen von Daten ein UserControl erstellen, dass sauber nach MVVM aufgebaut ist und ein eigenes ViewModel besitzt, allerdings auch Dependancy Properties, damit ich bei der Einbindung im XAML Werte wie das Maximum etc. per Binding setzen kann.

Bislang sieht es so aus, dass ich im XAML.cs die Dependancy Properties erstelle:

        public int Maximum
        {
            get { return (int)GetValue(MaximumProperty); }
            set { SetValue(MaximumProperty, value); }
        }

        public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", typeof(int), typeof(Surface2D), new FrameworkPropertyMetadata(new PropertyChangedCallback(MaximumPropertyChanged)));


        private static void MaximumPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
             // do something
        }

und im ViewModel (von INotifyPropertyChanged abgeleitet) die restlichen Properties, für das View erstelle. Auf die Dependancy Properties kann ich im View dann auch zugreifen, wie z.B. so (der Name des View ist einfach userCOntrol):

<TextBlock Text="{Binding Maximum, ElementName=userControl}"/>

Meine Frage ist jetzt, wie ich das sauber hinbekomme ohne an zwei verschiedenen Stellen Daten halten und pflegen zu müssen. Gerade weil ich in Anhängigkeit einiger Dependancy Properties auch Werte für das ViewModel generieren möchte, ist das so ja arg unschön.

29.12.2016 - 10:14 Uhr

Breit mit StrokeEndLineCap="Triangle" zeichnen, mit noch breiterer Linie mit StrokeEndLineCap="Flat" übermalen und dann den eigentlichen Arc mit normaler Breite wieder drüber zeichnen, wäre eine Möglichkeit, so wie hier:

<Line X1="15" Y1="75" X2="35" Y2="25" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Triangle"  StrokeThickness="10" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Line X1="15" Y1="75" X2="35" Y2="25" Stroke="White" StrokeStartLineCap="Round" StrokeEndLineCap="Flat"      StrokeThickness="20" HorizontalAlignment="Left" VerticalAlignment="Top"/>
<Line X1="15" Y1="75" X2="35" Y2="25" Stroke="Black" StrokeStartLineCap="Round" StrokeEndLineCap="Triangle"  StrokeThickness="1"  HorizontalAlignment="Left" VerticalAlignment="Top"/>
17.10.2016 - 18:55 Uhr

So, ganz bei dem Stand, dass ich deinen Konverter einsetzen kann, bin ich noch nicht.

Ich habe jetzt ein ItemViewModel mit einem Objekt, in dem die verschiedenen ViewModels der einzelnen Items gespeichert werden. Die Überprüfung, um was es sich handelt, geht das über "is xyzViewModel". Mit einzelnen überlagerten Views kriege ich das sauber hin, hier habe ich einfach die Visibility genutzt, wie oben bereits erwähnt.

Die Views kann ich jetzt natürlich auch als Grid mit Key in einem ResourceDirectory speichern, also viel habe ich noch nicht in die falsche Richtung gearbeitet.

Ich habe immer nur ein Element ausgewählt und daher auch nur ein ViewModel, was ich weiterreichen kann/möchte. Deine Antwort habe ich so verstanden, dass ich im MainViewModel alle ViewModels brauche und die in die ItemsControl packe?

14.10.2016 - 14:24 Uhr

Danke für die umfangreiche Antwort! Ich versuche gerade alles nachzuvollziehen/verstehen. 😉

Vielleicht noch als Info: Die Views/ViewModels für die verschiedenen Blöcke sind alle sehr unterschiedlich, manche haben nur einen Wert, andere mehrere Kennlinien o.ä..

14.10.2016 - 10:04 Uhr

Ich bin gerade dabei eine kleine Anwendung zum Zeichnen von Signalflussplänen auf Basis dieses Projekts (WPF Diagram Designer - Part 4) aufzubauen. Hier werden in einzelne Expander (und darin eine definierte untergeordnete Toolboxen, die von ItemsControl abgeleitet sind) Elemente aus eine einem ResourceDictionary hinzugefügt.

Ich würde dies gerne etwas dynamischer aufbauen und nicht alle Elemente in einem ResourceDictionary (pro Expander) definieren.

Meine Idee ist, dass jeder Block ein eigenes Symbol (als Grid hinterlegt?), ein eigenes UserControl (View) und eine eigene Klasse zur Datenhaltung (ViewModel) bekommt.

Zum Programmstart sollten dann (per Code?) alle Symbole zu den Expandern (bzw. den darin enthaltenen Toolboxen/ItemsControl) hinzugefügt werden.

Meine Fragen sind jetzt:
Macht das so überhaupt Sinn (Hinzufügen via Code)?
Wie kann ich über einen Key aus einem ResourceDictionary ein Element per Code hinzufügen (das reine Hinzufügen ist klar, nur wie komme ich an das Element)?
Macht es Sinn alle Views immer zu laden und dann einfach per Visibility nur anzuzeigen, wenn ein zugehöriges Element geladen ist?

07.06.2016 - 13:55 Uhr

Das ist ja eine einfache Erklärung des Problems. 😃

Was wäre denn dann die sinnvollste Variante, das zu umgehen? Gibt es das Problem auch mit ListView oder ListBox o.ä.?

07.06.2016 - 13:38 Uhr

Dank der hilfreichen Tipps von ErfinderDesRades habe ich jetzt in meinem aktuellen Projekt komplett auf ObservableCollections statt Listen umgestellt. Jetzt tritt jedoch bei einer OC, die nur floats enthält das Problem auf, dass bei Änderung der Werte im DataGrid immer der oben genannte Fehler auftritt. Sowohl die verschiedenen Modes noch das Einfügen/Weglassen vom Path im Itemsource bringen eine Änderung.

Das OC als Property, aus der korrekt ausgelesen/angezeigt wird:

public ObservableCollection<float> TransStageList
        {
            get { return _TransStageList; }
        }

Diese wird initial befüllt:

_TransStageList = new ObservableCollection<float> { 800.0f, 1200.0f, 0.0f, 0.0f, 0.0f };

So sieht das im XAML aus:

                    <DataGrid Grid.Column="0" Grid.Row="4" ItemsSource="{Binding Path=TransStageList}" AutoGenerateColumns="False" Height="140" Width="Auto" Margin="5" RowBackground="White" AlternatingRowBackground="LightGray" CanUserAddRows="False" VerticalAlignment="Center" HorizontalAlignment="Center">
                        <DataGrid.CellStyle>
                            <Style TargetType="{x:Type DataGridCell}">
                                <Setter Property="HorizontalAlignment" Value="Right"/>
                            </Style>
                        </DataGrid.CellStyle>
                        <DataGrid.Columns>
                            <DataGridTextColumn Binding="{Binding Path=., StringFormat='F1'}">
                                <DataGridTextColumn.Header>
                                    <TextBlock TextWrapping="Wrap" TextAlignment="Center">Transistion<LineBreak/>Stage</TextBlock>
                                </DataGridTextColumn.Header>
                            </DataGridTextColumn>
                        </DataGrid.Columns>
                    </DataGrid>

Gleicher Aufbau im DataGrid klappt mit OCs mit Objekten problemlos, nur hier bei float gibt es Probleme.

03.06.2016 - 12:43 Uhr

Ich habe ja jetzt alles eigentlich sauber mit Get und Set und ohne manuelle PropertyChange-Events.

Einzig das neu Erzeugen der OC in CalculateAbcForView ist vielleicht nicht das schönste. Das könnte ich über die von dir vorgeschlagenen IDs noch ändern, sodass ich in der AbcForView nur das passende Element ändern muss. Dafür muss ich aber die ABC-Klasse schon wieder anpassen, was ich eher vermeiden möchte.

03.06.2016 - 12:15 Uhr

Jetzt brauche ich das auch nicht mehr manuell auszulösen. Ich starte im Eventhandler die Neuberechnung und durch die Zuweisung wird das im Setter dann ja automatisch erledigt. So spare ich mir auch das ständige Erzeugen einer neuen OC.

Eventhandler:

        private void ABCViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (sender.GetType() == typeof(ABC))
                AbcForView = CalculateAbcForView();
        }

Porperty:

        public ObservableCollection<abcDXYVis> AbcForView
        {
            get { return _AbcForView; }
            set { _AbcForView = value; RaisePropertyChangedEvent("AbcForView"); }
        }

Interne Variable:

private ObservableCollection<abcDXYVis> _AbcForView = new ObservableCollection<abcDXYVis>();

Und die Berechnung:

        public ObservableCollection<abcDXYVis> CalculateAbcForView()
        {
            ObservableCollection<abcDXYVis> abcForView = new ObservableCollection<abcDXYVis>();
            double scale = 0.225;
            for (int i = 0; i < 10; i++)
            {
                if ((_abcList != null) && (_abcList.Count > i))
                    abcForView.Add(new abcDXYVis() { Margin = new Thickness(-scale * _abcList[i].PositionX, -scale * _abcList[i].PositionZ, scale * _abcList[i].PositionX,  scale * _abcList[i].PositionZ),
                                      D = scale * _abcList[i].Diameter, Visible = Visibility.Visible });
                else
                    abcForView.Add(new abcDXYVis() { Visible = Visibility.Hidden });
            }
            return abcForView;
        }
03.06.2016 - 11:53 Uhr

Ich abonniere ja das Event der Elemente der einen OC (_abcList / AbcList) um manuell das Event der anderen (AbcForView) auszulösen.

Wenn ich das Event im Get (von AbcForView) auslösen würde, würde das ja eine Endlosschleife werden, weil das Event (im Get) alle Elemente der View (die an AbcForView gebunden sind) anstiften würde wieder das Get (von AbcForView) aufzurufen.

03.06.2016 - 10:55 Uhr

Auf etwas reagieren tut man üblicherweise, indem man das entsprechende Event abonniert.

Ah - du hast ja grad INotifyPropertyChanged implementiert - da täte sich doch anbieten, einfach das PropertyChanged-Event zu abonnieren, um zu reagieren, wenn eine Property sich ändert.
Weil INotifyPropertyChanged .PropertyChanged benachrichtigt (engl: to notify) einen doch, wenn eine Property geändert wurde.
👍

Ich habe jetzt in jeder neuen Instanz von ABC, die ich der _abcList hinzufüge, direkt das Event abonniert. Im EventHandler löse ich dann nach Überprüfung, ob das Objekt aus der passenden Klasse (ABC) stammt, auch wieder das Event aus, dass sich AbcForView geändert hat.

        private void ABCViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)  
        {  
            if (sender.GetType() == typeof(ABC))  
                RaisePropertyChangedEvent("AbcForView");  
        }  

Geht das noch eleganter, als für jede Instanz den Handler einzeln zuzuweisen?

Ich sehe, daß du jedes Mal innerhalb bei eine neue Instanz erstellst. Wäre mal nicht sooo schlimm.
Das was mir fehlt, ist die Stelle, an der diese 'AbcForView'-Property aktualisiert wird, z.Bsp.:

  
this.PropertyChanged(this, new PropertyChangedEventArgs("AbcForView"));  
  

Daher es nur ein getter ist, wäre das in diesem Fall unbedingt notwendig, sonst tut sich nie was, weil es eben NICHT die gleiche OC ist vom generischen Typ her UND weil du immer eine neue Instanz erstellst.
Das werde ich auch noch eleganter lösen und nicht jedes Mal eine komplett neue OC erstellen. Da ich ja im Eventhandler (s.o.) weiß, dass jetzt AbcForView neu erstellt werden muss.

02.06.2016 - 17:34 Uhr

Sorry, hatte das beim vereinfachen falsch ersetzt. Muss natürlich .D sein.

02.06.2016 - 15:28 Uhr

ich muss gestehen, wenn ich mich zum dritten mal wiederholen muss, wird es mir üblicherweise zu blöd.
Wieso machst du nicht einfach mal, was ich dir empfohlen habe? (INotifyPropertyChanged implementieren) OK, ich habe das jetzt so implementiert, dass sowohl ABC als auch abcDXYVis INotifyPropertyChanged implementieren. Jetzt habe ich begriffen, dass da kein Weg vorbei führt. 😉

Wie kriege ich jetzt die AbcForView (also die Property im ViewModel die Geometrien berechnet) dazu, ihrerseits die auf die Änderung einzelner Properties eines Elements von AbcList zu reagieren?

Ich benutze gerne
>
. Die Doku findest Du unter
>
.

Dann brauchst Du nur ein

[ImplementPropertyChanged]  

vor die Klasse setzen und jede public Property implementiert dann INotifyPropertyChanged automatisch... Danke für den Tipp, ich gucke mir das mal an!

02.06.2016 - 13:52 Uhr

Dann dürfte aber jetzt doch schon die Bindung des Durchmessers nicht funktionieren. Das geht ja offenbar über die OC, was mich ja auch wundert.

Ich versuche auf jeden Fall die Klasse ABC zu ändern aber eine - wenn auch unschöne - Übergangslösung wäre super.

Kann ich z.B. selber das PropertyChanged Event der OC (AbcList) abfangen und dann wiederum eines für AbcForView auslösen?

02.06.2016 - 13:29 Uhr

In der Oberfläche habe ich ja ein DataGrid aufbauend auf einer OC von dieser Klasse. Direkt an die Properties eines Elements der OC (also ein Property dieser Klasse) funktioniert die Datenbindung ja bereits.

Das sieht so aus:

        private ObservableCollection<ABC> _abcList = new ObservableCollection<ABC>();
...
        public ObservableCollection<ABC> AbcList
        {
            get { return _abcList ; }
            set { _abcList = value; }
        }

Daran kann ich direkt den Durchmesser binden:

<Ellipse Width="{Binding AbcList[0].Diameter}" Height="{Binding AbcList[0].Diameter}" Stroke="Black" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center""/>

Und der wird auch sofort aktualisiert, wenn ich im DataGrid etwas ändere.

Die Bindung wird aber nicht aktualisiert, wenn ich indirekt über eine zweite Property auf die gleichen Daten zugreife:


public ObservableCollection<abcDXYVis> AbcForView
        {
            get
            {
                ObservableCollection<abcDXYVis> abcForView = new ObservableCollection<abcDXYVis>();
                double scale = 0.225;
                for (int i = 0; i < 10; i++)
                {
                    if ((_abcList != null) && (_abcList.Count > i))
                        abcForView.Add(new abcDXYVis() { Margin = new Thickness(-scale * _abcList[i].PositionX, -scale * _abcList[i].PositionZ, scale * _abcList[i].PositionX,  scale * _abcList[i].PositionZ),
                                      D = scale * _abcList[i].Diameter, Visible = Visibility.Visible });
                    else
                        abcForView.Add(new abcDXYVis() { Visible = Visibility.Hidden });
                }
                return abcForView;
            }
        }
...
    public class abcDXYVis
    {
        public Thickness Margin { get; set; }
        public double D { get; set; }
        public Visibility Visible { get; set; }
    }

XAML:

<Ellipse Width="{Binding abcForView [0].D}" Height="{Binding abcForView [0].D}" Stroke="Black" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center""/>

Die Frage ist also, warum klappt das mit der Bindung im ersten Falle überhaupt, wenn ABC nicht von INotifyPropertyChanged abgeleitet ist und wie müsste ich das im zweiten Fall ändern, damit das funktioniert.

01.06.2016 - 15:04 Uhr

Die Klasse ist als Schnittstelle zwischen mir und einem Entwickler für die Oberfläche definiert worden. Da der aber nicht aus dem Quark kommt, wollte ich eine eigene für Test bauen. Deshalb bin ich jetzt weder der Fachmann für WPF noch ist von meiner Seite besonderer Wert darauf gelegt worden, die optimal für WPF zu gestalten.

Hier mal der wichtige Teil, bereinigt um alle hier unnötigen weiteren Instanzvariablen und Properties.


    public class ABC
    {
        public ABC()
            : base()
        {
        }

        #region Fields

        protected Single _Diameter;
        protected Single _PositionX;
        protected Single _PositionZ;

        #endregion Fields


        #region Properties

        public Single Diameter
        {
            get { return _Diameter; }
            set { _Diameter = value; }
        }

        public Single PositionX
        {
            get { return _PositionX; }
            set { _PositionX = value; }
        }

        public Single PositionZ
        {
            get { return _PositionZ; }
            set { _PositionZ = value; }
        }

        #endregion Properties
    }

Und vielen Dank schon einmal für die Hilfe!

31.05.2016 - 14:37 Uhr

Ja, genau.

Die OC für das DataGrid enthält Objekte eine Klasse mit mehreren single für die Durchmesser, Positionen und noch andere physikalische Werte (ebenfalls single). An der kann ich nichts ändern.

Die OC, die ich jetzt für die geometrischen Objekte nutze hat Obejkte einer Klasse mit den Elementen X, Y, (double), Margin (Thickness) und Visibel (Visibility). X, Y und Margin werden aus den Werten der ersten OC berechnet und die Visibel wird gesetzt, je nach dem, ob die weiteren Werte passen.

31.05.2016 - 14:29 Uhr

Ja klar, ich meine doch eine OC die Objekte enthält.

Jetzt verstehe ich auch, was du vorhin meintest. Leider kann ich die Klasse der Objekte nicht ändern. Diese ist vorgegeben und wird auch so im Model verwendet.

31.05.2016 - 14:07 Uhr

Mal kurz als Beispiel:

Das DataGrid enthält die Durchmesser und Mittelpunkte (zu einem gedachten Ursprung und diverses anderes) von Kreisen, ich stelle mir dann diese auf einem Canvas mit Elipsen dar, allerdings brauche ich dafür Durchmesser und absolute Position, die noch skaliert werden müssen.

Bisher erzeuge ich mir eine neue OC, die Margin und X und Y Position enthält. Umrechnung auf Binding sind ja nicht direkt durchführbar, deshalb bin ich den Weg gegangen.

An anderer Stelle benutze ich auch Daten aus einer OC einer ListView und erzeuge daraus einen 2D-Graphen (mittels SciChart) wofür ich auch eine Property passenden Typ (IDataSeries) habe, die an den Graphen gebunden ist. Auch hier wäre eine automatische Aktualisierung wünschenswert, nur kann ich hier definitiv nicht auf die ursprüngliche OC zurückgreifen.

31.05.2016 - 13:42 Uhr

Mit Geometrien meine ich Größe und Position von Elipsen.

In meiner ObservableCollection für das DataGrid sind relative Positionen, die ich umrechne und wieder als ObservableCollection für die geometrischen Objekte zur Verfügung stelle.

Ändere ich jetzt im DataGrid etwas, wird das korrekt in die Collection übernommen, nur wird das PropertyChanged Event ja nur für die erste Collection angestoßen, sodass die geometrischen Objekte sich nicht neu positionieren.

31.05.2016 - 13:22 Uhr

Um nicht direkt wieder ein neues Thema zu eröffnen: Ich habe jetzt in einem der UserControls ein DataGrid, in dem ich Daten anzeigen und ändern kann, die in einer ObservableCollection im ViewModel hinterlegt sind.

Die Frage ist jetzt: Ich nutze Daten aus dieser ObservableCollection um mir Positionen für geometrische Objekte zu berechnen, die ich wieder als Property im ViewModel zur Verfügung stelle. Wie kann ich das PropertyChanged Event der Geometrie auslösen, wenn sich die ursprüngliche ObservableCollection ändert?

Binde ich geometrische Eigenschaften direkt an die ObservableCollection des DataGrids klappt das jetzt schon, nur müssen diese i.A. noch umgerechnet werden.

30.05.2016 - 13:05 Uhr

In dem Beispiel ist nur ein DataContext gegeben. Grundsätzlich habe ich mehrere UserControls, die ja einen eigenen DataContrxt brauchen.

Ich habe jetzt ein MainViewModel erzeugt, indem ich die einzelnen ViewModels als Properties habe. Das funktioniert auf jeden Fall, danke für den Tipp, Rioma!

30.05.2016 - 10:34 Uhr

Bisher habe ich noch kein MainViewModel, da hier im Moment keine Daten o.ä. vorhanden sind.

Wie müsste die Auflistung darin denn aussehen? Hast du vielleicht ein Beispiel?

Danke und Gruß,
Fabian | NOFX

24.05.2016 - 15:37 Uhr

Hi,

ich versuche mich gerade an WPF mit MVVM und habe mich auf dieses Beispiel gestürzt, was halbwegs überschaubar eine - mMn - verständliche und gute Einführung ist: The World's Simplest C# WPF MVVM Example

Das Proble bei der Umsetzung habe ich jetzt damit, dass ich gerne mehrere Views mit unterschiedlichen DataContext erstellen würde, die alle auf Tabs in einem Fenster liegen. Hier wird jetzt "global" der DataContext mit

<Window.DataContext>
        <ViewModel:Presenter/>
    </Window.DataContext>

festgelegt. Eine Verschieben der Zuweisung des DataContext in den Aufruf des UserControls

<View:ConverterControl DataContext="ViewModel:Presenter"/>

bewirkt, dass es so auf jeden Fall nicht mehr funktioniert.

Wie kann ich also unterschiedliche UserControls als View mit jeweils eigenen DataContext nutzen?

14.12.2015 - 16:17 Uhr

Keiner eine Idee?

Im Explorer ist der Cursor nach dem Doppelklick auch dauerhaft mit dem Sanduhr-Symbol.

04.12.2015 - 10:59 Uhr

Enable just my Code ist aktiv.

Wo finde ich die Code Type Option?

Edit: Vielleicht noch als Info, auch ältere Projekte lassen sich nicht starten, die in früheren Versionen von VS erstellt wurden. Alle sind im Taskmanager sichtbar mit jeweils zwei oder dreistelligem KB Soehcerbedarf (116 KB, 112, 92,...). Ich habe fast das Gefühl, dass hier vielleicht das Virenprogramm oder der Defender bei der Überprüfung Mist bauen und die Exe nicht starten lassen.

04.12.2015 - 10:12 Uhr

Bei mir ist das Problem genauso vorhanden, die Exe-Dateien im Debug und Release lassen sich nicht starten. Auch bei mir werden die Prozesse im Task Manager angezeigt. Und auch bei mir gilt, dass es auf einem anderen Rechner (Win10) - nicht der Entwicklungsrechner (der hat Win7) aber ebenfalls mit VS - problemlos läuft.

Das Fenster wird definitiv nicht geöffnet, es liegt nicht auf einem anderen Bildschirm, es wird kein Symbol in der Taskleiste angezeigt.

Das Verhalten ist echt seltsam...