Laden...

Forenbeiträge von ByteDevil Ingesamt 132 Beiträge

18.01.2022 - 08:33 Uhr

Vielen Dank Abt,

das ist ein echter Jammer 🙁 Könnte man nicht versuchen 3 echte Routen manuell zu basteln, die bei einem GET dann einen Status 200 und als Content diese Dateien ausspucken? Leider fehlen mir hier etwas die Kenntnisse und auch Google hat mich nicht sehr weit gebracht. Unter ASP würde ich jetzt halt einfach 3 Controller hinzufügen...

17.01.2022 - 17:04 Uhr

Hi,

ich baue gerade eine Blazor-Anwendung die Clientside funktionieren soll (Web assembly). Darin kann man eine Zip-Datei angeben die dann ausgepackt und deren Inhalt ins Root-Verzeichnis gepackt wird:


MemoryStream ms ...
using (var zipArchive = new ZipArchive(ms))
    zipArchive.ExtractToDirectory(Directory.GetCurrentDirectory());

Führe ich folgendes aus:


var files = Directory.GetFileSystemEntries(Directory.GetCurrentDirectory());

... sehe ich das die Dateien dort liegen. Nun muss ich zwingend and diese Dateien über die URL kommen können. Das verlangt leider eine JS-Komponente die von einem Drittanbieter ist. Wie mache ich eine Route die diese Dateien exponiert? Die Dateien heißen immer gleich und es sind immer 3 Stück.

02.03.2021 - 11:28 Uhr

@Abt: Ja, es sind DIP's soweit ich weiß. Nennen wir es "Größeneinheiten"^^ Auf dem Screenshot ist aber zu sehen, dass die mittlere Row 3 mal so hoch ist wie die anderen beiden welche angeblich 19 Größeneinheiten hoch sind.

@Th69: Danke! MaxHeight hilft tatsächlich...dachte die zu setzen wäre sinnlos wenn ich doch einen festen Wert angebe.

02.03.2021 - 09:15 Uhr

Hi,

ich habe ein seltsames Problem. Bitte fügt mal folgenden Code in ein neues WPF-Fenster ein:


<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="8"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="8"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <TextBox Text="1234" Grid.Row="0" Grid.Column="0"/>
    <Border Grid.Row="1" Grid.Column="0" Background="Aqua"/> <!--Nur zur Visualisierung wie groß Row 1 ist-->
    <TextBox Text="1234" Grid.Row="2" Grid.Column="0"/>
    <Button Grid.Row="0" Grid.RowSpan="3" Grid.Column="2" Padding="0" Width="{Binding RelativeSource={RelativeSource Self}, Path=ActualHeight}" VerticalAlignment="Stretch">
        <Border Background="Red" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
            <StackPanel>
                <TextBlock Text="1234231312123123"/>
                <TextBlock Text="1234231312123123"/>
                <TextBlock Text="1234231312123123"/>
            </StackPanel>
        </Border>
    </Button>
</Grid>

Im Anhang ist ein Screenshot wie es bei mir aussieht. Bitte auch die Maßangaben der Rows auf der linken Seite beachten^^

Ich möchte die zwei TextBoxen in einem festen Abstand von 8 Pixeln übereinander haben. Rechts daneben soll ein quadratischer Button in einem Abstand von ebenfalls 8 Pixeln sein, dessen Höhe gleich dem beider Textboxen zusammen + deren Abstand ist. Nun wird aber die mittlere Row weit über 8 Pixeln auseinander gezogen...kann mir das wer erklären? Entferne ich den Inhalt des Buttons, ist es korrekt.

18.01.2021 - 18:51 Uhr

Ich möchte gern allen die das gleich Problem haben viel Kopfschmerzen ersparen. Anstatt der WPFApp Referenzen auf das Projekt zu geben, erstellt das Projekt auf das ihr verweisen wollt und fügt eine Referenz auf die DLL hinzu...nichts weiter. So geht es...

16.01.2021 - 20:47 Uhr

Korrekt. Brush != Color

Ein Brush kann vieles sein... zB ein GradientBrush der einen Farbverlauf darstellt.

16.01.2021 - 13:26 Uhr

Magst du mal mehr code posten? Hab es eben ausprobiert und es funktioniert bei mir genau so:

<Button Width="100" Height="20" Background="Red">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <Grid>
                <Rectangle Fill="{TemplateBinding Background}"/>
            </Grid>
        </ControlTemplate>
    </Button.Template>
</Button>

Bzw auch so:


<Window>
....
    <Grid>
        <Grid.Resources>
            <ControlTemplate x:Key="myBtn" TargetType="{x:Type Button}">
                <Grid>
                    <Rectangle Fill="{TemplateBinding Background}"/>
                </Grid>
            </ControlTemplate>
        </Grid.Resources>

        <Button Width="100" Height="20" Template="{StaticResource myBtn}"
                Background="Red"/>
    </Grid>
</Window>
16.01.2021 - 13:02 Uhr
<Grid>
    <Rectangle x:Name="btnForm" Fill="{TemplateBinding Background}"/>
</Grid>

sollte schon helfen, denke ich.

16.01.2021 - 12:31 Uhr

Hi,

ich habe eine Klassenbibliothek an einem bestimmten Ort...sagen wir
C:\Projects\WpfThemes.csproj
Darin liegt ein ResourceDictionary mit diversen styles in einem Unterordner:
C:\Projects\WpfThemes\Styles\StylesRS.xaml

Nun habe ich eine neue Wpf Application an einem anderen Ort. Sagen wir
C:\Projects\MeineWpfApp\MeineWpfApp.csproj

Jetzt möchte ich in in der App.xaml von MeineWpfApp StylesRS.xaml einbinden. Ich habe WpfThemes der Projektmappe hinzugefügt in der auch MeineWpfApp liegt. MeineWpfApp hat auch eine Referenz auf WpfThemes.

Im Netz finde ich immer diese Lösung:

pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

Also in meinem Fall:

pack://application:,,,/WpfThemes;component/Styles/StylesRS.xaml

Aber dann kriege ich eine XamlParseException mit der Inner Exception:
IOException: Die Ressource "styles/stylesrs.xaml" kann nicht gefunden werden.

