Laden...

Variable ohne Bindung in xaml übergeben

Erstellt von Robin0 vor 10 Jahren Letzter Beitrag vor 10 Jahren 7.027 Views
R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren
Variable ohne Bindung in xaml übergeben

Hallo zusammen,

Ich versuche schon länger eine Variable im xaml zu übergeben ohne eine bindung zu erzeugen.

Im DataContext meines Hauptfensters habe ich das VievModel in dem die Liste enthalten ist.

Validation ist eine eigene klasse die von ValidationRule ableitet.
in der Validation möchte ich prüfen ob das Element in einer Liste vorkommt, diese Liste möchte ich an (object)"PermissibleValues" übergeben.
(Damit ich die klasse auch an anderen stellen verwenden kann. Nur leider bekomm ich das nich hin -.-)

Mit MvvMAddress sage ich im moment das die Liste "AllStoragePlaceStocks" heißt, ich lese diese Liste dann aus meinem ViewModel aus.

mit ValuePath geben ich an welche eigenschaft der liste ich vergleiche in disem fall "Name".


        <TextBox x:Name="tbTargetplace">
            <TextBox.Text>
                <Binding Mode="TwoWay"
                         Path="SelectedTargetPlaceName"
                         UpdateSourceTrigger="LostFocus"
                         >
                    <Binding.ValidationRules>
                        <local:Validation MvvMAddress="AllStoragePlaceStocks" Valuepath="Name" PermissibleValues="?" ValidationType="ContainsUniqueString"/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

Wie kann eine Liste aus meinem DataContext an PermissibleValues übergeben?

5.742 Beiträge seit 2007
vor 10 Jahren

Hallo Robin0,

verwende besser IDataErrorInfo zur Validierung; dann stellt sich das Problem erst gar nicht.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Hab ich mir schon angeschaut, aber ich hätte den String gern geprüft !bevor ich ihn verwende nicht danach.

16.806 Beiträge seit 2008
vor 10 Jahren

Normalerweise wird ja PropertyChanged als UpdateSourceTrigger verwendet und damit erfolgt die Validierung sofort, und nicht erst bei Verwendung.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

IDataErrorInfo wird erst durchlaufen nachdem der wert in der gebundenen Property gesetzt wurde.
Ich verwende den String der eingegeben wird eigentlich nur als abkürzung, damit der Anwender nicht die ganze Liste durchschauen muss wenn der name 2x vorkommt muss, ich dem Anwender zudem die möglichkeit geben den richtigen per Hand auszuwählen.

Ich hab ne recht große Liste die ich durchlaufe um zu prüfen wie oft der String drinn vorkommt, mir geht es hier auch hauptsächlich um die widerverwendbarkeit der Validation.

Es funktioniert ja wenn ich immer da gleiche ViewModel verwende.
Das möchte ich aber vermeiden.

immoment weise ich "PermissibleValues" noch so zu:


        public string MvvMAddress
        {
            set
            {
                try
                {
                    _MvvMAddress = value;
                    Type _Type = typeof(MainViewModel);
                    PropertyInfo _PInfo = _Type.GetProperty(value);
                    PermissibleValues = _PInfo.GetValue((new MainViewModel()), null);
                }
                catch { }
            }
        }

P
660 Beiträge seit 2008
vor 10 Jahren

Hallo,

vllt bietet dir dieser Artikel von CodeProject etwas mehr Informationen:

Validation in Windows Presentation Foundation

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Ich kann die IErrorInfo in dem fall ja nicht verwenden, da den wert überprüfen will bevor dieser übernommen wird.
Der Eigenschaftsoperator "set_SelectedTargetPlaceName(string value)" wird vor "get_IDataErrorInfo.this[string columnName]" ausgeführt, was das problem aufwirft, das ich nicht prüfen kann ob der Wert korrekt ist !bevor ich ihn in das Feld "_SelectedTargetPlaceName" schreibe.

Wenn ich im der ValidationResultden wert "false" das Feld "IsValid" eintrage, wird die eigenschaft "set_SelectedTargetPlaceName(string value)" garnichterst aufgerufen.
Mit "get_IDataErrorInfo.this[string columnName]" kan ich den aufruf leider nicht kontrollieren.

Ich will ja nur wissen wie ich eine Eigenschaft ohne eine Bindung übergeben kann. Das wird in anderen fällen sicher auchnoch nützlich sein.

P
660 Beiträge seit 2008
vor 10 Jahren

wenn du mal mit den Informationen die in dem Artikel sind, etwas weiter gesucht hättest, wärst du
bestimmt mal auf ValidationStep gestossen.
Mit RawProposedValue kannst du sogar den Wert prüfen, bevor irgendeine art von Konvertierung stattfindet.
Somit würde dein Wert zuerst die ValidationRule durchlaufen und du könntest ein False/True als Result zurückgeben.

