Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Portal
  • |
  • Mitglieder
Beiträge von PierreDole
Thema: ListView reagiert nicht auf Änderung eines Enums
Am im Forum: GUI: WPF und XAML

Zitat von Akanel
Was mir noch aufgefallen ist, aber ich bin absoluter Anfänger, warum hast du eine Klasse PluginList die eine IList<Plugin> hat und im ViewModel eine ObservableCollection<Plugin> PluginList.

Brauch man da die Klasse überhaupt?
Ja, ich brauche die Klasse. In der GUI hinzugefügte Plugins speichere ich in einer Json-Datei. IList<Plugin> wird beim Start vom Json's Deserializer mit Plugin-Objekten befüllt. Danach werden die Plugins ausgelesen, mit zusätzlichen Daten versehen und anschließend in die ObservableCollection<Plugin> eingetragen.
Zitat von Th69
Es geht also darum, daß das Objekt (in diesem Fall also Plugin) auch diese Schnittstelle implementiert haben muß - die ObservableCollection<T> benachrichtigt nur beim Änderungen an der Auflistung selbst (Add, Remove, Clear), nicht bei Änderungen der Eigenschaften der enthaltenen Objekte.
Das war dann der Fehler. Ich bin davon ausgegangen, daß ObservableCollection auch die Objekte managet.

Thema: ListView reagiert nicht auf Änderung eines Enums
Am im Forum: GUI: WPF und XAML

Für das Plugin selbst nicht. Das Plugin ist in der ObservableCollection<Plugin> Klasse. Muss ich das noch für die Plugin-Klasse machen?
(Nur damit keine Verwirrung entsteht, ich habe inzwischen State in Status umbenannt.)

Plugin:


public class PluginList
    {
        public IList<Plugin> Plugins;
    }

    public class Plugin
    {

        /// <summary>
        /// Represents the project path where the plugin is built.
        /// </summary>
        public string ProjectPath { get; set; }

        /// <summary>
        /// Determines if the plugin is loaded on start up.
        /// </summary>
        public bool AutoLoad { get; set; }

        /// <summary>
        /// Determines if the plugin is automaticly reloaded when changed in the project directory.
        /// </summary>
        public bool AutoReload { get; set; }

        /// <summary>
        /// Represents the current state of the plugin.
        /// </summary>
        [JsonIgnore] public PluginStatus Status { get; set; }
        /// <summary>
        /// Represents the absolute path (+file name) of the plugin in the application's plugin directory.
        /// </summary>
        [JsonIgnore] public string Path { get; set; }

        /// <summary>
        /// Instance of the AppDomain that was created for the plugin.
        /// </summary>
        [JsonIgnore] public AppDomain Domain { get; set; }

        /// <summary>
        /// Instance of the plugin.
        /// </summary>
        [JsonIgnore] public IPlugin Instance { get; set; }
    }

    public enum PluginStatus
    {
        Unloaded,
        Initializing,
        Loaded,
        Disposing
    }



ViewModel:

public class PluginViewModel : ViewModelBase
    {
        #region Properties
        private ObservableCollection<Plugin> pluginList;
        public ObservableCollection<Plugin> PluginList
        {
            get => pluginList;
            set => SetProperty(ref pluginList, value);
        }

        private Plugin selectedPlugin;
        public Plugin SelectedPlugin
        {
            get => selectedPlugin;
            set => SetProperty(ref selectedPlugin, value);
        }

        private string gConsoleText;
        public string GConsoleText
        {
            get => gConsoleText;
            set => SetProperty(ref gConsoleText, value);
        }
        #endregion


        #region ButtonCommands
        private ICommand addCommand;
        public ICommand AddCommand
        {
            get => addCommand ?? (addCommand = new CommandHandler(() => Add(), () => CanExecuteAdd));
        }

        public bool CanExecuteAdd
        {
            get => true;
        }

        private ICommand removeCommand;
        public ICommand RemoveCommand
        {
            get => removeCommand ?? (removeCommand = new CommandHandler(() => Remove(), () => CanExecuteRemove));
        }

        public bool CanExecuteRemove
        {
            get => SelectedPlugin != null &&
                   SelectedPlugin.Status == PluginStatus.Unloaded;
        }

        private ICommand loadCommand;
        public ICommand LoadCommand
        {
            get => loadCommand ?? (loadCommand = new CommandHandler(() => Load(), () => CanExecuteLoad));
        }

        public bool CanExecuteLoad
        {
            get => SelectedPlugin != null &&
                   SelectedPlugin.Status == PluginStatus.Unloaded;
        }

        private ICommand unloadCommand;
        public ICommand UnloadCommand
        {
            get => unloadCommand ?? (unloadCommand = new CommandHandler(() => Unload(), () => CanExecuteUnload));
        }

        public bool CanExecuteUnload
        {
            get => SelectedPlugin != null &&
                   SelectedPlugin.Status == PluginStatus.Loaded;
        }
        #endregion


        private string _pluginDir;

        public PluginViewModel()
        {
            _pluginDir = Settings.PluginDir;

            Manager.PluginManager.Instance.PluginLoaded += OnPluginLoaded;
            Manager.PluginManager.Instance.PluginUnloaded += OnPluginUnloaded;
            Manager.PluginManager.Instance.PluginRemoved += OnPluginRemoved;

            this.pluginList = new ObservableCollection<Plugin>();
        }

        public void Add()
        {
            var filePath = OpenFileDialog();

            if(string.IsNullOrEmpty(filePath))
                return;

            string pluginFile = Path.GetFileName(filePath);

            if(IsAssemblyInPluginList(pluginFile))
            {
                ShowErrorDialog($"Plugin '{pluginFile}' is already in the List.");
                return;
            }


            Plugin plugin = CreatePlugin(filePath);

            try
            {
                Manager.PluginManager.Instance.Add(plugin);
            }
            catch(Exception e)
            {
                GConsole($"Error: {e.Message} ({filePath})");
                ShowErrorDialog(e.Message);

                return;
            }

            PluginList.Add(plugin);
            Manager.PluginManager.Instance.Add(plugin);
            SavePluginList();
        }

        public void Remove()
        {
            if(SelectedPlugin == null)
                return;

            Manager.PluginManager.Instance.Remove(SelectedPlugin);
            PluginList.Remove(SelectedPlugin);
            SavePluginList();
        }

        public void Load()
        {
            if(SelectedPlugin != null && SelectedPlugin.Status == PluginStatus.Unloaded)
                try
                {
                    Manager.PluginManager.Instance.Load(SelectedPlugin);
                }
                catch(TypeLoadException e)
                {
                    string msg = $"'{Path.GetFileName(SelectedPlugin.Path)}' does not contain the class 'Plugin' in namespace '{Path.GetFileNameWithoutExtension(SelectedPlugin.Path)}'.";
                    ShowErrorDialog(msg);
                    GConsole(e.Message);
                }
                catch(SerializationException e)
                {
                    string msg = $"'{Path.GetFileName(SelectedPlugin.Path)}' does not inherit from 'MarshalByRefObject' class.";
                    ShowErrorDialog(msg);
                    GConsole(e.Message);
                }
        }

        public void Unload()
        {
            if(SelectedPlugin != null && SelectedPlugin.Status == PluginStatus.Loaded)
                Manager.PluginManager.Instance.Unload(SelectedPlugin);
        }


        #region Helpers

//... Muss wieder Zeichen sparen.
    }

