Laden...

Forenbeiträge von CodeHamster Ingesamt 6 Beiträge

06.11.2019 - 21:56 Uhr

Deine Eigenschaft heißt Text und dein DependencyProperty MyProperty, das kann nicht funktionieren.

Darauf habe ich schon vorher reagiert, aber du hast es offenbar überlesen. Lies dir mal den Quelltext durch, die Variable Text hat nichts mit der Property zu tun. Ich binde die Variable **My **an die Property

hier der Codeschnipsel:

public static readonly DependencyProperty MyProperty = DependencyProperty.Register("My", typeof(string), typeof(Bena), new PropertyMetadata("leer")); 

        public string My
        {
            get
            {
                Console.WriteLine("Lese Wert aus");
                return (string)this.GetValue(MyProperty);
            }
            set { this.SetValue(MyProperty, value); Console.WriteLine("Setze den Wert neu"); }
        }

Und die Geometrie, die du erzeugst, gehört ins ViewModel. Genau wie Daten einer Liste ins ViewModel gehören und an die Liste in der View gebunden werden, gehören die Geometrie-Daten ins ViewModel und werden an den Viewport3d in der View gebunden.

Nicht bös sein, aber du übertreibst es. Du siehst es so, ich sehe es anders.
Die für die Darstellung benötigte technische Berechnung gehört in die Klasse, welche das Objekt representiert. Viewmodel hin oder her.

Ich empfehle auch den
>
, der nimmt dir bei der 3D-Darstellung einiges an Arbeit ab.

Das Helix-Toolkit kenne ich bereits. Nützt mir bei den Objekten die ich brauche nur nichts.

Mal davon abgesehen, habe ich es gefunden
und zwar hier:

https://docs.microsoft.com/de-de/dotnet/framework/wpf/advanced/dependency-property-callbacks-and-validation

tatsächlich muß die Deklaration der Property angepasst werden, speziell muß ein anderer Konstruktor für die PropertyMetadata, welches die **PropertyChangedCallback **unterstützt gewählt werden. So sieht es nun aus:

public static readonly DependencyProperty MyProperty = DependencyProperty.Register("My", typeof(string), typeof(Bena), new PropertyMetadata("leer", new PropertyChangedCallback(OnMyChanged)));

Folgende Funktion wird beim Setzen meiner Variable My aufgerufen:

        private static void OnMyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //Was auch immer hier aufgerufen wird, dies passiert wenn meine Variable My geändert wird
            Console.WriteLine(d.ToString() + " " + e.ToString());
        }

da geht sogar noch mehr, ich kann **CoarcedValueCallback **und **ValidateValueCallback **nutzen 😃

Sieht gut aus 😮)

PS: ich habe das kleine Beispiel-Projekt hochgeladen falls noch jemand auf der Suche nach dieser Lösung ist

06.11.2019 - 21:30 Uhr

Also solange du die Naming-Conventions für DependencyPropertys und die Hinweise auf die Doku, und sogar die Beispiele ignorierst, kann dir natürlich niemand weiterhelfen.

Bitte beachte
>

wieso ignoriere ich die? ich habe doch den Namen der Property entsprechend geändert

06.11.2019 - 21:27 Uhr

Lies nochmal die Doku zu den DependencyPropertys. Es müßte so aussehen:

  
public class Bena : ModelVisual3D  
    {  
  
        public string Text { get; set; }  
  
        public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(Bena), new PropertyMetadata("leer"));   
    }  
  

das ist quasi das gleich dass auch bei mir steht, nur habe ich es nicht mit der Text-Variable umgesetzt, sondern mit der Variable namens My

Davon abgesehen ist das, wie schon gesagt, der falsche Weg.

sehe ich ehrlich gesagt nicht so. Bena ist im Moment ein Platzhalter für ein bestimmtes, dynamisch generiertes Objekt, welches unter bestimmten Bedingungen seine Form verändert. Es besteht aus hunderten Dreiecken, welche algorithmisch, dynamisch erzeugt werden.
Es stellt sich da die Frage ob man so etwas überhaupt in XAML implementieren kann.

Keine Ahnung, was du genau vor hast, aber ModelVisual3D verwendest du in der View, und bindest die Geometrie-Daten an die ModelVisual3D.Content-Eigenschaft.

