Laden...

[gelöst] NET.Remoting ObservableCollection<DataClass> und ItemsSource Binding Problem

Erstellt von Stipo vor 13 Jahren Letzter Beitrag vor 13 Jahren 4.335 Views
Stipo Themenstarter:in
699 Beiträge seit 2007
vor 13 Jahren
[gelöst] NET.Remoting ObservableCollection<DataClass> und ItemsSource Binding Problem

Hallo zusammen,

folgende Situation möchte ich lösen. Ich habe einen Windows Dienst, der durch einen WPF Client Daten erhalten soll und auch ausgelesen werden soll.
Soweit sollte das ja kein Problem sein.

Nun hab ich aber ein Problem bei folgendem, was ich realisieren möchte.
In meinem Remoting Object, erstelle ich eine ObservableCollection<DataClass> und lasse die dann mit Daten aus der Datenbank füllen.
Diese Collection reiche ich dann durch einen Property aus dem RemoteObject nach außen in mein WPF Programm. Dort binde ich dann die Collection an das DataGrid.ItemsSource Object.

Soweit funktioniert das schon mal.

Um neue Daten zu erfassen, erstelle ich eine Instanz meiner DataClass im WPF Client und übergebe diese dann an das RemoteObject. Im RemoteObject, füge ich die neuen Daten dann der ObservableCollection<DataClass> hinzu durch Add().
Auch das funktioniert einwandfrei.

Nun aber zu dem Problem.
Wenn ich neue Daten der Collection hinzufüge, wird mein DataGrid nicht aktualiesiert. Habe testweise schon mal den Client neu gestartet, und den Server laufen gelassen. Wenn ich den Client neu gestartet habe, wird der neue Eintrag auch im DataGrid angezeigt.

Ich schätze mal, das mein Ansatz da total falsch ist. Aber im Moment hab ich keine Ahnung wie ich das anders lösen soll.

Habt Ihr mir da ein paar stichworte, wie ich das mit NET.Remoting lösen kann?

Grüße Stephan

1.044 Beiträge seit 2008
vor 13 Jahren

Hallo Stipo,

entweder du löscht die Objekte, die nicht mehr gebraucht werden, oder du bindeset direkt an die Datenquelle. Mit "direkt" meine ich, dass du z.B. eine RemoveObservableCollection hast, die direkt die Daten liefert und aktualisiert. Daran kann dann direkt gebunden werden. Ansonsten geht das auch einfacher, indem man prüft, ob das Objekt nocht existieren soll und dann via _Remove _entfernt wird.

Ich hoffe mal, dass ich dich richtig verstanden habe.

zero_x

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 13 Jahren

Hallo zero_x,