Thema: ListView reagiert nicht auf Änderung eines Enums
Am im Forum: GUI: WPF und XAML

Moin,
ich tue mir gerade schwer beim richtigen Einbinden eines Enum in eine ListView mittels MVVM. Die ListView wird vom ObservableCollection<Plugin> befüllt. Nach dem Start wird das Enum gelesen und richtig angezeigt, sowohl als Text als auch als Image via Converter.
Beim Laden und Entladen eines Plugins wird der Wert des Enum-Propertys (State) verändert. Die Veränderung wird aber nicht von der ListView registiert, aber sehr wohl von den Buttons, die jenach Value des Enums aktiviert und deaktiviert werden.

Auf dem Screenshot im Anhang sieht man es deutlicher, als ich es beschreiben kann. Das Plugin wird beim Start geladen und sowohl das Icon als auch der State sind richtig. Nachdem ich das Plugin entladen habe, reagierten die Buttons, aber nicht die ListView.

Google hilft mir leider nicht weiter, denn obwohl ich nach ListView suche, sind die meisten Treffer über Comboboxen.

Wie macht man das richtig?

XAML:


<Window x:Class="TestApp.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:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:local="clr-namespace:TestApp"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="150" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>

            <Grid
                Grid.Column="0" Grid.Row="0"
                HorizontalAlignment="Stretch"
                VerticalAlignment="Stretch"
                Margin="0, 5, 0, 0">
                
                <ListView
                    Name="PluginListView"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Top"
                    ItemsSource="{Binding PluginList}"
                    SelectedItem="{Binding SelectedPlugin}"
                    SelectionMode="Single"
                    SizeChanged="PluginListView_OnSizeChanged" Loaded="PluginListView_OnLoaded">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Width="32">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <Image Tag="{Binding State}" Width="16" Height="16" Margin="0">
                                            <Image.Style>
                                                <Style TargetType="Image">
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Loaded">
                                                            <Setter Property="Source" Value="/Resources/green_icon.png"/>
                                                        </DataTrigger>
                                                        <DataTrigger Binding="{Binding Path=Tag, RelativeSource={RelativeSource Self}}" Value="Unloaded">
                                                            <Setter Property="Source" Value="/Resources/red_icon.png"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </Image.Style>
                                        </Image>
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                            <GridViewColumn Header="Path" DisplayMemberBinding="{Binding ProjectPath}" Width="Auto" />
                            <GridViewColumn Header="State" DisplayMemberBinding="{Binding State}" Width="80"/>
                            <GridViewColumn Header="Auto Load" Width="80">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <CheckBox
                                            IsChecked="{Binding Path=AutoLoad, Mode=TwoWay}"
                                            HorizontalAlignment="Center"
                                            Checked="OnCheckboxCheckChange"
                                            Unchecked="OnCheckboxCheckChange"/>
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                            <GridViewColumn Header="Auto Reload" Width="80">
                                <GridViewColumn.CellTemplate>
                                    <DataTemplate>
                                        <CheckBox
                                            IsChecked="{Binding Path=AutoReload, Mode=TwoWay}"
                                            HorizontalAlignment="Center"
                                            Checked="OnCheckboxCheckChange"
                                            Unchecked="OnCheckboxCheckChange"/>
                                    </DataTemplate>
                                </GridViewColumn.CellTemplate>
                            </GridViewColumn>
                        </GridView>
                    </ListView.View>
                </ListView>
                <TextBox
                    Text="{Binding GConsoleText}"
                    Name="GConsole"
                    VerticalAlignment="Bottom"
                    MinHeight="100"/>
            </Grid>
            <StackPanel Grid.Column="1">
                <StackPanel Orientation="Horizontal" Margin="5">
                    <Button
                        Content="Add"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Padding="3"
                        Command="{Binding AddCommand}" />
                    <Button
                        Content="Remove"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Margin="10, 0, 0, 0"
                        Padding="3"
                        Command="{Binding RemoveCommand}" CommandParameter="Remove"/>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="5">
                    <Button
                        Content="Load"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Padding="3"
                        Command="{Binding LoadCommand}" CommandParameter="Load"/>
                    <Button
                        Content="Unload"
                        HorizontalAlignment="Left"
                        VerticalAlignment="Top"
                        Margin="10, 0, 0, 0"
                        Padding="3"
                        Command="{Binding UnloadCommand}" CommandParameter="Unload"/>
                </StackPanel>
            </StackPanel>
        </Grid>
    </Grid>
