Laden...

Forenbeiträge von SimpleTool Ingesamt 12 Beiträge

09.12.2020 - 16:49 Uhr

Hi,

aber was muss ich da bei ??? eingaben?

XmlNodeList nodes = xDoc.SelectNodes("//element[@name='value1']");

Das im "" ist also eben der XPath Befehl wo man jetzt das Dokument nach Knotenname "element" durchsucht das den Attribut "name" hat mit dem Wert "value1".

Da ich nicht weiß was du genau für Elemente suchst wären hier Beispiele zu XPath bei dem verschiedenes durchgespielt wird. Ich denk das du dann den Inhalt für ??? findest.
Beispiele XPath
Bzw. "." XPath-Erklärung für "ab dem Knoten suchen"

06.12.2020 - 17:06 Uhr

Hab jetzt das Binding "ActualWidth" nicht auf das UserControl-Element selbst gemacht, sondern auf das Grid-Element im UserControl. Jetzt funktioniert es wie ich es wollte.
Warum das jetzt geht und das andere nicht ist mir nur nicht klar.

05.12.2020 - 17:03 Uhr

Hi,

ich hab hier mal weiter gesucht und versucht das umzusetzen. Dabei habe ich ein Beispiel der Implementierung des IDataErrorInfos gesehen
Beispiel UserControl mit IDataErrorInfo

Bei dem Beispiel wurde die Validierung vom Inhalt der Textboxen in einem "UserControl" wie folgt umgesetzt:*Es wurde eine Klasse erstellt die dann mit UserControl verbunden wird. Diese beinhaltet das IDataErrorInfo wo die Daten auf dessen Richtigkeit geprüft werden *Die Klasse wird dann an das UserControl gebindet wo dann der IDataErrorInfo diese Daten abgreift und diese für z. B. die Textbox setzt *Also wurde das Error innerhalb der über DataContext gebundenen Klasse ermittelt und nur bis zum Usercontrol z. B. Anzeige im ToolTip weiter gegeben.

Meine Validierung beim DataGridColumn habe ich aber jetzt nicht über die gebundene Klasse gemacht, **sondern mit **einer ValidationRule Klasse. Kann man dieses Validation Error dann auch irgendwie in XAML z. B. an den Button WPF-Command binden?!
-> Bei mir erkennt die DataGridCell in Verbindung mit ValidationRule Klasse das der Inhalt inkorrekt ist und nicht wie bei dem Beispiel oben die Klasse die daran gebunden ist.
-> sollt ich hier mein Validation ändern damit ich so ein "Sammel-HasError" erstellen kann/abfragen kann ob das DataGrid irgendein Fehler hat?

Ich hoffe ihr könnt mir ein Tipp geben.
Vielen Dank schon mal im Voraus.

Liebe Grüße

20.11.2020 - 10:50 Uhr

Zur Ergänzung noch die Info bzgl.:

[...]allerdings möchte ich an der Klasse QHMI_DATALOG_CS momentan ungern was ändern, da diese an vielen stellen verwendet wird.

Wenn du in deiner Klasse den alten Konstruktor nicht löscht oder veränderst, dürfte es bei den anderen Stellen im Code, wo du diesen Konstruktor schon benutzt, nichts ändern. Bzw. du hast ihn noch nicht implementiert daher würde ich den dann noch hinzuschreiben.

Spontan würde ich die Klasse wie folgt ändern um so auch an anderen Stellen noch das alte Verhalten zu gewährleisten:


    public class QHMI_DATALOG_CS
    {
        public int ID { get; set; }

        public DateTime TS { get; set; }

        public string DATASOURCE { get; set; }

        public string DATATYPE { get; set; }
        public string VARNAME { get; set; }
        public string VALUE { get; set; }

        public string Quality { get; set; }

        public string MESSAGE { get; set; }

        /// <summary>
        /// Default Konstruktor der für die  anderen Programmstellen dann benutzt wird
        /// </summary>
        public QHMI_DATALOG_CS()
        {

        }
        /// <summary>
        /// Konstruktor um die Liste mit QHMI_DATALOG_CS zu klonen, Item für Item mit ForEach
        /// </summary>
        /// <param name="cloneItem">Item das ich kopieren möchte (ohne Referenz)</param>
        public QHMI_DATALOG_CS(QHMI_DATALOG_CS cloneItem) :this()
        {
            ID = cloneItem.ID;
            TS = DateTime.Parse(cloneItem.TS.ToString()); // DateTime ist glaube ich ein Referenztyp, daher würde ich in String wandeln und neues Objekt daraus machen, müsste man wenn man das nicht will einfach testen
            DATASOURCE = cloneItem.DATASOURCE;
            DATATYPE = cloneItem.DATATYPE;
            VARNAME = cloneItem.VARNAME;
            VALUE = cloneItem.VALUE;
            Quality = cloneItem.Quality;
            MESSAGE = cloneItem.MESSAGE;
        }

    }