MfG
ProGamer*Der Sinn Des Lebens Ist Es, Den Sinn Des Lebens Zu Finden! *"Wenn Unrecht zu Recht wird dann wird Widerstand zur Pflicht." *"Ignorance simplifies ANY problem." *"Stoppt die Piraterie der Musikindustrie"

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Das will ich doch die ganzezeit machen, nur würde ich meiner validation gerne eine Liste mitgeben, die sich in meinem ViewModel befindet.

eien DependencyProperty kann ich nicht verwenden, da ich dann von DependencyObject erben müsste, meine Validationsklasse erbt aber schon von ValidationRule.

so sieht meine Validationsklasse aus(unnötiges entfernt)
Der aufruf steht ja schon oben, ich möchte gerne PermissibleValues eine Liste übergeben, die sich in mienem MainviewModel befindet


  class Validation : ValidationRule
    {
        private object _PermissibleValues;
        public object PermissibleValues
        {
            get { return _PermissibleValues; }
            set { _PermissibleValues = value; }
        }

        public static int updateValidates = 0;
        public static void UpdateSource()
        {
            updateValidates++;
        }
        int valUpdateIndex = 0;

        private string _MvvMAddress;
        public string MvvMAddress
        {
            set
            {
                try
                {
                    _MvvMAddress = value;
                    Type _Type = typeof(MainViewModel);
                    PropertyInfo _PInfo = _Type.GetProperty(value);
                    PermissibleValues = _PInfo.GetValue((new MainViewModel()), null);
                }
                catch { }
            }
        }

        private string _Valuepath;
        public string Valuepath
        {
            get { return _Valuepath; }
            set { _Valuepath = value; }
        }

        public Validation(){ }

        public List<object> GetValues(object Val, string PropName)
        {
            List<object> MyList = GetCollection(Val);
            List<object> _out = new List<object>();

            foreach (var item in MyList)
            {
                Type _Type = item.GetType();

                PropertyInfo _PInfo = _Type.GetProperty(PropName);

                _out.Add(_PInfo.GetValue(item, null));
            }

            return _out;
        }

        public List<object> GetCollection(object Val)
        {
            Type _Type = Val.GetType();

            PropertyInfo _PInfo = _Type.GetProperty("Item");

            PropertyInfo _PInfoFieldCount = _Type.GetProperty("Count");
            int FieldCount = (int)_PInfoFieldCount.GetValue(Val,null);

            List<object> _out = new List<object>();

            for (int i = 0; i < FieldCount; i++)
            {
                _out.Add(_PInfo.GetValue(Val, new object[]{i}));  
            }
            
            return _out;
        }


        private StringComparison _StringComparisonType = StringComparison.OrdinalIgnoreCase;
        public StringComparison StringComparisonType
        {
            get { return _StringComparisonType; }
            set { _StringComparisonType = value; }
        }


        public ValidationResult Validate(object value, CultureInfo cultureInfo)
        {

            int index = 0;
            try
            {
                foreach (var item in GetValues(PermissibleValues, Valuepath))
                {
                    if (item.Equals(value))
                        index++;
                }
            }
            catch (Exception e)
            {
                return new ValidationResult(false, "Illegal Input or " + e.Message);
            }

            if (index == 0)
            {
                return new ValidationResult(false, "Request does not exist!");
            }
            if (index == 1)
                return new ValidationResult(true, null);
            if (index > 1)
            {
                return new ValidationResult(false, "Not unique!");
            }


            return new ValidationResult(false, "\t!!!!!\t");
        }
    }

(Eigentlich habe ich mehrere ValidationsFunktionen hab ich aber jetz mal weggelassen, wird sonst zu lang)

F
10.010 Beiträge seit 2004
vor 10 Jahren

Ich kann die IErrorInfo in dem fall ja nicht verwenden, da den wert überprüfen will bevor dieser übernommen wird.

Da hast du etwas falsch vetstanden.
IDataErrorInfo ist zur Anzeige der Fehler nicht zur Validierung.

Die Validierung findet normalerweise im Setter des Properties statt.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Ja, ich weiß das will es deshalb ja nich verwenden.

5.742 Beiträge seit 2007
vor 10 Jahren

Ja, ich weiß das will es deshalb ja nich verwenden.

Evtl. wäre es eine Überlegung wert, dein viewModel so umzustellen, dass es zwar ungültige Werte in seinen eignen Properties zulässt, aber nur gültige Werte weitergibt.
Dann kannst du wunderbar Validierungsfehler mittels IdataErrorInfo anzeigen und bist deine Probleme los.