ich denke, Du hast mich falsch verstanden.
Füge mal ein wenig Code ein, wie ich das mache:


        public FileWatcherRemote()
        {
            _watchDetailList = new ObservableCollection<WatchDetail>();
            _watchDetailList.CollectionChanged += new NotifyCollectionChangedEventHandler(_watchDetailList_CollectionChanged);
           
           // Hier hab ich dann mal noch statisch ein paar Daten eingefügt, das ich die Funtion testen kann.
           // Das abbilden der Daten in die Datenbank kommt dann noch hinzu, soll aber zu diesem Problem nicht gehören.
        }

        void _watchDetailList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            
        }

        public ObservableCollection<WatchDetail> DetailCollect
        {
            get
            {
                return _watchDetailList;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public void AddWatchDetail(WatchDetail watchDetail)
        {
            _watchDetailList.Add(watchDetail);
            // Hier sollen dann die Daten noch in die DB geschrieben werden und der Windows Dienst zum einlesen angeregt werden.
        }


// Bindung an das DataGrid
DataGridWatcherItems.ItemsSource = remoteService.DetailCollect;

// Und ein neues DataObject an den Service schicken
remoteService.AddWatchDetail(new WatchDetail("Meine Details"));

Wie gesagt, er aktualisiert mir das DataGrid im WPF Client dann nicht, wenn ich das Item der ObservableCollection<WatchDetail> hinzugefügt habe.

Grüße Stephan

6.862 Beiträge seit 2003
vor 13 Jahren

Hallo,

das Problem wird sein dass du auf Client Seite ja nur nen Proxyobjekt hast, es ist ja nicht diejenige Collection welche beim Hinzufügen vom Items Events wirft. Mit Remoting hab ich mich schon lang nicht mehr beschäftigt aber soweit ich weiß gabs da einige Fallstricke. Hier hats auch nochmal nen Beitrag auf Codeproject. Das bei dir die ObservableCollection nur nen Property deines Remoteobjects ist, macht die Sache sicherlich nicht leichter.

Baka wa shinanakya naoranai.

Mein XING Profil.

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 13 Jahren

Hallo Talla,

ich schätze mal in einem dieser Stricke hänge ich gerade.
Lese mir den Link von Dir mal durch. Wenn ich aber deine Kommentare so durchlese, sehe ich schon, das ich wohl einen anderen Weg gehen muss.

Grüße Stephan

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 13 Jahren

Hallo zusammen,

ich dreh mich gerade irgendwie im Kreis.
Habe mir nun den Artikel durchgelesen, was Talla verlinkt hat und da entschieden, das mir Variante 2 reichen würde.

Nachdem ich das nun implementiert habe, bekomme ich beim hinzufügen des Client an den Server eine Exception:

Der Typ System.Runtime.Remoting.ObjRef und die davon abgeleiteten Typen (z.B. System.Runtime.Remoting.ObjRef) dürfen in dieser Sicherheitsebene nicht deserialisiert werden.

Ich habe mir eine Klasse Server und Client geschrieben, jeweils mit einem Interface, wie im Beispiel auch.
Die Server Klasse instanziere ich dann in einer Konsolenanwendung zum testen.
Bei der Client Klasse hole ich mir dann in dem WPF -Window die Singleton Instanz der Client Klasse und rufe darin dann Connect() auf ( das ist der einzige Unterschied, den ich gemacht habe ).

Die beiden Klassen und die Interfaces habe ich in einer eigenen Assembly ausgelagert, die ich dann in der Konsole und der WPF Anwendung referenziere.

Hier noch ein bisschen Code:


    public interface IFileWatcherServer
    {
        // Einen Client hinzufügen
        void AttachClient(IFileWatcherClient client);

        // Einen Client entfernen
        void DetachClient(IFileWatcherClient client);
    }

    class FileWatcherServer : MarshalByRefObject, IFileWatcherServer
    {
        private Hashtable _clients = new Hashtable();
        
        public FileWatcherServer()
        {
            
        }
       
        public void AttachClient(IFileWatcherClient client)
        {
            if (client == null)
                return;

            lock (_clients)
            {
                _clients[RemotingServices.GetObjectUri((MarshalByRefObject)client)] = client;
                Console.WriteLine("Client \"{0}\" hinzugefügt", client);
            }
        }

        public void DetachClient(IFileWatcherClient client)
        {
            if (client == null)
                return;

            lock (_clients)
            {
                _clients.Remove(client);
                Console.WriteLine("Client \"{0}\" entfernt", client);
            }
        }
    }


    public interface IFileWatcherClient
    {
        void Connect();
    }

    public class FileWatcherClient : MarshalByRefObject, IFileWatcherClient
    {
        private IFileWatcherServer _remoteService;
        public static readonly FileWatcherClient Instance = new FileWatcherClient();

        private FileWatcherClient()
        {
                       
        }

        public void Connect()
        {
            TcpChannel channel = new TcpChannel(0);
            ChannelServices.RegisterChannel(channel, false);
            _remoteService = (IFileWatcherServer)Activator.GetObject(typeof(IFileWatcherServer), "tcp://localhost:9898/FileWatcherRemote/Service");
            _remoteService.AttachClient(FileWatcherClient.Instance); // Hier kommt die Exception
        }
    }

Hat jemand noch eine Idee?

Grüße Stephan

Stipo Themenstarter:in
699 Beiträge seit 2007
vor 13 Jahren

Nabend zusammen,

habe das/die Probleme nun gelöst.

  1. Problem mit dem aktualisieren des DataGrid.ItemsSource.
    Hier hänge ich mich nun an ein Event, was der Server feuert, wenn ein neuer Eintrag der Datenquelle hinzugefügt wurde. In dem Event setze ich dann die ItemsSource auf NULL und danach lade ich die Daten neu nach.
    Ob das nun die beste Methode darstellt, weiß ich nicht.

  2. Problem Fehlermeldung Sicherheitsebene.
    Prinzipiell konnte ich das mit diesem Blog Eintrag lösen .NET Works: Remote Events mit .NET 2.0: Generische Lösung mit Dispatcher und Adapter.

Das Problem was aber dann ja bestand, das er mir eben obige Fehlermeldung geliefert hatte. Ich hatte mich da gestern lange im Kreis gedreht und manche Blog Posts etc versucht, hatte aber immer den selben erfolg -> Exception wie oben.

Irgendwann ist mir eine kleinigkeit aufgefallen bei dem MiniChat Beispiel. Nämlich folgender kleine Code abschnitt:

            /* build channel and sink providers */
            BinaryServerFormatterSinkProvider serverSinkProvider = new BinaryServerFormatterSinkProvider();
            serverSinkProvider.TypeFilterLevel = TypeFilterLevel.Full;

            BinaryClientFormatterSinkProvider clientSinkProvider = new BinaryClientFormatterSinkProvider();

            Hashtable channelProperties = new Hashtable();
            channelProperties["port"] = remoteEndPoint.Port;

            /* boot channel */
            TcpChannel channel = new TcpChannel(channelProperties, clientSinkProvider, serverSinkProvider);

Durch das hinzufügen der BinaryServerFormatterSinkProvider und BinaryClientFormatterSinkProvider im Server und im Client konnte ich die Fehlermeldung beheben.

Warum das damit genau zusammengehangen ist, konnte ich bis jetzt noch nicht herausfinden, denn die MSDN schweigt sich da ein wenig aus, oder ich interpretiere das falsch.

Auf jedenfall konnte ich soweit meine Probleme lösen. Danke noch an alle.

Grüße Stephan

1.378 Beiträge seit 2006
vor 13 Jahren

Vielleicht ist das auch interessant: Remoting-Helfer

Lg XXX