Alles ist .Net5

Kann mir jemand sagen was ich falsch mache?

20.11.2020 - 11:01 Uhr

Vielen Dank für den Tipp. Ich stelle meine Nachforschungen aber nun ein. Wir haben aus anderen Gründen nun von .Net Framework 4.7 auf 4.8 migriert. Hier ist das Problem nicht mehr vorhanden. Das verwenden von DynamicResource hat keinen spürbaren Einfluss mehr. Offenbar hat MS da nochmal was verbessert.

18.11.2020 - 16:47 Uhr

Hallo,

der Titel klingt etwas komisch, ich weiß. Ich habe eine relativ große Anwendung die Verschiedene Themes unterstützt. Es gibt ein ResourceDictionary das sämtliche Styles und Templates beinhaltet. Dieses bindet dann ein weiteres ResourceDictionary in sich ein, wo die Farbcodes hinterlegt sind. Davon gibt es halt für jedes Theme eines. Möchte ich das Theme ändern, erzeuge ich das ResourceDictionary mit den Styles und Templates und packe dann das mit den gewünschten Farbcodes rein und weise es den Window.Resources zu. Möchte ich nun auf Farbwerte von aussen zugreifen, mache ich das mit DynamicResource, weil ich sonst die falsche Farbe kriege nachdem sich das Theme geändert hat.
Das funktioniert auch gut, nur habe ich jetzt ein solches DynamicResource in einem DataTemplate einer ListBox verwendet. Hier filtere ich die Items die angezeigt werden sollen mit einer Textbox in Echtzeit. Das ist unerträglich langsam wenn ich DynamicResource verwende...ersetze ich es durch ein StaticResource, funktioniert es tadellos.

Nun meine Frage: Im Moment wird jedes mal ein lookup nach diesem Farbwert vorgenommen, weil WPF ja davon ausgehen muss, dass sich diese DynamicResource jeder Zeit geändert haben kann. Tatsächlich möchte ich lieber StaticResource nutzen und WPF an einer einzigen Stelle sagen "Ruf mal bitte alle StaticResources neu ab" weil es sich nur ganz selten ändert. Geht das irgendwie? Wenn ich das nicht hinkriege, muss ich wohl oder übel die Farbe in meinem ViewModel für diesen speziellen Fall einmal abrufen und dann binden...ungern.

28.07.2020 - 09:42 Uhr

Hi,

Ich möchte einen neuen Button basteln, der ein paar mehr Anpassungsmöglichkeiten bietet als der Normale, ohne das man jedes mal ein neues Template machen muss. Daher habe ich den Button abgeleitet und möchte nun einen Impliziten Style mit einem Template machen. Hier habe ich das default-Template vom normalen Button genommen zwecks Übersichtlichkeit etwas beschnitten.

Ich habe eine neue DP eingebaut, die den Brush für den Foreground beinhaltet, wenn IsEnabled == false gesetzt wird.

ich habe hier mal ein Minimalbeispiel, welches mein Problem reproduziert:

MyButton Klasse:

public class MyButton : Button
    {
        public static readonly DependencyProperty DisabledForegroundProperty = DependencyProperty.Register(
            nameof(DisabledForeground), typeof(Brush), typeof(MyButton), new PropertyMetadata(Brushes.Gray));
        public Brush DisabledForeground
        {
            get => (Brush) GetValue(DisabledForegroundProperty);
            set => SetValue(DisabledForegroundProperty, value);
        }
    }

Style/Template:

<Style TargetType="{x:Type local:MyButton}">
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Background" Value="#FFDDDDDD"/>
            <Setter Property="BorderBrush" Value="#FF707070"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="DisabledForeground" Value="Red"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:MyButton}">
                        <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                            <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisabledForeground}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Das funktioniert nicht. Die Schriftfarbe ist dann immer schwarz.

Ändere ich den Trigger zu:


<Trigger Property="IsEnabled" Value="false">
      <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisabledForeground}"/>
</Trigger>

...geht es, solange der Button Content tatsächlich nur ein String ist. Habe ich da dann zb sowas hier drin:

<local:MyButton x:Name="TestButton" IsEnabled="False">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="123"/>
                    <Rectangle Width="16" Fill="{Binding ElementName=TestButton, Path=Foreground}"/>
                </StackPanel>
            </local:MyButton>

... funktioniert es nicht, weil ich in dem Trigger den Foreground vom Button selbst ja nie ändere...

Ist etwas anderes im Button Content, was sich am Foreground Binden soll, wird es nicht gefärbt.

Hat jemand eine Ahnung warum

<Setter Property="Foreground" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DisabledForeground}"/>

...nicht funktioniert? Ersetze ich das Binding durch eine Konstante, geht es...in der Ausgabe sind keine Binding-Errors zu sehen.

01.07.2020 - 12:04 Uhr

Update: Entschuldigt bitte...es funktioniert ganz genauso wie ich es beschrieben habe. Es war ein Fehler im Template selbst, der sich da reingeschummelt hat. Also kann man so machen wie ich, falls das jemandem weiterhilft. Danke 😃

01.07.2020 - 11:21 Uhr

@witte Hi und danke für die Antwort 😃 Mhhh 3rd Party-Libs würde ich da gern wenn möglich vermeiden. Das muss doch mit WPF-Boardmitteln möglich sein, oder? Aber ich behalte den Tipp im Hinterkopf.

01.07.2020 - 10:32 Uhr

Hi,

folgendes Szenario: In einer größeren Solution die aus vielen Projekten besteht (C++ code und UI, Windows Forms UI und nun auch WPF) soll es nun möglich sein, bei den neuen Programmteilen welche in WPF umgesetzt sind, zur Laufzeit zwischen einem Dark- und einem Light-Mode umzuschalten. Nun überlege ich gerade wie man das Ganze strukturieren kann, damit es später möglichst einfach wird die controls zu stylen und zu nutzen...hier kommen Standard WPF-Controls zum einsatz, sowie UserControls und CustomControls.

Meine Idee war:

Ich definiere von jedem Control zwei Styles (Light und Dark) und (wenn nötig) ein ControlTemplate, da das Template ja immer gleich sein soll. Sowohl das Template als auch jeder Style soll in ein eigenes ResourceDictionary... Das mit den Templates wird von jedem der Theme-ResourceDictionaries eingebunden und eines der beiden Themes wird dann von dem Window eingebunden. So wirken sich Änderungen an einem Template auf beide Themes aus.

Versuche in nun folgendes:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestProject">
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="ControlTemplates.xaml"/>
    </ResourceDictionary.MergedDictionaries>

    <Style TargetType="{x:Type local:MyButton}">
        <Setter Property="Background" Value="#494949"/>
        <Setter Property="Foreground" Value="#DEDEDE"/>
        <Setter Property="Template" Value="{DynamicResource MyButtonTemplate}"/>
    </Style>
</ResourceDictionary>

(ControlTemplates.xaml enthält erstmal nur ein ControlTemplate mit dem Key "MyButtonTemplate" mit dem TargetType "MyButton". MyButton ist ein CustomControl welches von Button erbt. Musste einige zusätzliche Properties einbauen)

und binde dieses ResourceDictionary nun in meine Window.Resources ein, bekomme ich folgende Exception direkt beim Start:

Fehlermeldung:
System.Windows.Markup.XamlParseException: "Zeilennummer "17" und Zeilenposition "48" von "Beim Festlegen der Eigenschaft "System.Windows.Setter.Value" wurde eine Ausnahme ausgelöst."."

Innere Ausnahme:
ArgumentException: Bei dem Ausdruckstyp handelt es sich nicht um einen gültigen Style-Wert.

Das Problem scheint beim Setter des Templates zu liegen. Kommentiere ich das aus, kracht es nicht mehr...natürlich ist dann von dem Control nichts zu sehen, weil kein Template da ist.

Compiliert prima und IntelliSense bzw. Resharper meckert auch nirgends.
Packe ich das Template direkt in den Setter und definiere es somit in dem Style, klappt alles ganz prima. Auch das umschalten zur Laufzeit. Dann habe ich das Template aber in jedem Theme einmal drin stehen und das obwohl es immer identisch ist. Das heißt ich muss immer beide anpassen wenn ich was ändere und es bläht die beiden Themes sehr auf. Das wollte ich so nur machen, falls es tatsächlich mal den Fall gibt, dass das Template sich in beiden Themes unterscheiden soll.

Ist das was ich da vor habe überhaupt möglich? Wenn ja was mache ich falsch?

Habe diesen oder einen ähnlichen Ansatz noch nirgends im Netz entdeckt.

10.06.2020 - 12:10 Uhr

Interessante Idee, doch das wird wohl nicht weniger Aufwand als den TypeConverter an jede Property zu schrauben. Auch ist es ja nicht nur der Aufwand...so faul bin ich nun auch wieder nicht 😄 Nur arbeite ich da nicht allein dran und die Wahrscheinlichkeit das jemand das dann nicht tut wenn eine Weitere Klasse dazu kommt ist recht hoch. Ich bräuchte also wirklich eine Möglichkeit das PropertyGrid selbst anzupassen... vielleicht kann man das Teil ableiten und irgendwas überschreiben? Das Teil muss ja irgendeinen Standard-TypeConverter oder so nutzen um double-Werte anzuzeigen... kann man das irgendwie abfangen?

Bin leider auch nicht so ganz fit was Windows Forms angeht...arbeite sonst nur mit WPF.

10.06.2020 - 11:13 Uhr

Hi,

ich muss eine Änderungsanforderung umsetzen. Es soll in einem PropertyGrid, wo unter anderem double Werte eingegeben werden können, ein Punkt statt einem Komma verwendet werden. Jetzt kenne ich zwei Möglichkeiten das umzusetzen: Die ThreadCulture ändern kommt schonmal nicht in Frage, weil das würde ja auch alles andere betreffen. Und sonst müsste man für jede Klasse und deren double-properties die man darin anzeigen möchte einen TypeConverter als Attribut vergeben, oder? Das wäre auch nicht so toll, da hier viele - und ich meine echt viele Klassen dran hängen.
Kennt ihr einen Weg wie ich ein PropertyGrid dazu kriege einfach einen Punkt statt ein Komma zu verwenden?

04.06.2020 - 14:20 Uhr

@witte ja schon, allerdings würde ich ungern nur wegen dieser einen Stelle eine neue Property machen, die ich sonst nirgends bräuchte. Das summiert sich halt von Fall zu Fall.

@dannoe Perfekt! An einen MultiDataTrigger in einem Style hab ich nicht gedacht. Das klappt! Danke

04.06.2020 - 08:09 Uhr

Hi,

ich habe gerade mal wieder eine solche Situation:

<ListBox Grid.Column="2" Grid.Row="1" Margin="0,3,0,0">
    <ListBox.Visibility>
        <MultiBinding Converter="{StaticResource BoolTrueForAllToBoolMultiValueConverter}">
            <Binding Path="PasteSweepPaths"/>
            <Binding Path="ChosenDrawing" Converter="{StaticResource NotNullToBoolConverter}"/>
            <Binding Path="ChosenDrawing.HasSimulationSweepPaths"/>
        </MultiBinding>
    </ListBox.Visibility>
</ListBox>

Wird so natürlich nicht funktionieren, da ich aus dem bool eine Visibility machen muss. Nur wie könnte ich das an dieser Stelle tun? Bei einem einfachen Binding würde ich einen ValueConverter nehmen, der mir aus einem False ein Visibility.Hidde bzw. Collapsed machen würde. Ich kann ja leider keine MultiBindings verschachteln...

Wie kann ich nur mit XAML die Listbox auf Visibility.Visible setzen, wenn in meinem ViewModel PasteSweepPaths == true, ChosenDrawing != null und ChosenDrawing.HasSimulationSweepPaths == true ist und sonst auf Collapsed?

26.02.2020 - 21:28 Uhr

Danke euch vielmals 😃 Das mit dem Shader wirkt etwas Hacky^^ Ich würde es gern zuerst mit der Opacity Mask versuchen. Allerdings kann ich mir das nicht so ganz vorstellen. Mit einer Opacity Mask kann ich doch regionen durchsichtig machen, oder?