</Window>

(Kann leider nicht mehr Code einfügen, da ich 8k Zeichen aufgebraucht sind.)

Thema: VS anweisen beim Debuggen Framework ins eigene Verzeichnis zu kopieren
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Moin,
ich nutze für meine GUI WPF und für die Button-Commands die Klasse CommandHandler. Dafür hat VS das Framework Microsoft.VisualStudio.Uitilities installiert. Funktioniert wunderbar. Aber nach dem Debuggen kopierte VS die benütigten Dateien ins Stammverzeichnis. Jetzt sieht das so aus wie im Anhang.

Kann man VS 2022 anweisen, daß das Framework ins eigene Unterverzeichnis kopiert werden soll, damit es etwas aufgeräumter aussieht?

Thema: FileSystemWatcher "blockt" Datei
Am im Forum: Grundlagen von C#

Ich habs raus. War das eine schwere Geburt! Es liegt nicht am Code! Und ich bin irgendwie froh drüber. Aber dein Verweis auf VS war auch richtig. Ich habe VS zweimal offen. Einmal mit der TestApp und einmal mit dem TestPlugin. Schließe ich das VS mit der TestApp und starte das Programm aus dem bin/Debug-Ordner, funktioniert der Build vom TestPlugin anstandslos. Puuuuuh! Blöderweise kommt der Fehler auch, wenn ich zwei verschiedene VS Versionen für die beiden Projekte nutze. 2019 und 2022 beißen sich auch.

Zitat
Jetzt fängst an zu stochern statt strukturiert vorzugehen, das macht kein Sinn.
Du, das ist ein Hobby. Ich mache das nicht professionell. Paarmal im Jahr überkommt es mich und ich habe plötzlich eine Idee, die ich programmieren will, und dann artet es schon öfter in einer Trail & Error-Orgie aus. Googlen, Code-Beispiele ausprobieren, noch mehr Beispiele ausprobieren, grübeln, was ich anders machen könnte, frei nach dem Motto: wenn ich nich so rum, dann andersrum..., ausprobieren, usw. Aber nichts gegen Weiterentwicklung, wenn du mir einen Hinweis gibts, wie man strukturiert Fehler sucht, versuche ich es gerne.

Thema: FileSystemWatcher "blockt" Datei
Am im Forum: Grundlagen von C#

Ich habe jetzt nochmal paar Ideen ausprobiert, z.B. habe ich den Watcher als erstes erstellt und dann die AppDomain. Hat nicht funktioniert. Darauf hin habe ich alles einzeln auskommentiert, spricht die Elemente von AppDomain, Copy und FSW, bis zu der Stelle, an der VS den Build ohne Probleme durchführt. Funktioniert hat haben diese Mal tatsächlich AppDomain mit dem Watcher, aber ohne File.Copy (es wurde die dll geladen, die bereits im Plugin-Verzeichnis war). Das ist wieder einer dieser Momente, an dem ich geneigt bin zu glauben, daß mein Code ein Eigenleben hat. Denn, es war beim Schreiben des Codes anders. Da war es noch der FSW. Und eigentlich sollte das Lesen einer Datei nichts locken. Wie auch immer.

Ich habe File.Copy durch FileStream ersetzt um zu schauen, ob sich etwas ändert.