13.11.2020 - 15:19 Uhr

Hi,

das DataGrid lässt mir keine Ruhe 😁 und so hab ich ein weiteres Problem bei dem ich nicht weiß welche Lösung ich anstreben soll.
**
Was möchte ich erreichen:***Ein Button soll disabled sein wenn im DataGrid eine ValidationRule auslöst

Wie ist mein DataGrid aufgebaut?


        <DataGrid Name="myDataGrid"
                      VerticalScrollBarVisibility="Auto" ItemsSource="{Binding}" 
                      AutoGenerateColumns="False" Validation.Error="myDataGrid_Error">

            <DataGrid.Columns>


                <DataGridTextColumn Header="OffsetByte" x:Name="dgcolumn" >
                    <DataGridTextColumn.Binding>
                        <Binding Path="OffsetByte" UpdateSourceTrigger="PropertyChanged" StringFormat="d" ValidatesOnDataErrors="True">
                            <Binding.ValidationRules>
                                <DataErrorValidationRule ValidationStep="UpdatedValue" ValidatesOnTargetUpdated="True"/>
                            </Binding.ValidationRules>
                        </Binding>
                    </DataGridTextColumn.Binding>
                </DataGridTextColumn>

                <DataGridTextColumn Header="test" Binding="{Binding Test}"/>
            </DataGrid.Columns>

        </DataGrid>


Besonderheit:*Ich benutze keine eigene ValidationRule sondern arbeite mit DataErrorValidationRule und StringFormat. *DataGrid wird im CodeBehind mit ObserveableCollection<MEINDATENTYP> verbunden mit "myDatagrid.ItemsSource = Liste".

Jetzt würde ich gerne einen Button disablen wenn eben ein DataGrid-Cell eine Fehleingabe hat (z. B. es wird ein Buchstabe statt eine Zahl eingegeben). Wenn das kein DataGrid sondern eine TextBox ist bekomme ich das hin, aber hier weiß ich nicht weiter.

Was habe ich bereits probiert*Ich wollte den Validation Error zum DataGrid "bubblen", sodass ich HasError vom DataGrid in xaml binden könnte. Aber das hab ich nicht hin bekommen. Dafür habe ich auch probiert RowValidation zu erstellen die in der Zeile die Cell-Errors abfragen soll und dann vom RowValidation wollt ich das dem DataGrid übergeben. *WPF-Command beim Button habe ich auch versucht, und zwar wollte ich da das DataGrid übergeben und so jede Zelle durchsuchen nach HasError. Den code dafür habe ich, aber hier scheitere ich bei der Übergabe des DataGrids mit Elementname. Der Übergabeparameter lässt sich dann im WPF-Command nicht zum DataGrid wandeln sondern ist nun meine ObservableCollection<> *Im Internet wenn ich danach suche finde ich immer Ansätze bzgl. INotifyDataError bzw. IDataErrorInfo. So wie ich das verstanden habe müsste ich aber in meiner Klasse, die ich in meiner ObserveableCollection<> habe dann das implementieren. Ansich ist das kein Problem, jedoch hab ich ja dann mit DataErrorValidationRule schon eine Kontrolle ob die Eingabe korrekt ist. Hätte dann somit an zwei Stellen im Programm so eine Prüfung. *Wenn CellEditEnding ist wollte ich eine Sammelvariable z. B. "DataGridHasError" **beschreiben **wenn im DataGrid ein HasError ist. Problem ist aber, das nach CellEditEnding im "object sender = DataGrid" noch nicht der neuste Wert steht. (Code hätte ich und funktioniert, aber es steht halt der alte Wert noch im DataGrid) Hier weiß ich nicht wie ich am besten den an diesem Punkt aktualisiere bzw. evtl. ein eigenes Event oder so trigger der dann die Zellen nach HasError abfragt.