Wenn ich dich richtig verstehe, schlägst du zwei TextBlöcke vor, die den selben Text haben und genau übereinander liegen. Einer hat weiße Schrift, der andere schwarze und dann soll ich sie irgendwie mit einer Opacity Mask sichtbar/unsichtbar machen?

24.02.2020 - 21:23 Uhr

Hi,

ich bastel gerade an einer WPF App (.net Core 3.1) im MVVM Pattern. Darin habe ich einen Progressbar, auf dem ich gern genauere Informationen zum Fortschritt anzeigen möchte. Das könnte ich einfach mit einem Textblock machen, der zusammen mit dem Progressbar in einem Grid liegt. Nun habe ich auch ein Theme für die ganze App geschrieben, was im Grunde auf heller Schrift auf dunklem Grund basiert. Mein Progressbar besteht aus einem Hellen Balken auf grauem Grund.

Nun möchte ich, dass der Text in Weiß angezeigt wird, wenn der Progressbar darunter grau ist und Schwarz wenn der Hintergrund Weiß ist. Das möchte ich für jeden einzelnen Buchstaben tun. Google konnte mir dabei leider nicht helfen. Habt ihr eine Idee wie ich das machen könnte?

Edit: Genau sowas hier suche ich: https://css-tricks.com/reverse-text-color-mix-blend-mode/

15.02.2020 - 17:46 Uhr

Hi,
ich habe hier einen Path den ich mit Gimp gezeichnet und Exportiert habe. Leider scheint er nicht mittig in dem Button zu sitzen. Könnt ihr mir sagen was ich hier falsch mache?


<Grid>
    <Button Background="Red" Height="32" Width="32">
        <Viewbox>
            <Path Data="M26,25C26,25 26,28 26,28 26,28 6,28 6,28 6,28 6,25 6,25 6,25 4,25 4,25 4,25 4,30 4,30 4,30 28,30 28,30 28,30 28,25 28,25 28,25 26,25 26,25z 
                    M14,4C14,4 18,4 18,4 18,4 18,23 18,23 18,23 23,20 23,20 23,20 24,22 24,22 24,22 16,27 16,27 16,27 8,22 8,22 8,22 9,20 9,20 9,20 14,23 14,23 14,23 14,4 14,4z" 
                    Fill="Black" Stroke="Black" StrokeThickness="0.1"/>
        </Viewbox>
    </Button>
</Grid>

Danke vielmals

Edit: Okay, Stretch vom Path einfach auf "Fill" setzen...warum auch immer. Danke trotzdem

15.02.2020 - 16:21 Uhr

Danke Abt,

ja aber ich hab etwas Probleme mir das vorzustellen.

15.02.2020 - 16:00 Uhr

Hi,

ich möchte Path-Geometrien für eigene Buttons und ähnlichem Zeichnen. Leider kann ich keine Möglichkeit finden, wie ich eine Art Raster einschalten kann, damit ich meine Pfad-Punkte korrekt und symmetrisch zeichnen kann.
Kann mir da wer helfen?

29.01.2020 - 16:29 Uhr

Naja, die Klasse ist gute 20 Jahre alt^^ Daran hat damals wohl noch keiner so richtig gedacht.

Okay, ich schaue mir die Doku nochmal genau an mit dem im Hinterkopf was du gesagt hast. Melde mich wenn ich Erfolg hatte.

Dankeschön

29.01.2020 - 16:19 Uhr

Achso meinst du das. Mhhh ja das geht zwar...aber ungern. Auf diese Klasse habe ich Zugriff, aber auch die ist nicht von mir und wird in einer gigantischen Software noch an (buchstäblich) hunderten weiteren Stellen genutzt. Möchte die ungern anpacken. Deshalb habe ich mir auch den bereits erwähnten ContractResolver geschrieben um einige der Properties zu ignorieren und habe nicht alles mit


[JsonIgnore]

geschmückt.

EDIT: Kann ich nicht deine Idee mit dem Converter und meine mit dem ContractResolver verheiraten? Also einen ContractResolver der diesen einen Converter nutzt, wenn er einen Vector3d vor die Flinte bekommt?

29.01.2020 - 16:14 Uhr

Hallo Abt,

danke für die Antwort. Nun ist mir leider nicht ganz klar, wie ich einer Klasse auf die ich keinerlei Zugriff habe mit einem Attribut versehen kann. Hilfst du mir bitte auf die Sprünge?

29.01.2020 - 16:07 Uhr

verwendetes Datenbanksystem: <Json>

Hi,

ich serialisiere Daten, speichere sie in einer Datenbank und hole sie bei Bedarf heraus und deserialisiere sie wieder. Dabei wird unter Anderem eine struct mit deserialisiert, welche nicht aus meiner Feder stammt. Darin enthalten sind 3 double Werte, über die ich nur über Properties komme. Diese haben leider nur einen Getter. Die Struktur verfügt über drei Konstruktoren:


Vector3d() // macht einen 0-Vektor
Vector3d(double x, double y, double z)
Vector3d(double [] xyz)

Newtonsoft.Json verwendet natürlich den Standardkonstruktor und verwirft die Werte dann halt einfach, weil sie nicht zugewiesen werden können.

So sieht der Json-String aus:


{
      "LargestElement": 0,
      "LengthSqrd": 5.0336,
      "Length": 2.2435685859808254,
      "Z": 1,
      "Y": 1.4,
      "X": 1.44
}

Ich muss Newtonsoft nun irgenwie dazu kriegen, den zweiten oder dritten Konstruktor mit den x, y und z-Werten zu nutzen.

Ich weiß, das ich das irgendwie über einen ContractResolver lösen kann. Ich nutze auch bereits einen bei der serialisation/deserialisation, wo ich spezielle Properties setze die generell ignoriert werden sollen. Nur habe ich nichts dazu gefunden, wie ich in diesen einen ContractResolver nun eine "Anleitung" für Newtonsoft hinterlegen kann, wie es diesen blöden Vector initialisieren kann. Der Vector ist von Autodesk (AutoCAD) und den muss ich leider auch nutzen.
Auch wäre es schön, wenn ich dort noch weitere dieser "Anleitungen" für andere Typen hinterlegen kann.