//File.Copy(fileFrom, fileTo, overwrite: true);
            using(var streamFrom = new FileStream(
                fileFrom,
                FileMode.Open,
                FileAccess.Read,
                FileShare.ReadWrite))
            {
                using(var streamTo = new FileStream(fileTo, FileMode.Create))
                {
                    var buffer = new byte[0x10000];
                    int bytes;

                    while((bytes = streamFrom.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        streamTo.Write(buffer, 0, bytes);
                    }
                }
            }
Leider ändert sich am Verhalten nichts.

Dann kam mir die Idee, das Kopieren async durchzuführen, um wirklich sich er zu sein, daß der Kopiervorgang auch abgeschlossen wurde.

//File.Copy(fileFrom, fileTo, overwrite: true);            
            CopyFileAsync(fileFrom, fileTo).Wait();

...

private async Task CopyFileAsync(string sourcePath, string destinationPath)
        {
            using(Stream source = File.OpenRead(sourcePath))
            {
                using(Stream destination = File.Create(destinationPath))
                {
                    await source.CopyToAsync(destination);
                }
            }
        }
Hehe, beim Klick auf den Load Button friert die GUI ein und es tut sich nichts (dachte immer, async + await sollen genau das verhindern). In der Konsole wird auch nichts mehr ausgegeben, d.h. das Programm kommt erst gar nicht so weit die dll zu laden. Ich habe vorher nicht versucht ein Build zu erstellen, die GUI friert immer und bei jedem Versuch ein.


Was das Plugin angeht, ja, es hat noch kein Dispose. Es besteht aus reinen TestMethoden. Alles andere kommt erst in den nächsten Schritten.

public class MyPlugIn : MarshalByRefObject, IPlugIn
    {
        public void DoSomething()
        {
            Console.WriteLine("working...");
        }

        string IPlugIn.DoSomethingElse(string message)
        {
            Console.WriteLine(message);
            return "Something else done...";
        }
    }

Thema: FileSystemWatcher "blockt" Datei
Am im Forum: Grundlagen von C#

Das ist mir schon bewusst, daß es am Code liegt. Aber am welchen Teil des Codes? Am Dispose kann es nicht wirklich liegen, da FSW während des Build-Vorgangs noch läuft und laufen muss, damit er eben diesen registriert und feuert. Dispose geschieht erst danach. Das Builden läuft aber schon nach dem ersten Laden der Dll nicht rund, also bevor der FSW das erste Mal disposet wird.

Thema: FileSystemWatcher "blockt" Datei
Am im Forum: Grundlagen von C#

Ich habe Dispose() tatsächlich nicht benutzt. Habe es eingefügt und es ändert sich leicht etwas. Beim ersten Mal kann ich nicht builden, auch, wenn ich eine Minute lang warte, bevor ich builde. Drücke ich gleich danach nochmal F6, geht das. Entlade und lade ich die AppDomain, fängt das Spiel von vorn an. Er buildet beim zweiten Mal auch, wenn ich gleich nach dem Laden der dll zweimal builde.

Ich habe aber eben herausgefunden, daß wenn ich die .pdb-Datei im bin/Debug lösche, buildet er auch beim ersten Mal. Scheinbar wird die Blockade aufgehoben, wenn sich etwas im Verzeichnis ändert. Erstelle ich nach dem Aufrufen des Watchers eine leere Text-Datei im bin/Debug und warte paar Sekunden, kann ich beim ersten Mal builden oder ich builde zweimal. Aber nach dem Reload fängt auch das nochmal an. Wahrscheinlich braucht der Watcher etwas bis er disposet.


public partial class MainWindow : Window
    {
        private Contracts.IPlugIn _plugin;
        private AppDomain _domain;
        private FileSystemWatcher _watcher;

        public MainWindow()
        {
            // For english exceptions
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");

            InitializeComponent();
        }

        private void BtnLoadPlugin_Click(object sender, RoutedEventArgs e)
        {
            string fileFrom = "J:\\workspace\\_csharp\\Projects\\_test\\TestPlugIn\\bin\\Debug\\TestPlugIn.dll";
            string fileTo = "J:\\workspace\\_csharp\\Projects\\_test\\PlugInManager\\TestApp\\bin\\Debug\\PlugIns\\TestPlugIn.dll";
            File.Copy(fileFrom, fileTo, overwrite: true);

            _domain = AppDomain.CreateDomain("TestPlugIn", AppDomain.CurrentDomain.Evidence, new AppDomainSetup
            {
                ApplicationName = "TestPlugIn",
                ApplicationBase = "J:\\workspace\\_csharp\\Projects\\_test\\PlugInManager\\TestApp\\bin\\Debug\\PlugIns",
            });

            _plugin = (IPlugIn)_domain.CreateInstanceAndUnwrap("TestPlugIn",
                $"{"TestPlugIn"}.{"MyPlugIn"}");


            _plugin.DoSomething();
            string msg = _plugin.DoSomethingElse("Do Something else...");
            Console.WriteLine(msg);

            _watcher = new FileSystemWatcher("J:\\workspace\\_csharp\\Projects\\_test\\TestPlugIn\\bin\\Debug\\")
            {
                NotifyFilter = NotifyFilters.LastWrite,
            };
            _watcher.EnableRaisingEvents = true;
            _watcher.Changed += OnFolderChanged;

            string workaround = "J:\\workspace\\_csharp\\Projects\\_test\\TestPlugIn\\bin\\Debug\\workaround.txt";
            File.Create(workaround).Dispose();
        }

        private void BtnUnloadPlugin_Click(object sender, RoutedEventArgs e)
        {
            AppDomain.Unload(_domain);
            _watcher.Changed -= OnFolderChanged;
            _watcher.Dispose();          
            _watcher = null;
        }

        private void OnFolderChanged(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"File Changed: '{e.Name}'.");
        }
    }

Ich verstehe aber nicht, was das alles bin mit obj/Debug Verzeichnis zu tun hat und warum der FSW in einem eigenen Projekt, ohne das Laden und Entladen von AppDomains, keinen Einfluss auf VS hat und ich builden kann, obwohl er permanent das bin/Debug-Verzeichnis überwacht.

Thema: FileSystemWatcher "blockt" Datei
Am im Forum: Grundlagen von C#

Moin,
ich möchte .dlls dynamisch laden und entladen und habe mich an der ersten Anwort in diesem Post orientiert.

Das Programm kopiert eine Dll aus dem Debugverzeichnis eines anderen Projekts (Plugin), läd die Dll und schaltet den FileSystemWatcher ein, der das bin/Debug-Verzeichnis des Plugin-Projekts überwacht. Wenn ich das Projekt builde und die Dll überschrieben wird, soll der Watcher feueren. Am Ende soll das Entladen, Kopieren und Laden der Dll aus dem Debug-Verzeichnis automatisch ablaufen. Momentan benutze ich noch für das LAden und Entladen Buttons.

Das ist der Code:


private void BtnLoadPlugin_Click(object sender, RoutedEventArgs e)
        {
            string fileFrom = "J:\\workspace\\_csharp\\Projects\\_test\\TestPlugIn\\bin\\Debug\\TestPlugIn.dll";
            string fileTo = "J:\\workspace\\_csharp\\Projects\\_test\\PlugInManager\\TestApp\\bin\\Debug\\PlugIns\\TestPlugIn.dll";
            File.Copy(fileFrom, fileTo, overwrite: true);

            _domain = AppDomain.CreateDomain("TestPlugIn", AppDomain.CurrentDomain.Evidence, new AppDomainSetup
            {
                ApplicationName = "TestPlugIn",
                ApplicationBase = "J:\\workspace\\_csharp\\Projects\\_test\\PlugInManager\\TestApp\\bin\\Debug\\PlugIns",
            });

            _plugin = (IPlugIn)_domain.CreateInstanceAndUnwrap("TestPlugIn",
                $"{"TestPlugIn"}.{"MyPlugIn"}");


            _plugin.DoSomething();
            string msg = _plugin.DoSomethingElse("Do Something else...");
            Console.WriteLine(msg);

            _watcher = new FileSystemWatcher("J:\\workspace\\_csharp\\Projects\\_test\\TestPlugIn\\bin\\Debug\\")
            {
                NotifyFilter = NotifyFilters.LastWrite,
            };
            _watcher.EnableRaisingEvents = true;
            _watcher.Changed += OnFolderChanged;
        }

        private void BtnUnloadPlugin_Click(object sender, RoutedEventArgs e)
        {
            AppDomain.Unload(_domain);
            _watcher.Changed -= OnFolderChanged;         
        }

        private void OnFolderChanged(object sender, FileSystemEventArgs e)
        {
            Console.WriteLine($"File Changed: '{e.Name}'.");
        }

Das Laden und Entladen der AppDomain und der Dll funktioniert auch soweit. Leider führt das Überwachen des FileSystemWatchers irgendwie dazu, daß ich das Projekt, das vom Watcher überwacht wird, nicht builden kann.

Fehlermeldung beim Build-Versuch:
Fehler
Cannot open 'J:\workspace\_csharp\Projects\_test\TestPlugIn\obj\Debug\TestPlugIn.pdb' for writing -- 'The process cannot access the file 'J:\workspace\_csharp\Projects\_test\TestPlugIn\obj\Debug\TestPlugIn.pdb' because it is being used by another process.'

Ich brauchte eine Weile bis ich die Fehlermeldung richtig gelesen habe. Es handelt sich nicht um bin/Debug, sondern um obj/Debug. Das Verzeichnis obj/Debug wird nirgends im Code benutzt. Die beiden Projekte kannen sich nicht. Die einzige Verbindung zwischen den beiden ist das Interface IPlugin, deren Dll beide Projekte als Referenz haben.

Ich habe im Zuge meiner Recherche bereits erfahren, daß der FileSystemWatcher weder Verzeichnisse noch Dateien blocken kann. ABER, lasse ich ihn weg, lade mit dem Programm die Dll und versuche dann das Plugin-Projekt zu builden, dann klappts. Auf der anderen Seite, wenn ich nur den Wachter in einem separatem Projekt starte, kann ich builden wie ich will, läuft auch ohne Probleme. Ich komme einfach nicht dahinter, woran es liegt, daß beides zusammen nicht funktionert, aber einzeln schon.

Thema: GUI Framework für .NET 7 unter Linux Mint 21.1
Am im Forum: Cross Platform Entwicklung - Mobile und IoT

Danke dir. Von Avalonia nehme ich lieber Abstand. Das habe ich vor dem Upgrade benutzt und kann mich erinnern, daß ich eine Ewigkeit dran saß um es zum Laufen zu bekommen.
Uno zu installieren funktionierte fast auf Anhieb.

Thema: GUI Framework für .NET 7 unter Linux Mint 21.1
Am im Forum: Cross Platform Entwicklung - Mobile und IoT

Moin,
ich hab mein Linux Mint auf v21.1 upgegradet und musste dafür .net core deinstallieren. Jetzt habe ich .net wieder eingerichtet und gleich die neuste Version .net 7 genommen. Leider finde ich aber kein GUI Framework für. Gibt es schon was für .NET 7 unter Linux? Am liebsten wäre mir Qt, aber ich finde nur was für Windows.

Thema: Gibt es noch das alte simple SQLite?
Am im Forum: Datentechnologien

Ok, das hat mich jetzt sehr überrascht. Aber nach einem Blick, tief in meine Projektkiste, habe ich die Lösung des Rätsels gefunden. Erstmal: ja, ihr habt Recht, SQLite war auch schon früher mit ADO.net, und auch von der Code-Struktur her gleich.
Ich habe mir irgendwann einen kleinen Wrapper geschrieben, benutzte dann SQLite immer auf diese Weise und habe irgendwann vergessen, daß es ein Wrapper war. Jetzt, nach längerer Zeit, suchte ich nach meinen Geistern, die ich für SQLite hielt.

Thema: Gibt es noch das alte simple SQLite?
Am im Forum: Datentechnologien

Moin,
ich habe schon etwas länger keine Datenbanken verwendet. Jetzt brauche ich eine für ein kleines CRUD Projekt. Meine Wahl fiel instinktiv auf SQLite. Leider finde ich die Version nicht mehr, die ich gewohnt war.
Was ich meine, sieht man hier auf der Microsoft-Seite:
https://learn.microsoft.com/de-de/dotnet/standard/data/sqlite/?tabs=netcore-cli

Als ich das letzte Mal SQLite benutzt habe, hatte ich einen "normalen" SQL-String, den ich mit C#-Variablen dynamisch füllte. In der Microsoft Version muss man jetzt Commands kreiren, sie mit API spezifischen Variablen füllen, diese "Parameter" dann noch spezifizieren und anschießend das ganze ausführen. Viel zu umständlich für das, was ich vorhabe.
Wenn ich das richtig verstanden habe, basiert das auf ADO.net.