**Wie würdet ihr den Button disablen wenn im DataGrid ein ValidationError entseht?***INotifyDataError bzw. IDataErrorInfo in der Klasse die mit ObserveableCollection<> mit dem DataGrid verknüpft ist implementieren? *Kann man doch das DataGrid bzw. ein gesammelten HasError für das WPF-Command in xaml binden? *Oder kann man eine Sammelvariable im Code-Behind beschreiben?

Ich hoffe ihr könnt mir ein paar Anregungen geben, da beim Durchsuchen des Interent und Forums nicht auf eine Antwort gekommen bin.

Vielen Dank schon mal.
Liebe Grüße

13.11.2020 - 14:48 Uhr

Hi,

ich hab mal eine Liste kopiert damit diese unabhängig voneinander bearbeitet werden können (2 seperate Listen, wobei die eine ein Klone ist)


ListWhichIWantToCopy.ForEach((item) => { ListWhichIsNew.Add(new QHMI_DATALOG_CS(item)); });

Aber dafür muss die Klasse (hier QHMI_DATALOG_CS) dann einen Konstruktor haben z. B.


public QHMI_DATALOG_CS(QHMI_DATALOG_CS cloneItem)
        {
            _interneVar1 = cloneItem.InterneVar1;
        }

Vielleicht hilft dir das weiter.

05.11.2020 - 19:31 Uhr

Hi again,
ich habe jetzt HorizontalAlignment="Center" immer Stück für Stück in den höheren Element eingefügt und hab dann das Resultat beobachtet (im Editor und im laufenden Programm).

Im UserControl bei Grid und dann StackPanel eingefügt -> trotzdem war der Fehler noch.

Im MainWindow beim UserControl, StackPanel, dann Scrollviewer und zuletzt DockPanel eingefügt -> trotzdem war der Fehler noch da.

Wenn ich dem StackPanel (indem das UserControl ist) eine Width gebe, also eine definierte Größe, dann funktioniert es. Jedoch verliere ich so die Option das das UserControl selber die Größe bestimmt und ich dann Scrollen kann.


<ScrollViewer x:Name="myScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" >
            <StackPanel Name="sptest" HorizontalAlignment="Stretch" 
Width="100">
                <uc:MyUserControl DockPanel.Dock="Top" x:Name="ucexample" HorizontalAlignment="Stretch"/>
            </StackPanel>
</ScrollViewer>

Irgendwie ist also am Anfang die Größe des UserControls noch nicht bekannt, daher denke ich, dass die Columns sich auf die kleine Größe rendern. Dann erst bekommt das UserControl seine Größe, aber die Columns sind ja schon gerendert... So ein Effekt in der Art müsste sein.

Evtl. müsste ich probieren erst nach der Erstellung des UserControls irgendwie erst die Columns Width zu definieren (also DataGridLength=Star).

Wär das evtl. etwas?! Wäre das was mit dem Event "Loaded"?

Liebe Grüße

03.11.2020 - 15:47 Uhr

Wenn ich im UserControl das DataGrid wie folgt mache:


            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition Height="auto"/>
                </Grid.RowDefinitions>

                <TextBlock Grid.Row="0">text</TextBlock>

                <DataGrid Name="dataGridWpf" 
                  Height="200" AutoGenerateColumns="False" 
                  Grid.Row="1"
                  
                  HorizontalAlignment="Stretch"
                  >
                    <!--Width="{Binding ElementName=UsercontrolName, Path=ActualWidth}"-->
                    <DataGrid.Columns>
                        <DataGridTextColumn Header="eins"/>

                        <DataGridTextColumn Header="zwei" Width="*" x:Name="header2"/>

                    </DataGrid.Columns>

                </DataGrid>
            </Grid>

Passiert das Gleiche wie wenn ich Strech nicht verwenden würde.

Wie das aussieht habe ich im Dateianhang.
-> letzte Spalte füllt hier nicht den restlichen Raum aus
-> ich kann die Spalten auch nicht mehr von der Width ändern mit der Maus

Funktioniert leider nicht.