Hat das jemand von euch schonmal gemacht und mag mir da helfen?

23.01.2020 - 10:42 Uhr

Hi,

ich möchte die Opacity von einem control abhängig von 2 unterschiedlichen DependencyProperties auf unterschiedliche Werte setzen. Das soll animiert geschehen.
Hier mal mein Versuch:


<StackPanel>
     <CheckBox x:Name="ChkBoxA" Content="A"/>
     <CheckBox x:Name="ChkBoxB" Content="B"/>
</StackPanel>

.
.
.


<ListBox>
    <ListBox.Style>
        <Style TargetType="{x:Type ListBox}">
            <Style.Triggers>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding ElementName=ChkBoxA, Path=IsChecked}" Value="true"/>
                        <Condition Binding="{Binding ElementName=ChkBoxB, Path=IsChecked}" Value="true"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" To="1.0" Duration="0:0:0.2"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </MultiDataTrigger.EnterActions>
                </MultiDataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding ElementName=ChkBoxA, Path=IsChecked}" Value="false"/>
                        <Condition Binding="{Binding ElementName=ChkBoxB, Path=IsChecked}" Value="false"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.1" Duration="0:0:0.2"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </MultiDataTrigger.EnterActions>
                </MultiDataTrigger>
                <MultiDataTrigger>
                    <MultiDataTrigger.Conditions>
                        <Condition Binding="{Binding ElementName=ChkBoxA, Path=IsChecked}" Value="true"/>
                        <Condition Binding="{Binding ElementName=ChkBoxB, Path=IsChecked}" Value="false"/>
                    </MultiDataTrigger.Conditions>
                    <MultiDataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetProperty="Opacity" To="0.3" Duration="0:0:0.2"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </MultiDataTrigger.EnterActions>
                </MultiDataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.Style>
</ListBox>

Is jetzt eine ListBox, lässt sich aber auch mit anderen UIElementen reproduzieren. Starte ich das Programm, springt die Opacity auf 0.1 ... soweit richtig. Checke ich nun Checkbox A, geht die Opacity auf 0.3 ... auch richtig. Klicke ich beide an, passiert nichts...es bleibt auf 0.3, müsste aber auf 1.0 gehen. Was mache ich falsch?

18.12.2019 - 11:11 Uhr

Hallo,

gegeben sei folgender Test-String:

irgendwas
noch mehr irgendwas
hier können beliebig viele Zeilen sein

Zahl 1 ist "2"

ganz viel irgendwas
hier können beliebig viele Zeilen sein

     Zahl 2 ist "unbekannt" und die Zeile hat n Leerzeichen am Anfang

Als Ausgabe möchte ich "2" und "unbekannt" haben.

Folgender Regex tut leider nicht was er soll:

^\s*Zahl 1 ist "(.+?)"$(?:^.*$)+?^\s*Zahl 2 ist "(.+?)"

Getestet mit regex101
Zahl 1 findet er, wenn ich den Part von Zahl 2 wegnehme.
Ich möchte nicht den Singleline mode nehmen, da sich das offenbar schlecht auf die Performance auswirkt...ist ein recht langer Quellcode einer Webseite.

Problem scheint das hier zu sein: (?:^.*$)+?
Damit möchte ich 1-n Zeilen beschreiben, in denen alles mögliche oder auch gar nichts steht. Jetzt wo ich es laut lese, wird das wohl Performance-Technisch auch nocht so toll sein und aufs gleiche raus kommen wie singleline. Kann mir hier jemand helfen? Am liebsten würde ich einfach die Zeilen-Anker ^ und $ Quantifizieren, aber das geht wohl nicht.

04.12.2019 - 21:55 Uhr

Habe es doch noch geschafft. Hier die Lösung:


<TabControl x:Name="tabControl" TabStripPlacement="Bottom" AlternationCount="2"
                IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedMonthRecordViewModel, Mode=TwoWay}">
        <TabControl.Resources>
            <CollectionViewSource Source="{Binding Path=MonthRecordViewModels}" x:Key="ItemsCollectionViewSource"/>
        </TabControl.Resources>
        <TabControl.ItemsSource>
            <CompositeCollection>
                <CollectionContainer x:Name="monthCollectionContainer" Collection="{Binding Source={StaticResource ItemsCollectionViewSource}}"/>
                <TabItem Header="Übersicht">
                    <local:YearSummary DataContext="{Binding YearSumaryViewModel}"/>
                </TabItem>
            </CompositeCollection>
        </TabControl.ItemsSource>
        <TabControl.ItemContainerStyle>
            <Style TargetType="{x:Type TabItem}">
                <Setter Property="Header" Value="{Binding Month, Converter={StaticResource shortMonthConverter}}"/>
                <Style.Triggers>
                    <Trigger Property="TabControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="LightSeaGreen"/>
                    </Trigger>
                    <Trigger Property="TabControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGreen"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TabControl.ItemContainerStyle>
    </TabControl>

04.12.2019 - 07:46 Uhr

Was kommt bei Timespan = 30 Stunden heraus?
Habe es nicht nachgeprüft, aber ich kann mir gut vorstellen dass der TimeSpan alles größer als 23,x Stunden auf Tage umbricht.
Am besten rechnest du dir die Zahlenwerte selber um.

Nein da kam vorher tatsächlich 30:00 raus

04.12.2019 - 07:29 Uhr

nun - das Property TotalHours sieht hierfür vielversprechend aus

Perfekt, danke 😃 Daran hab ich nicht gedacht. Musste nur noch den Absolutbetrag von den Minuten nehmen, da die sonst auch noch ein Minus davor haben wenn es negativ ist.

03.12.2019 - 23:40 Uhr

Du kannst dafür eine CompositeCollection verwenden:
>

Ahhh vielen Dank 😃

So ganz klappt es aber bei mir noch nicht. Hier mal der gesamte XAML Code von dem Control:


<UserControl x:Class="WorkTimeTracker.View.Controls.YearPlan"
             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:converters="clr-namespace:WorkTimeTracker.View.Converters"
             xmlns:valRules="clr-namespace:WorkTimeTracker.View.ValidationRules"
             xmlns:viewModels="clr-namespace:WorkTimeTracker.ViewModels"
             xmlns:local="clr-namespace:WorkTimeTracker.View.Controls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" x:Name="this">
    <UserControl.Resources>
        <converters:IntToShortMonthLocalizedConverter x:Key="shortMonthConverter"/>
        <DataTemplate DataType="{x:Type viewModels:MonthRecordViewModel}">
            <local:MonthPlan/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewModels:YearSumaryViewModel}">
            <local:YearSummary/>
        </DataTemplate>
    </UserControl.Resources>
    <TabControl x:Name="tabControl" TabStripPlacement="Bottom" AlternationCount="2"
                IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedMonthRecordViewModel, Mode=TwoWay}">
        <TabControl.ItemsSource>
            <CompositeCollection>
                <CollectionContainer x:Name="monthCollectionContainer" Collection="{Binding MonthRecordViewModels}"/>
                <TabItem Header="Übersicht">
                    <local:YearSummary DataContext="{Binding ElementName=this, Path=DataContext}"/>
                </TabItem>
            </CompositeCollection>
        </TabControl.ItemsSource>
        <TabControl.ItemContainerStyle>
            <Style TargetType="{x:Type TabItem}">
                <Setter Property="Header" Value="{Binding Source=monthCollectionContainer, Path=Month, Converter={StaticResource shortMonthConverter}}"/>
                <Style.Triggers>
                    <Trigger Property="TabControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="LightSeaGreen"/>
                    </Trigger>
                    <Trigger Property="TabControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGreen"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TabControl.ItemContainerStyle>
    </TabControl>
</UserControl>

Nun ist der Extra-Tab zwar da, die Monate aber nicht mehr.
In der Ausgabe sind folgende Fehlermeldungen zu sehen:

Fehlermeldung:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=MonthRecordViewModels; DataItem=null; target element is 'CollectionContainer' (HashCode=31674992); target property is 'Collection' (type 'IEnumerable')

Fehlermeldung:
System.Windows.Data Error: 40 : BindingExpression path error: 'Month' property not found on 'object' ''String' (HashCode=1434043879)'. BindingExpression:Path=Month; DataItem='String' (HashCode=1434043879); target element is 'TabItem' (Name=''); target property is 'Header' (type 'Object')

MonthRecordViewModel.Month ist übrigens nur ein Int zwischen 1-12 und shortMonthConverter macht aus einem int einfach Jan, Feb, Mrz usw. Ohne den Converter würde halt der Header der Tabs einfach aus der Zahl bestehen.

03.12.2019 - 22:50 Uhr

Hallo 😃

Ich formatiere mir für ein Binding mit diesem Converter ein TimeSpan in das Format hh:mm

public class SignedTimeSpanToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            TimeSpan timeSpan = (TimeSpan)value;
            if (timeSpan >= TimeSpan.Zero)
                return timeSpan.ToString(@"hh\:mm");
            else
                return "-" + timeSpan.ToString(@"hh\:mm");
        }
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => throw new NotImplementedException();
    }

Die TimeSpan wird meistens geringer sein als 100h, kann aber auch deutlich drüber sein und sowohl positiv als auch negativ. Ist sie nun größer als 100h, wird die erste Ziffer abgehackt. Wie kann ich 9h : 15 min als 09:15 ausgeben und 144h : 15 min als 144:15?

02.12.2019 - 20:12 Uhr

Hi,

ich schreibe gerade an einem kleinen Tool zur Zeiterfassung. Nichts großartig kompliziertes und nichts was die Welt revolutioniert. Mache das hauptsächlich um mir das MVVM Pattern beizubringen. Bisher funktioniert auch alles prima.

Ein kurzer Überblick über meine Struktur der ViewModels:

  • DayRecordViewModel
  • MonthRecordViewModel
  • YearRecordViewModel

Ein DayRecordViewModel beinhaltet alles über den Arbeitstag: Datum, Anfang, Ende, Pause, Soll...
Ein MonthRecordViewModel hat eine ObservableCollection<DayRecordViewModel>
Ein YearRecordViewModel hat eine ObservableCollection<MonthRecordViewModel>

Jedes MonthRecordViewModel bedient ein DataGrid und das YearRecordViewModel ein TabControl. Das YearRecordViewModel ist an die ItemSource des TabControls gebunden und somit habe ich einen Tab für jeden Monat.

Nun zu meinem Problem: Ich hätte gern einen dreizehnten Tab am Ende der "Übersicht" heißt und welcher vielleicht auch eine andere Farbe hat (färbe die Tabs mittels TabControl.AlternationIndex in dessen Style ein).
Ich habe aber keine Ahnung wie ich das machen soll. Hier mal der XAML Code von meinem TabControl:

<TabControl x:Name="tabControl" TabStripPlacement="Bottom" ItemsSource="{Binding MonthRecordViewModels}" AlternationCount="2"
            IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedMonthRecordViewModel, Mode=TwoWay}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="Header" Value="{Binding Path=Month, Converter={StaticResource shortMonthConverter}}"/>
            <Style.Triggers>
                <Trigger Property="TabControl.AlternationIndex" Value="0">
                    <Setter Property="Background" Value="LightSeaGreen"/>
                </Trigger>
                <Trigger Property="TabControl.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="LightGreen"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TabControl.ItemContainerStyle>
    <TabControl.ContentTemplate>
        <DataTemplate>
            <local:MonthPlan/>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>
28.11.2019 - 19:57 Uhr

Hi,

ich führe mir gerade den MVVM Guide zu Gemüte, weil ich gerade etwas fest hänge. Und zwar habe ich verschachtelte Models/Viewmodels.

Ich habe es so verstanden, dass jedes View ein ViewModel braucht. Und jedes ViewModel braucht ein Model.

Hier hält aber das ViewModel die Daten die doch ins Model gehören, oder? Wieso ist hier Model und ViewModel ein und das Selbe?

14.11.2019 - 10:29 Uhr

Ah, okay danke.