Wie gesagt, Bena ist nur ein Platzhalter. Die richtige Klasse setzt sich die Content-Eigenschaft selbst.
Außerdem gibt es in der View ein Viewport3D und Bena wird diesem über Children.add hinzugefügt.

Die Geometrie-Daten kannst du im ViewModel erzeugen und dann an die View binden.

Und dann soll ich mich also von der Objektorientierung verabschieden und alles in einem komplett überladenen Viewmodel reinpacken?
Ich möchte Bena mit verschiedenen Facetten des Viewmodels koppeln und auch mehrere, aufgrund ihrer Bindung und der daraus generierten Darstellung unterschiedliche Objekte darstellen.

Erzähl mal, was du eigentlich vor hast.

Ganz einfach, ich will das mein Custom Objekt an Variable(n) im Viewmodel gebunden wird. Wird eine Variable im ViewModel geändert, muß ich eine Funktion aufrufen können, damit mein Objekt u.U. angepasst wird.

Hier ein Beispiel:
Nimm mal z.B. drei Mauern. du hast die linke, rechte und mittlere Mauer.
die linke ist an materialLinks im Viewmodel, die mittlere ist an MaterialMitte und die rechte an MaterialRechts gebunden.
_MaterialLinks _hat den Wert Backstein, _MaterialMitte _und _MaterialRechts _haben _Beton _als Wert.

Da erzeuge ich mir drei Objekte meiner Klasse und binde sie entsprechend an meine Variablen im Viewmodel.
_MauerRechts _sei noch an _MauerRechtsRandRechts _gebunden und der Wert ist nun "ausgerissen". Von der Darstellung wird sich der rechte MauerRand schon deutlich von den anderen Rändern der Mauern unterscheiden. Es ist dennoch ein Objekt der Klasse Mauer und diese Klasse muß das Leisten was ich von ihr will, weil ich sie dahingehend entsprechend programmiere.
Die Logik der Darstellung des rechten Randes gehört genau in meine Klasse.

Repariert mir nun jemand den rechten Rand der rechten Mauer, indem er die Variable _MauerRechtsRandRechts _ auf "gerade" setzt, so muß ich eine Funktion aufrufen können, welche das 3D-Objekt anpasst.

Das nun der interne Wert von Bena über BindingOperations.SetBinding bei Änderung der bestimmten Variable im Viewmodel auch geändert wird ist schon mal ein Fortschritt.
Dennoch muß es eine Möglichkeit geben über die Änderung auch informiert zu werden.
INotifyPropertyChanged hilft hier seltsamerweise nicht.

06.11.2019 - 20:56 Uhr

Bist Du Dir da sicher? Hast Du versucht, den Wert nach der Änderung im MainViewModel aus der gebundenen Property in Bena mal abzurufen?

Hey, du hast Recht! ich habe quick 'n dirty einen Button mit einem Event in die Oberfläche eingebaut:

private void Button_Click(object sender, RoutedEventArgs e)
        {
            Console.WriteLine(mvm.My + " und nun die MyPropery aus Bena: " + bena.My);
        }

und tatsächlich:

blah22 und nun die MyPropery aus Bena: blah22

nur blöd dass mein Setter nicht aufgerufen wird. Es soll schließlich eine Routine aufgerufen werden, welche das 3D-Objekt u.U. anpasst.

Ich habe versucht das INotifyPropertyChanged Interface in Bena zu implementieren, aber das wird auch nicht aufgerufen, obwohl sich die Propery namens My sich ja offensichtlich ändert.

So sieht bena nun aus:

public class Bena : DependencyObject, INotifyPropertyChanged
    {
        private string text;

        public string Text { get => text; set => text = value; }

        public static readonly DependencyProperty MyProperty = DependencyProperty.Register("My", typeof(string), typeof(Bena), new PropertyMetadata("leer")); //new UIPropertyMetadata(0, (sender, e) => OnMyPropertyChanged(sender, e)));

        public event PropertyChangedEventHandler PropertyChanged;

        public string My
        {
            get
            {
                Console.WriteLine("Lese Wert aus");
                return (string)this.GetValue(MyProperty);
            }
            set { this.SetValue(MyProperty, value); Console.WriteLine("Setze den Wert neu"); }
        }


        public Bena()
        {
            text = "";
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            Console.WriteLine("INotofypropertychanged wird in Bena ausgeführt");
            var handler = PropertyChanged;
            if (handler != null)
            {

                handler(this, new PropertyChangedEventArgs(propertyName));

            }
        }

    }