EDIT:
> Im XAML-Editor von Visual-Studio zeigt er mir das aber so an wie ich es gerne hätte.
> Wenn ich jetzt HorizontalScrollBarVisibility = disabled habe würde es auch funktionieren nur dann habe ich leider kein ScrollViewer Horizontal X(

02.11.2020 - 20:31 Uhr

Hi,

(denn das UserControl bestimmt seine Breite doch u.a. durch die Breite des DataGrids)?

Ohne HorizontalScrollBarVisible funktioniert die Erstellung vom UserControl ohne Probleme.

Ich denke mal, dass bei der Erstellung des UserControls dieses erstmal die Breite des ScrollViewers bekommt und so bekommt das DataGrid die Breite des UserControls. Die letzte Spalte kann dann den "restlichen Raum" ausfüllen.

Es wird dann wohl so eine Schleife auftreten wenn ich BorderThickness hinzufüge. Sowas wie

  • Border thickness wird gesetzt
  • UserControl Breite ändert sich dadurch
  • DatagridColumn soll restlichen raum ausfüllen
  • HorizontalScrollbar gibt aber unendlich viel Platz oder so...
    -> Leider weiß ich hier nicht was wirklich passiert und somit fällt mir kein Workaround ein.

Falls das ActualWidth das Problem auslöst, müsste ich nur wissen wie ich die letzte Spalte auf den noch aktuell restlichen Raum strechen kann. Also:
"Die letzte Spalte vom DataGrid auf den restlichen Raum zu strechen ohne das ich eine Schleife bzw. Bezug auf ActualWidth vom UserControl benötige".

Auf den ScrollViewer möchte ich eigentlich nicht verzichten, da bei mehreren Spalten vom Datagrid das UserControl und somit das DataGrid außerhalb des Fensters ist. Das würde dann alle UserControls im ScrollViewer betreffen (gemeinsam und nicht jedes einzeln, daher der ScrollViewer über dem UserControl und nicht in dem UserControl).

Gibt es hierfür eine alternative Lösung die ich verfolgen und probieren kann?

Liebe Grüße

02.11.2020 - 16:29 Uhr

Hi Th69,
danke für deine Antwort

Hast du das denn mal getestet?

-> ja habe ich. Hab es jetzt nochmal ausprobiert.

Wenn ich

myScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;

einstelle (sei es in XAML oder wie hier im Code-Behind) und anschließend den Border ändere wird der Border wie gewünscht gesetzt.
Wenn ich aber dann wieder

myScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;

einstelle, dann friert das Fenster ein. Auch wenn ich mit einem Button diese Eigenschaft setze. Ich kann auch nicht mehr die Größe des Fensters ändern.

Also allgemein: Ist HorizontalScrollBarVisiblility Auto, dann kann ich nicht den Border von dem UserControl setzen ohne Fehlfunktion.

Eine Möglichkeit die ich noch ausprobiert habe, ist die XAML Bindung des DataGrids zu entfernen.

                
<DataGrid Name="dataGridWpf" 
    Height="200" AutoGenerateColumns="False" 
    Grid.Row="1"
    >
    <!--Width="{Binding ElementName=UcName, Path=ActualWidth}"-->
        <DataGrid.Columns>
            <DataGridTextColumn Header="eins"/>
            <DataGridTextColumn Header="zwei" Width="*" x:Name="header2"/>
        </DataGrid.Columns>
</DataGrid>

-> dann funktioniert das Border setzen wieder, jedoch sind die DataGrid Columns zusammengeschoben und lassen sich nicht mehr bedienen. (der Width="*" funktioniert dann nicht wie ich möchte)

Liebe Grüße

01.11.2020 - 17:55 Uhr

Hallo,
vielen Dank für deine Antwort Tobias.

  • ich habe das mit Window_Loaded ausprobiert -> selbe Resultat, das Fenster friert ein
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    ucexample.BorderThickness = new Thickness(2);
}
  • ich habe einen Button mal bemüht den ich drücken kann -> hier kann ich zwar das Fenster noch verschieben, jedoch ist die Bedienung des Fensters überhaupt nicht mehr akzeptabel (ruckelt)
        private void Button_Click(object sender, RoutedEventArgs e)
{
    ucexample.BorderThickness = new Thickness(2);
}

Das Problem ist also auch vorhanden, nachdem die Ladephase vorbei ist und der GUI-Thread nichts mehr zu tun hat.