In VS Code wird im Nuget Package Manager als erstes Ergebnis SQLite 3.12.3 angezeigt. Aber diese Version kommt ohne Referenzen. Die Version System.Data.SQLite hingegen ist wie die Microsoft.Data.SQLite aufgebaut, also auch nicht das, was ich suche.

Gibt es das "normale" SQLite noch, ohne ADO.net?

Thema: Arbeitsverzeichnis online spiegeln
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Danke für die Tipps. Das sind sehr interessante Sachen bei. Muss mir das alles aber nochmal genauer anschauen.

Dachte die Projekte auf Github sind immer öffentlich. Scheint jetzt anders zu sein und wäre die leichteste Lösung, denke ich. Aber ein SeaFile Server auf einem RasPi ist auch ein sehr verführerischer Gedanke.

Zur Versionskontrolle:
Jaaa, habe ich eigentlich auch seit Jahren auf meiner imaginären ToDo-Liste. Mir ist auch bewusste, ich sollte das mal lernen. Das Ding ist aber, meine Projekte sind so klein, ich hatte nie den Bedarf eine Version zurückzuspringen, und schiebe es ständig vor mich hin.

Thema: Arbeitsverzeichnis online spiegeln
Am im Forum: Entwicklungs- und Laufzeitumgebung (Infrastruktur)

Moin,

ich möchte meine Projekte gerne zusätzlich zum lokalem Arbeitsverzeichnis auch online speichern. Ich laß etwas über das Thema und merkte schnell, es gibt viele Möglichkeiten. Fühle mich gerade etwas vom Thema erschlagen. Hat jemand darin Erfahrung und könnte mir einen Tipp geben, wonach ich konkret suchen sollte?

Momentan speichere ich alle meine Daten auf einen USB-Stick und arbeite mal am Desktop-PC und mal am Notebook. Auf beiden läuft sowohl Linux Mint als auch Windows 10. Auf beiden System wird auch programmiert. Oft vergesse ich den Stick zu Hause und wünschte mir dann, ich könnte den aktuellen Stand online runterladen.

Zu Verfügung stehen mir ein eigener (klassischer) Webspace - kein Server, den ich konfigurieren oder etwas drauf installieren könnte - den ich via FTP als Speicherplatz zweckentfermden könnte und Google cloud. Ich möchte es so simple wie möglich halten. Heißt, es soll automatisch hoch- und runtergeladen werden. Versionskontrolle ist nicht nötig. Es genügt mir, wenn die aktuelle Version immer online ist und die lokalen Daten überschrieben werden.

Ich nutze VS Code, da gibt es Remote SSH für, aber ich habe ja keinen Server. Vielleicht gibt es aber was anderes dafür?

Thema: Klasse existiert in zwei Namespaces, aber beide Namespaces existieren nicht
Am im Forum: Grundlagen von C#

Ok, das hat funktioniert. Vielen Dank. Habe nur die Zeile

 <PackageReference Include="System.Drawing.Common" Version="6.0.0" />
hinzugefügen müssen. Kannte ich so aber auch noch nicht.

Tue mir noch etwas schwer. Ist mein erstes C#-Projekt unter Linux und mit VS Code.

In dem Code kommt Color.FromRPG von Avalonia.Media.

Thema: Klasse existiert in zwei Namespaces, aber beide Namespaces existieren nicht
Am im Forum: Grundlagen von C#

Naja, soweit war ich auch schon...

Nun, ich nutze nicht .Net Core 3.0 sondern v6. Alles vorgestern frisch installiert. Muss ich trotzdem jetzt 3.0 installieren?

Thema: Klasse existiert in zwei Namespaces, aber beide Namespaces existieren nicht
Am im Forum: Grundlagen von C#

Moin,

ich versuche gerade den ColorTranslator zu benutzen und laufe in einen Fehler, den ich nicht wegbekomme.

Zitat
The type 'ColorTranslator' exists in both 'System.Drawing.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51' and 'System.Drawing.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' [WerkstattOrganizer]csharp(CS0433)

Das ist der Code:


using Avalonia.Media;

namespace WerkstattOrganizer
{
    public static class Utils
    {
        public static Color HexToColor(string hex)
        {
            var color = System.Drawing.ColorTranslator.FromHtml(hex);
            return Color.FromRgb(color.R, color.G, color.B);
        }
    }
}

Das Ding ist jetzt, wenn ich "System.Drawing.Common.ColorTranslator" oder "System.Drawing.Primitives.ColorTranslator" nehme, wird mir gesagt, daß diese Namespaces nicht existieren. Wie wähle ich jetzt eins von beiden aus?

Thema: Exception trotz try-catch
Am im Forum: Grundlagen von C#

Ich habe das nicht programmiert, ich benutze es nur. Es ist ein open-source Client für das uralte Ultima Online, geschrieben in C#. ClassicUO nennt er sich und das Plugin, das ich dazu benutze, ist der ClassicAssist.

Thema: Exception trotz try-catch
Am im Forum: Grundlagen von C#

@Abt:
Ja, das ist etwas komplizierter, als ich es anfangs beschrieben habe. Die eigentliche Ursache liegt in einem Plugin. Ohne das Plugin wurde die Exception nicht geworfen. Irgendwo beißen sich die beiden unter bestimmten Umständen. Nun, das Plugin ist einerseits auch open-source, andererseits hat es mehrere Hundert Klassen. Da die Exception auf den Client verweist, weiß ich nicht wo ich im Plugin suchen sollte. Alleine das Einlesen würde Wochen dauern, die Fehlersuche womöglich Monate.
Von daher ist es jetzt für mich das Naheliegendste die Exception zu umgehen, da die Methode eh nur zur Berechnung einer Amimation von Spielfiguren dient. Ich kann damit leben, wenn mal eine Figur eine Animation nicht mitmacht. Nur der Client sollte nicht dabei crashen.