Du kannst aber problemlos mit .NET Core einen eigenen Wrapper gegen die Win32 API schreiben.
Nichts anderes, was .NET Framework gemacht hat.
Feel free:
>

Das war mir gar nicht so klar. Danke 😃 Vielleicht mache ich das sogar.

09.11.2019 - 22:05 Uhr

API Complete?

Auch alle großen SDKs und Projekte unterstützen .NET Core bzw. .NET Standard.

Naja scheinbar ja nicht. System.Speech ist nicht verfügbar für .Net Core 3.0
Und auch sonst kann ich nichts freies finden das kompatibel wäre.

wir nutzen Azure Cognitive Services für Text to Speech bzw vise versa und .NET Core / JavaScript.

Damit habe ich auf Arbeit auch schon gearbeitet. Nur möchte ich mir das für ein privates, nicht kommerzielles Projekt nicht leisten. Zudem ist dafür eine Internetverbindung erforderlich. Und die Sprachsynthese die ich hier verwenden möchte, funktioniert eigentlich tadellos.

PS: Habe hier jemanden gefunden der genau das selbe Problem hat.

09.11.2019 - 21:18 Uhr

Ja ich werde es morgen mal versuchen. Es ist frustrierend...möchte ungern noch was neues mit dem .Net Framework starten, weil ich nicht in ein paar Jahren in die Röhre gucken will. Aber es gibt noch fast nichts am Bibliotheken dafür...sehr nervig 😦

Kennst du einen anderen Weg wie ich Bibliotheken aus dem .Net Framework irgendwie in .Net Core nutzen kann?

09.11.2019 - 17:34 Uhr

Hallo,

ich schreibe gerade an einer .Net Core Anwendung, in der ich die Assembly System.Speech nutzen möchte. Da diese aber nicht mit .Net Core 3.0 zusammen spielt, wollte ich sie über die PowerShell nutzen.
Folgender Code funktioniert:


private static void Execute(string command, bool wait)
{
    var cFile = System.IO.Path.GetTempPath() + Guid.NewGuid() + ".ps1";

    using var tw = new System.IO.StreamWriter(cFile, false, Encoding.UTF8);
    tw.Write(command);
 
    var start =
        new System.Diagnostics.ProcessStartInfo()
        {
            FileName = "C:\\windows\\system32\\windowspowershell\\v1.0\\powershell.exe",  // CHUPA MICROSOFT 02-10-2019 23:45                    
                LoadUserProfile = false,
            UseShellExecute = false,
            CreateNoWindow = true,
            Arguments = $"-executionpolicy bypass -File {cFile}",
            WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden
        };

    var p = System.Diagnostics.Process.Start(start);
  
    if (wait)
        p.WaitForExit();
}

public static void Speak(string textToSpeech, bool wait = false)
{
    // Command to execute PS  
    Execute($@"Add-Type -AssemblyName System.Speech;  
    $speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;      
    $speak.Speak(""{textToSpeech}"");", wait); // Embedd text 
}

Ist aber irgendwie nicht das Gelbe vom Ei und ist nutzlos wenn ich einen Rückgabewert aus der PS haben möchte. Also habe ich mir via NuGet Microsoft.PowerShell.SDK (6.2.3) besorgt und die Execute Methode von oben ausgetauscht durch:


private static object Execute2(string command, bool wait)
{
    PowerShell PowerShellInstance = PowerShell.Create(RunspaceMode.NewRunspace);

    PowerShellInstance.AddScript(command);

    var results = PowerShellInstance.Invoke();

    foreach (PSObject outputItem in results)
    {
        Console.WriteLine(outputItem.BaseObject.ToString());
    }

    return results.Count > 0 ? results[0] : null;
}

PowerShellInstance.Streams.Error beinhaltet nun folgendes für mich:

"Exception calling &quot;Speak&quot; with &quot;1&quot; argument(s): &quot;Object reference not set to an instance of an object.&quot;"

offenbar ist der SpeechSynthesizer null. Wieso klappt es wenn ich die PowerShell "manuell" öffne und hier nicht? Selbes Spiel wenn ich die Powershell öffne und den code hineinkopiere...geht wunderbar.

02.10.2019 - 11:22 Uhr

Beschreibung:

Hier sind zwei Erweiterungsmethoden für System.Linq.Expressions.Expression, welche es ermöglichen zwei Linq-Expressions logisch zu "verodern" bzw. zu "verunden". Der Code ist nicht von mir, nur leicht von mir angepasst. Weiß leider nicht mehr genau woher ich den habe, musste aber lange nach sowas suchen. Verwende es um eine Datenbankabfrage, unter Angabe eines Query Strings aus der URL eines Webservices, zu generieren.


public static class ExpressionExtensions
{
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T));

        var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
        var left = leftVisitor.Visit(expr1.Body);

        var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
        var right = rightVisitor.Visit(expr2.Body);

        return Expression.Lambda<Func<T, bool>>(
            Expression.AndAlso(left, right), parameter);
    }

    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
    {
        var parameter = Expression.Parameter(typeof(T));

        var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0], parameter);
        var left = leftVisitor.Visit(expr1.Body);

        var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
        var right = rightVisitor.Visit(expr2.Body);

        return Expression.Lambda<Func<T, bool>>(
            Expression.OrElse(left, right), parameter);
    }

    private class ReplaceExpressionVisitor : ExpressionVisitor
    {
        private readonly Expression _oldValue;
        private readonly Expression _newValue;

        public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
        {
            _oldValue = oldValue;
            _newValue = newValue;
        }

        public override Expression Visit(Expression node)
        {
            if (node == _oldValue)
                return _newValue;
            return base.Visit(node);
        }
    }
}

Verwendung:


List<Expression<Func<string, bool>>> expressions = new List<Expression<Func<string, bool>>>();
expressions.Add(x => x.ToLower().Contains("foo") || x.ToLower().Contains("bar"));
expressions.Add(x => !x.ToLower().Contains("not this"));

var combinedExpression = expressions.Aggregate((x, y) => x.And(y));

Schlagwörter: Linq, Verknüpfen, Linq OR, Linq AND

02.10.2019 - 10:11 Uhr