Alternativ kannst du auch mittels Exception Validierungsfehler auslösen (Binding.ValidatesOnException) oder so. Davon würde ich aber eher abraten und diese Vorgehensweise nur für die Schicht unter den ViewModels anwenden.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Ich hätt trotzdem gern gewusst wie ich ne variable ohne binding übergebe. Die angeführte Validation is nur eins von vielen beispielen wo dies hilfreich wär.

F
10.010 Beiträge seit 2004
vor 10 Jahren

Ja, ich weiß das will es deshalb ja nich verwenden.

Äh wie bitte?
Wenn ich mir deinen Code und deine Erklärungen anschaue dann denke ich das du es eben nicht wirklich verstanden hast.

Harte Validierung findet immer im Setter statt durch Ablehnung der Übernahme des neuen Wertes.
Weiche Validierung übernimmt die Werte und benachrichtigt lediglich den Benutzer.
Ersteres braucht kein IDataErrorInfo, letzteres auf jeden Fall.

Die angeführte Validation is nur eins von vielen beispielen wo dies hilfreich wär.

Und deshalb ist Validierung auch ein sehr schlechtes Beispiel für deine Anfrage.

In WPF gibt es eigentlich nicht wirklich einen Grund auf DataBinding zu verzichten.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Ich glaube ihr habt meine frage nicht richtig verstanden.

Ich suche einen weg in WPF eine eigenschaft zu übergeben, ohne ein DataBinding erstellen zu müssen.

Ob das sinvoll ist oder nicht sei einmal mal dahingestellt.
Ich kann die Validierung auch in einer Funk<in T,out result> veranstalten, und die übergeben, dazu müsste ich aber auch ohne Binding eigenschaften übergeben können.

Die tatsache das ich nicht weiß wie das geht stört mich, aus diesem grund hab ich die frage ja gestellt.

Der grund für die verwendung der Validate klasse ist die hohe widerverwertbarkeit, ich kann die klasse später über ein TFS öffentlich machen und in anderen projekten verwenden. Zudem hab ich somit den Luxus die übersichtlichkeit meines ViewModels zu verbessern.

5.657 Beiträge seit 2006
vor 10 Jahren

Ich glaube ihr habt meine frage nicht richtig verstanden.
Ich suche einen weg in WPF eine eigenschaft zu übergeben, ohne ein DataBinding erstellen zu

Das hast du jetzt schon fünf- oder sechsmal gesagt. Was meinst du damit? Für mich ist "Binding" und "Übergabe" das gleiche.

Christian

Weeks of programming can save you hours of planning

2.298 Beiträge seit 2010
vor 10 Jahren

Hallo Robin0,

das vorgehen was du erreichen möchtest ist schlicht und ergreifend in WPF nicht vorgesehen. XAML ist nur die Auszeichnung für die Oberfläche. - Die kann (abgesehen von Binding) überhaupt nicht mit Objekten des Codebehind kommunizieren (abgesehen von der zur View gehörenden Codebehind Klasse und hier auch nur über Events / Commands).

Wissen ist nicht alles. Man muss es auch anwenden können.

PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |

T
461 Beiträge seit 2013
vor 10 Jahren

Ich muß gestehen ich versteh ihm auch nicht.

Das ist doch das optimale, trenne Visuelles mit Code, der Oberfläche sollte es egal sein was dahinter passiert, im Großen und Ganzen...

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

F
10.010 Beiträge seit 2004
vor 10 Jahren

Der grund für die verwendung der Validate klasse ist die hohe widerverwertbarkeit, ich kann die klasse später über ein TFS öffentlich machen und in anderen projekten verwenden. Zudem hab ich somit den Luxus die übersichtlichkeit meines ViewModels zu verbessern.

Du versuchst hier mit Gewalt genau das Gegenteil zu tun was man machen sollte.

  1. Natürlich kannst du eine Klasse zur Validierung erstellen, alles andere wäre auch falsch.
  2. Solltest du dann aber verstehen das du dich an die in WPF ( und vorher in WForms ) eingebauten, funktionierenden und gut unterstützten Interfaces halten solltest.

In Exception einer Property bei Datenbindung abfangen - BindingComplete? habe ich mal eine kleine Demo bereitgestellt ( ValidationEngine ist C#, Program in VB.NET ).
Da siehst du wie einfach das ist, wenn man sich nicht mit Gewalt dagegen streubt.

Ach ja, natürlich kannst du bei jedem WPF Control auf Werte von Hand setzen.
Da musst du keine Eigenschaften übergeben sondern Werte.

R
Robin0 Themenstarter:in
212 Beiträge seit 2012
vor 10 Jahren

Dann halten wir fest, es funktioniert nicht, das hatte ich schon befürchtet, dann muss ich mir was anderes überlegen.

Trotzdem danke an alle die sich der Frage angenommen haben. 😃

F
10.010 Beiträge seit 2004
vor 10 Jahren

Du musst nichts Überlegen, sondern mal verstehen was wir versuchen dir zu erklären.