@Th69:
Ehrlich gesagt: keine Ahnung. Mit Memory und Pointern habe ich mich noch nicht auseinandergesetzt. Ich weiß nur, daß der >>-Operator irgendwas mit verschieben bedeutet, aber ausrechnen und/oder überprüfen kann ich die Rechnung im Code nicht.

Thema: Exception trotz try-catch
Am im Forum: Grundlagen von C#

Habe ich das richtig verstanden, daß wenn ich das Attribut [HandleProcessCorruptedStateExceptions] hinzufüge, dann sollte die Exception gecatcht werden? Leider kann ich die Exception nicht ohne Weiteres rekonstruieren und überprüfen ob es jetzt klappt. Die wird einfach ab und zu geworfen.

Ist das so richtig?


[HandleProcessCorruptedStateExceptions]
        public unsafe AnimDataFrame CalculateCurrentGraphic(ushort graphic)
        {
            IntPtr address = _file?.StartAddress ?? IntPtr.Zero;

            if(address != IntPtr.Zero)
            {
                try
                {
                    IntPtr addr = address + (graphic * 68 + 4 * ((graphic >> 3) + 1));

                    ref AnimDataFrame a = ref Unsafe.AsRef<AnimDataFrame>((void*)addr);

                    return a;
                }
                catch(System.AccessViolationException e)
                {
                    System.Console.WriteLine(e.Message);
                    return default;
                }
            }

            return default;
        }

Thema: Exception trotz try-catch
Am im Forum: Grundlagen von C#

Sorry, mein Edit und Dein Post haben sich überschnitten.

Wenn man MemoryExceptions nicht abfangen kann, gibt es dann wenigstens eine Möglichkeit zu überprüfen, ob auf jene Stelle im Memory gerade zugegriffen werden kann?

Thema: Exception trotz try-catch
Am im Forum: Grundlagen von C#

Moin,

ich habe mir ein Open-Source-Projekt runtergeladen und bekomme da ab und zu eine Exception geworfen. Dachte, ich packe einfach an der Stelle einen try-catch Ausdruck und gut ist. Leider funktioniert das nicht. Da ich selber eigentlich sehr selten try-catch benutze, tue ich mir gerade etwas schwer das richtig zu setzen.

Der Ausnahmefehler kommt immer bei return a, ob mit oder ohne try.

Im Original sieht die Methode wie folgt aus:


public unsafe AnimDataFrame CalculateCurrentGraphic(ushort graphic)
        {
            IntPtr address = _file?.StartAddress ?? IntPtr.Zero;

            if(address != IntPtr.Zero)
            {
                IntPtr addr = address + (graphic * 68 + 4 * ((graphic >> 3) + 1));

                ref AnimDataFrame a = ref Unsafe.AsRef<AnimDataFrame>((void*)addr);

                return a;
            }

            return default;
        }

Das ist mein try-catch Versuch:


public unsafe AnimDataFrame CalculateCurrentGraphic(ushort graphic)
        {
            IntPtr address = _file?.StartAddress ?? IntPtr.Zero;

            if(address != IntPtr.Zero)
            {
                try
                {
                    IntPtr addr = address + (graphic * 68 + 4 * ((graphic >> 3) + 1));

                    ref AnimDataFrame a = ref Unsafe.AsRef<AnimDataFrame>((void*)addr);

                    return a;
                }
                catch(System.AccessViolationException e)
                {
                    System.Console.WriteLine(e.Message);
                    return default;
                }
            }

            return default;
        }

Ist das so richtig?

Edit:
Habe die Exception ganz vergessen.
Unhandled Exception: System.AccessViolationException: Attempted to read or write protected memory. Dann der Verweis auf die Zeile mit return a.

Thema: Womit erstelle ich am besten Live-Diagramme?
Am im Forum: Rund um die Programmierung

Moin, ich möchte ein Diagramm programmieren, das live mit Daten gefüttert wird, 30 mal in der Sekunde. Außerdem ist die Zeitachse auch live, d.h.
ältere Daten sollen aus dem Diagramm herausscrollen.

Was nehme ich dafür?

Canvas war meine erste Idee. Aber macht es Sinn ein Canvas mit Hunderten von Children zu fluten?

Oder doch lieber mit Bitmap arbeiten. Aber da weiß ich nicht, ob der GUI-Thread da mitkommt. Der wird jetzt schon etwas beansprucht.

Oder gibt es da noch eine ganz andere Möglichkeit?

Ahja, das ganze ist in WPF. Wobei auch hier die Frage: bietet C# für grafische Darstellungen etwas besseres an als WPF?

Thema: Image aus dem sichtbaren Bereich eines Grids rotieren
Am im Forum: GUI: WPF und XAML

Moin,

Ich habe eine grafische Drehzahlmesseranzeige mit einem transparten Bereich, in einem Grid, mit den Ausmaßen der Anzeige (Ziffernblatt). Der Anzeigebereich hat die Form eines Halbkreises und wird, je nach Stand, mit einem sich hineindrehenden Image "gefüllt". Funktioniert auch soweit.

Das Problem ist, das Image soll, wenn es außerhalb des Grid ist, nicht angezeigt werden. Wird es aber. :) Wenn ich das Image nicht drehe, sondern in der Position verändere, dann verschwindet der Teil, der nicht im Grid ist.