Jemand noch dafür ne Idee?

04.11.2019 - 21:31 Uhr

Du mußt bei der DependencyProperty die Naming Conventions beachten, siehe
>
:

okay, das habe ich nun gemacht. Bena sieht nun so aus


public class Bena : ModelVisual3D
    {
        private string text;

        public string Text { get => text; set => text = value; }

        public static readonly DependencyProperty MyProperty = DependencyProperty.Register("My", typeof(string), typeof(Bena), new PropertyMetadata("leer")); 

        public string My
        {
            get
            {
                Console.WriteLine("Lese Wert aus");
                return (string)this.GetValue(MyProperty);
            }
            set { this.SetValue(MyProperty, value); Console.WriteLine("Setze den Wert neu"); }
        }


        public Bena()
        {
            text = "";
        }

    }

Funktioniert leider immer noch nicht. Mein Objekt wird nicht benachrichtigt.

Davon abgesehen ist dort der falsche Ort für die Logik der View. Die gehört ins ViewModel.

hmm... wie sollte das denn aussehen...
selbst wenn ich mein Objekt vom Typ Bena in den ViewModel setze, so wird es nicht automatisch benachrichtigt wenn sich die Variable MyText ändert. Es gibt schließlich keine Bindung zwischen den beiden.

03.11.2019 - 21:44 Uhr

Hi Leute, ich hätte folgendes Problem:

Ich habe ein einfaches WPF-Fenster, welches ein Textfeld beinhaltet. Dieses ist an eine Variable im MainViewModel gebunden, diese nennt sich MeinText.

Soweit funktioniert meine Anwendung schon mal 😉

Anbei das MainViewModel:

public class MainViewModel : INotifyPropertyChanged
    {
        private string meinText;
        public string MeinText { set { meinText = value; OnPropertyChanged(); } 
            get
            {
                return meinText;
            }
        }

        public MainViewModel()
        {
            MeinText = "blah";
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {

                handler(this, new PropertyChangedEventArgs(propertyName));
               
            }
        }
    }

Nun möchte ich eine weitere Klasse schreiben, diese soll von ModelVisual3D abgeleitet sein (da sie später mal ein 3D-Objekt darstellen wird).

Der Klasse habe ich eine DependencyProperty spendiert; diese nennt sich: MyProperty. Hier ist die Klasse:

public class Bena : ModelVisual3D
    {
        private string text;

        public string Text { get => text; set => text = value; }

        public static readonly DependencyProperty MyProperty = DependencyProperty.Register("BetonHoehe", typeof(string), typeof(Bena), new PropertyMetadata("leer")); //new UIPropertyMetadata(0, (sender, e) => OnMyPropertyChanged(sender, e)));

        public string BetonHoehe
        {
            get
            {
                Console.WriteLine("Lese Wert aus");
                return (string)this.GetValue(MyProperty);
            }
            set { this.SetValue(MyProperty, value); Console.WriteLine("Setze den Wert neu"); }
        }


        public Bena()
        {
            text = "";
        }

    }

Nun habe ich ein Databinding Objekt erzeugt, welches mir die Bindung zwischen meiner Variable "MeinText" im MainViewModel und der DependencyProperty myProperty erzeugen soll.

Ist im Moment alles noch im CodeBehind:

 public partial class MainWindow : Window
    {
        public static MainViewModel mvm;
        public MainWindow()
        {
            mvm = new MainViewModel();
            DataContext = mvm;
            InitializeComponent();

            Bena bena = new Bena();

            Binding myBinding = new Binding("MeinText");
            myBinding.Source = mvm;
            myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
            myBinding.Mode = BindingMode.TwoWay;
            BindingOperations.SetBinding(bena, Bena.MyProperty, myBinding);
        }
    }

Der tiefere Sinn hierbei ist dass meine Klasse namens _Bena _benachrichtigt wird sobald sich meine Variable **MeinText **im _MainViewModel _ändert.
Funktioniert nur leider nicht. meine Debugging-Ausgaben kommen nicht.

Hat jemand eine Idee warum das so ist, oder eine bessere Idee wie ich das Binding zwischen MVM und meiner Custom-Klasse bewerkstelligen kann?