Wäre noch keine Lösung X(

Liebe Grüße

01.11.2020 - 12:41 Uhr

Hallo myCsharp Community,

ich habe eine Frage zu WPF und wie man so etwas umsetzen kann.

Thema:
Ich habe ein eigenes UserControl indem ein DataGrid vorhanden ist. Das letzte DataGridColumn soll dabei den restlichen Raum/Länge ausfüllen (DataGridLength.Star). Dafür musst ich im UserControl die DataGrid.Width anpassen an das UserControl (Elementbindung).
Zur Laufzeit wird dann in ein StackPanel ein/mehrere UserControls erstellt und eingefügt. (im Beispiel unten wurde das nicht gemacht, da dies für den Fehler nicht nötig ist)
Das StackPanel hingegen sitzt in einem ScrollViewer, damit ich dann, falls mein UserControl außerhalb des Fensters sich befindet, scrollen kann. Da dies nicht nur bei der "height" passieren kann sondern je nach DataGrid Columns auch in der Width, wollte ich beim ScrollViewer den HorizontalScrollBar aktiv lassen.

Soweit funktioniert das. Problem ist jedoch, wenn ich den Border.Thickness einstellen vom UserControl. Wenn ich diesen einstelle, friert mein WPF-Fenster ein und ich kann nichts mehr bedienen.
Das Problem hat was mit dem DataGrid.Width (Elementenbindung zu UserControl ActualWidth) zu tun und dem ScrollViewer HorizontalBar. Beispielsweise wenn ich den HorizontalScrollBarVisible = disable stelle, müsst das mit der Border.Thickness funktionieren.

Vielleicht kann mir hier jemand erklären wie man so etwas realisieren könnte. Habe hierfür schon mal auf "MainWindow.Loaded" Event gewartet, aber das Resultat war das Gleiche.


Zur besseren Verständnis folgend ein Beispielcode mit Erklärung.
Mein UserControl
Im User Control befindet sich mein DataGrid. Die letzte Spalte wurde dabei auf Widht=* gestellt damit dieser den kompletten Raum ausfüllt. Damit hier nicht alle Spalten "zusammengeschoben" sind, musste ich die Width vom DataGrid selber auf das UserControl (ActualWidth) binden.

<UserControl x:Class="WpfTestArea.UserControls.MyUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfTestArea.UserControls"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" Name="UcName">
    <StackPanel>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"/>
                <RowDefinition Height="auto"/>
            </Grid.RowDefinitions>

            <TextBlock Grid.Row="0">text</TextBlock>

            <DataGrid Name="dataGridWpf" 
                  Height="200" AutoGenerateColumns="False" 
                  Grid.Row="1"
                  Width="{Binding ElementName=UcName, Path=ActualWidth}">

                <DataGrid.Columns>
                    <DataGridTextColumn Header="eins"/>
                    <DataGridTextColumn Header="zwei" Width="*" x:Name="header2"/>
                </DataGrid.Columns>

            </DataGrid>
        </Grid>
    </StackPanel>
</UserControl>

Beim UserControl wurde beim Code-Behind kein weiterer Code bzw. Code von mir hinzugefügt. Daher werde ich den Code hier nicht auflisten.

MainWindow.xaml in dem ich das UserControl erstelle und einbinde.
Im Beispiel hier habe ich gleich in XAML mein User Control erstellt. Bei dem will ich dann z. B. BorderThickness einstellen. Das UserControl sitzt dabei in einem StackPanel, da hier dann weitere UserControls im Code-Behind hinzugefügt werden. Damit man dann scrollen kann, falls diese UserControls außerhalb des Fensters sind (weil sie so groß sind), wurde das StackPanel in den ScrollViewer gepackt.

<Window x:Class="WpfTestArea.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfTestArea"

        xmlns:uc="clr-namespace:WpfTestArea.UserControls"

        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <DockPanel>

        <ScrollViewer x:Name="myScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <StackPanel Name="spTest">

                <uc:MyUserControl DockPanel.Dock="Top" x:Name="ucexample"/>

            </StackPanel>
        </ScrollViewer>

    </DockPanel>
</Window>

MainWindow.cs

namespace WpfTestArea
{
    public partial class MainWindow : Window
    {

        public MainWindow()
        {
            InitializeComponent();

            ucexample.BorderBrush = new SolidColorBrush(Colors.DarkGoldenrod);
            ucexample.Margin = new Thickness(20);

// --> Wenn ich das auskommentiere hängt sich mein WPF-Fenster auf
// Im Constructor das gemacht, da ich theoretisch hier noch weitere Usercontrols erstelle und dem StackPanel hinzufüge. Dann soll auch bei denen die border.thickness eingestellt werden.

            //ucexample.BorderThickness = new Thickness(1);

        }
     }
}

Kennt hier jemand einen Workaround wie man so etwas dann umsetzen kann?
Vielen Dank schon mal im Voraus.

Liebe Grüße