Scheinbar wird bei der Darstellung nur auf die Position (Margin) geachtet, aber nicht die Rotation. Meine Frage wäre: wie lasse ich ein Image aus dem sichtbaren Bereich eines Grid herausrotieren?

Das hier ist der Code für die Rotation:

public double NeedlePos
        {
            get { return needleRotation.Angle; } // TODO: Type
            set { this.NeedleImage.Dispatcher.Invoke(() => { 
                        switch (GaugeType)
                        {
                            case Type.CIRCULAR:
                                this.needleRotation.Angle = value;
                                break;
                            case Type.LINEAR_HORIZONTAL:
                                needleImage.Margin = new Thickness(value, needleImage.Margin.Top, 0, 0);
                                break;
                            case Type.LINEAR_VERTICAL:
                                needleImage.Margin = new Thickness(needleImage.Margin.Left, value, 0, 0);
                                break;
                        }
                    }); 
                }
        }

        public GaugeUI() : base()
        {
            this.backgroundImage = new Image();
            this.needleImage = new Image();

            this.NeedlePivot = new Point(0, 0);

            this.needleRotation = new RotateTransform();
            TransformGroup transformGroup = new TransformGroup();
            transformGroup.Children.Add(needleRotation);

            this.NeedleImage.RenderTransform = transformGroup;

            this.GaugeType = Type.CIRCULAR;
        }

Thema: Regex: Finde alles zwischen einem @ und einem Whitespace/Ende des Strings
Am im Forum: Rund um die Programmierung

Ja, fand das mit Redex etwas eleganter. :) Aber jetzt komme ich nicht drum herum es mit den String-Funktionen zu lösen. Mir ist aufgefallen, daß die Namen auch Space-Zeichen enthalten können. Somit muss ich alles von @ bis zur Cursor-Position auslesen.

Wie lese ich nun den Index des Cursors aus? Geht das überhaupt?

Und btw. der leere String lang an einem Fehler im ViewModel. Von daher, Redex war gar nicht so falsch, bis auf den fehlenden Ausdruck des Stringendes. Aber das nützt mir ja jetzt auch nichts mehr.

Thema: Regex: Finde alles zwischen einem @ und einem Whitespace/Ende des Strings
Am im Forum: Rund um die Programmierung

Moin,
ich quäle mich gerade mit redex ab und brauche etwas Hilfe. :)

Ich habe eine Liste mit Chat-Usern, bzw deren Namen. Wenn ich in das Input-Feld ein @ schreibe, poppt eine Liste mit den Namen auf. Mit [Tab] gibts dann die Autovervollständigung.

Nun versuche ich gerade alles hinterm @ und einem Space oder dem Ende des Strings auszulesen, um die Namensliste anzupassen.

Naja, ich krieg da immer einen leeren String raus. :)


if(this.viewModel.ChatGlobalText != string.Empty)
                {
                    Regex rx = new Regex(@"\@(.*?)\s");

                    string startsWith = rx.Match(this.viewModel.ChatGlobalText + " ").Value;
                    this.UpdatePlayerNameList(startsWith);
                }

Ich setzte da ein "künstliches" Space hinter dem String, da es ansonsten kracht. Ich weiß nicht, wie man "oder das Ende des Strings" ausdrückt.

Hoffe, jemand kann mir helfen.

Thema: Eine vererbte Klasse in einer Liste finden
Am im Forum: Grundlagen von C#

Das funktioniert. Vielen dank.

Thema: Eine vererbte Klasse in einer Liste finden
Am im Forum: Grundlagen von C#

Moin,

ich habe eine Liste mit dem Datentyp einer Base-Klasse und möchte überprüfen, ob sich ein bestimmtes vererbtes Objekt dieser Base-Klasse in der Liste befindet.

Zum Beispiel:


List<BaseTask> taskList = new List<BaseTask>();

// TaskA, TaskB und TaskC erben von BaseTask.

taskList.Add(new TaskA());
taskList.Add(new TaskB());
taskList.Add(new TaskC());

Bin da etwas ratlos und habe es wie folgt versucht:


if(taskList.Find(task => task.GetType().Name == "TaskA") != null)
// do something

Naja, es klappt nicht. Gibt es da eine andere Möglichkeit?

Thema: Wie finde ich passende Namen für Klassen und Namespaces, vor allem für kleine Helfermethoden?
Am im Forum: Grundlagen von C#

Moin,
ich verschwende sehr viel Zeit damit passende Namen für Namespaces und Klassen zu finden. Habt ihr einen "Trick", mit dem man sich das einfacher machen kann?

Vor allem bei kleinen Methoden, wie die Folgenden, fällt mir nichts ein:

public static int GenerateID()
        {
            var now = DateTime.Now;
            var date = DateTime.MinValue.AddHours(now.Hour).AddMinutes(now.Minute).AddSeconds(now.Second).AddMilliseconds(now.Millisecond);
            return (int)(date.Ticks / 10000);
        }

... oder...

public static bool IsNumeric(string str)
        {
            // wird benütigt, da TryParse eine Referenz verlangt
            float output;

            // versucht den String in ein Float zu parsen und gibt zurück ob der Versuch erfolgreich war
            return float.TryParse(str, out output);
        }
In welche Klasse packt ihr solche Methoden, die quasi von überall her angesprochen werden können? Aus Ratlosigkeit habe ich meine Klasse "Helpers" genannt und da alles reingetan.

Hoffe, ihr könnt mir weiterhelfen, denn für die ganze Namensfinderei gehen bei mir Stunden drauf.