Hi 😃

in meiner ASP.Core Anwendung sollen query parameter in der URL mitgegeben werden können. Klappt soweit auch prima.

Hier ein Minimalbeispiel der Implementierung:


[Route("api/Items")]
[ApiController]
public partial class ItemsController : ControllerBase
{
    public class ItemsQuery
    {
        public string Id { get; set; }
        public int PageIndex { get; set; } = 0;
        public string FullText { get; set; }
        public int? Type { get; set; }
    }

    public ActionResult Get([FromQuery] ItemsQuery query)
    {
        ...
    }
}

Nun möchte ich jedoch gern einen Parameter mehrfach angeben können.
Beispiel URL: www.myapi.de/items?Type=1&Type=2&Type=3

Habe nichts brauchbares dazu gefunden, ausser es selbst zu parsen. Hat jemand eine elegantere Lösung für mich?

EDIT: Ehm...okay, entschuldigt die dumme Frage. Es war so offensichtlich, das ich nicht gleich drauf gekommen bin. Einfach einen entsprechenden Array in ItemsQuery einbauen und fertig.

01.10.2019 - 11:51 Uhr

Du bist der Beste 😃 Mit diesem SDK geht es prima...musste zwar einiges umschreiben, aber jetzt passt alles. Dankeschön 😃 Weiß nicht wie ich das übersehen konnte.

01.10.2019 - 10:40 Uhr

Öhm, aber NuGet sagt Version 2.7.0 ist die aktuellste 🤔

Das mit dem ResultSet habe ich auch gesehen, jedoch ist mir nicht klar wie ich performant an eine spezielle Seite navigieren kann. Also ich habe eine Konstante PageSize definiert und in der URL wird ein PageIndex mitgegeben. Müsste meine API dann also alles erst aus der Datenbank holen und dann das zurückgeben, was verlangt wurde?

01.10.2019 - 10:16 Uhr

verwendetes Datenbanksystem: DocumentDB

Hi,

ich arbeite zur Zeit an einer REST-API die Daten aus einer Microsoft DocumentDB (Cosmos DB) ausgibt. Nun wird diese Datenbank mit der Zeit wachsen und ich kann nicht immer einfach alles an den Client senden was er angefordert hat. Ich muss Pagination (so wird es glaube ich genannt) einsetzen. Da ich die Datenbank mit dem Microsoft.Azure.Documents.Client und einer Linq-Query abfrage, dachte ich mir "Ok, einfach den gewünschten Seitenindex in der URL mitliefern, dann Skip() und ein Take()". Leider erhalte ich dann aber folgende Fehlermeldung: > Fehlermeldung:

ArgumentException: Cross Partition OFFSET / LIMIT is not supported.

Google habe ich selbstverständlich zuerst befragt und einige Beiträge gefunden, wo gesagt wird das Skip nicht unterstützt wird. Hier wird jedoch gesagt es wäre nun möglich.

Verstehe nicht so ganz was ich tun kann...

Hier noch ein paar Details:

ASP.NET Core-Webanwendung (API)
Framework: .NET Core 3.0
Microsoft.Azure.DocumentDB.Core 2.7.0

Die DocumentDB läuft zu Zeit noch auf dem Lokalhost im CosmosDB Emulator von Microsoft in einem Docker Container.

27.09.2019 - 12:26 Uhr

Okay, ich nehm's mir zu Herzen. Danke für deine Zeit 😃

27.09.2019 - 12:22 Uhr

Hmmm okay aus der Sicht habe ich es noch gar nicht betrachtet...Also du würdest es schon so implementieren, dass die API immer geupdated werden muss?

27.09.2019 - 11:55 Uhr

Daher der Hinweis auf die Schichtentrennung und die Modelle.
Eine API ist technisch gesehe nichts anderes als eine Ansicht - und da hat man eben extra Modelle.
Das hat sich bewährt, ist üblich und empfohlen.

Okay, danke. Ich werde es mir ansehen.

Tut mir leid; verstehe ich nicht.
Der Client will also Informationen vom Service, die der Service nicht kennt, aber in der Datenbank vorhanden sind.
.....wat ? 👶

Ja 😄 Tatsächlich genau das^^ Naja stell dir vor du hast in Tool A (füttert die Datenbank) eine Klasse. Bleiben wir bei der Klasse Person von oben. Du entwickelst dieses Tool über Jahre ständig weiter (und nicht nur du alleine) und hin und wieder wird Person um eine Property erweitert. Dann musst du ja JEDES mal an den Webservice und ihm diese neue Property ja auch in PersonFlat implementieren...selbst wenn der Webservice selbst diese Property nie verwendet, weil danach nicht gefiltert werden soll. Einfach nur damit der Client sie dann mit in seinem JSON string hat... Das wirkt auf mich wie eine sehr blöde Lösung bei der mit Sicherheit bald was schief läuft weil es vergessen wird.

27.09.2019 - 11:43 Uhr

So wie ich Dich verstanden habe: Du willst nur ein Teil laden, aber alles zurück geben.

Ich will dem Webservice einfach so wenig wie nur möglich über die Datenstruktur bekannt machen, damit ich möglichst selten etwas an dem Webservice ändern muss.

Wenn Du das gleiche Modell für das Speichern der Daten verwendest und für das Abfragen, dann hat eine Schemaänderung direkte Auswirkungen auf die Abfrage.

Nein eben nicht. Wenn ich Personen mit den Vornamen [Hans, Henry, Heinrich] in der DB habe, ich mit PersonFlat nach Vornamen suche die mit H anfangen, kriege ich die drei zurück. Update ich den Datenbankeintrag und ergänze die Struktur der Daten noch mit dem Gewicht der drei personen, bekomme ich ja trotzdem wieder die drei zurück wenn ich den Query wiederhole. Und genau das will ich erreichen. Der Webservice soll quasie nicht wissen das die Personen auch über ein Gewicht verfügen...kann dem Service total egal sein, weil er eh nicht danach Filtern können soll. Für den Client der den API call gemacht hat, ist es aber vielleicht interessant wie viel die wiegen...daher soll er die Information bekommen wenn sie da ist.