/class/System.Windows/Mono.Xaml/MarkupExpressionParser.cs
https://github.com/andreiagaita/moon · C# · 457 lines · 343 code · 80 blank · 34 comment · 98 complexity · 7444c9de69d39f47b68010b8542250f1 MD5 · raw file
- //
- // MarkupExpressionParser.cs
- //
- // Contact:
- // Moonlight List (moonlight-list@lists.ximian.com)
- //
- // Copyright 2009 Novell, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Linq;
- using System.Text;
- using System.Windows;
- using System.Windows.Data;
- using System.Collections.Generic;
- using System.Windows.Markup;
- namespace Mono.Xaml {
- internal class SL3MarkupExpressionParser : MarkupExpressionParser {
- private IntPtr parser;
- private IntPtr target_data;
- public SL3MarkupExpressionParser (object target, string attribute_name, IntPtr parser, IntPtr target_data) : base (target, attribute_name)
- {
- this.parser = parser;
- this.target_data = target_data;
- }
- protected override object LookupNamedResource (DependencyObject dob, string name)
- {
- if (name == null)
- throw new XamlParseException ("you must specify a key in {StaticResource}");
- IntPtr value_ptr = NativeMethods.xaml_lookup_named_item (parser, target_data, name);
- object o = Value.ToObject (null, value_ptr);
- if (value_ptr != IntPtr.Zero)
- NativeMethods.value_delete_value2 (value_ptr);
- if (o == null && !parsingBinding)
- throw new XamlParseException (String.Format ("Resource '{0}' must be available as a static resource", name));
- return o;
- }
- protected override FrameworkTemplate GetParentTemplate ()
- {
- IntPtr template = NativeMethods.xaml_get_template_parent (parser, target_data);
- if (template == IntPtr.Zero)
- return null;
- INativeEventObjectWrapper dob = NativeDependencyObjectHelper.FromIntPtr (template);
- return dob as FrameworkTemplate;
- }
- }
- internal class SL4MarkupExpressionParser : MarkupExpressionParser {
- private XamlParser parser;
- private XamlObjectElement target_element;
- public SL4MarkupExpressionParser (object target, string attribute_name, XamlParser parser, XamlObjectElement target_element) : base (target, attribute_name)
- {
- this.parser = parser;
- this.target_element = target_element;
- }
- protected override object LookupNamedResource (DependencyObject dob, string name)
- {
- if (name == null)
- throw new XamlParseException ("you must specify a key in {StaticResource}");
- object o = parser.LookupNamedItem (target_element, name);
- if (o == null && !parsingBinding)
- throw new XamlParseException (String.Format ("Resource '{0}' must be available as a static resource", name));
- return o;
- }
- protected override FrameworkTemplate GetParentTemplate ()
- {
- return parser.GetParentTemplate (target_element);
- }
- }
- internal abstract class MarkupExpressionParser {
- private StringBuilder piece;
- private object target;
- private string attribute_name;
- protected bool parsingBinding;
- public MarkupExpressionParser ()
- {
- }
- public MarkupExpressionParser (object target, string attribute_name)
- {
- this.target = target;
- this.attribute_name = attribute_name;
- }
- public static bool IsTemplateBinding (string expression)
- {
- return MatchExpression ("TemplateBinding", expression);
- }
- public static bool IsStaticResource (string expression)
- {
- return MatchExpression ("StaticResource", expression);
- }
- public static bool IsBinding (string expression)
- {
- return MatchExpression ("Binding", expression);
- }
- public delegate object ExpressionHandler (ref string expression);
- public object ParseExpression (ref string expression)
- {
- if (expression.StartsWith ("{}"))
- return expression.Substring (2);
- object result = null;
- bool rv = false;
- if (!rv)
- rv = TryHandler ("Binding", ParseBinding, ref expression, out result);
- if (!rv)
- rv = TryHandler ("StaticResource", ParseStaticResource, ref expression, out result);
- if (!rv)
- rv = TryHandler ("TemplateBinding", ParseTemplateBinding, ref expression, out result);
- if (!rv)
- rv = TryHandler ("RelativeSource", ParseRelativeSource, ref expression, out result);
- return result;
- }
- private static bool MatchExpression (string match, string expression)
- {
- int dummy;
- return MatchExpression (match, expression, out dummy);
- }
- private static bool MatchExpression (string match, string expression, out int end)
- {
- if (expression.Length < 2) {
- end = 1;
- return false;
- }
- if (expression [0] != '{') {
- end = 2;
- return false;
- }
- int i;
- bool found = false;
- for (i = 1; i < expression.Length; i++) {
- if (expression [i] == ' ')
- continue;
- found = true;
- break;
- }
- if (!found) {
- end = 3;
- return false;
- }
- if (i + match.Length > expression.Length) {
- end = 4;
- return false;
- }
-
- int c;
- for (c = 0; c < match.Length; c++) {
- if (expression [i+c] == match [c])
- continue;
- end = 5;
- return false;
- }
- if (c != match.Length) {
- end = 6;
- return false;
- }
- end = i + c;
- return true;
- }
- private bool TryHandler (string match, ExpressionHandler handler, ref string expression, out object result)
- {
- int len;
- if (!MatchExpression (match, expression, out len)) {
- result = null;
- return false;
- }
- expression = expression.Substring (len).TrimStart ();
- if (expression.Length == 0)
- throw new Exception ("Expression did not end in '}'");
- result = handler (ref expression);
- return true;
- }
- public Binding ParseBinding (ref string expression)
- {
- Binding binding = new Binding ();
- parsingBinding = true;
- char next;
- if (expression [0] == '}')
- return binding;
- string remaining = expression;
- string piece = GetNextPiece (ref remaining, out next);
-
- if (next == '=')
- HandleProperty (binding, piece, ref remaining);
- else
- binding.Path = new PropertyPath (piece);
- while ((piece = GetNextPiece (ref remaining, out next)) != null) {
- HandleProperty (binding, piece, ref remaining);
- };
- parsingBinding = false;
- return binding;
- }
- public object ParseStaticResource (ref string expression)
- {
- if (!expression.EndsWith ("}"))
- throw new Exception ("Whitespace is not allowed after the end of the expression");
- char next;
- string name = GetNextPiece (ref expression, out next);
- object o = LookupNamedResource (null, name);
- #if !__TESTING
- if (o == null)
- o = Application.Current.Resources [name];
- #endif
- return o;
- }
- public object ParseTemplateBinding (ref string expression)
- {
- TemplateBindingExpression tb = new TemplateBindingExpression ();
- char next;
- string prop = GetNextPiece (ref expression, out next);
- /*FrameworkTemplate template = */GetParentTemplate ();
- tb.TargetPropertyName = attribute_name;
- tb.SourcePropertyName = prop;
- // tb.Source will be filled in elsewhere between attaching the change handler.
- return tb;
- }
- public object ParseRelativeSource (ref string expression)
- {
- char next;
- string mode_str = GetNextPiece (ref expression, out next);
- try {
- return new RelativeSource ((RelativeSourceMode) Enum.Parse (typeof (RelativeSourceMode), mode_str, true));
- } catch {
- throw new XamlParseException (String.Format ("MarkupExpressionParser: Error parsing RelativeSource, unknown mode: {0}", mode_str));
- }
- }
- private void HandleProperty (Binding b, string prop, ref string remaining)
- {
- char next;
- object value = null;
- string str_value = null;
- if (remaining.StartsWith ("{")) {
- value = ParseExpression (ref remaining);
- remaining = remaining.TrimStart ();
- if (remaining.Length > 0 && remaining[0] == ',')
- remaining = remaining.Substring (1);
- if (value is string)
- str_value = (string) value;
- }
- else {
- str_value = GetNextPiece (ref remaining, out next);
- }
- switch (prop) {
- case "FallbackValue":
- b.FallbackValue = value ?? str_value;
- break;
- case "Mode":
- if (str_value == null)
- throw new XamlParseException (String.Format ("Invalid type '{0}' for Mode.", value == null ? "null" : value.GetType ().ToString ()));
- b.Mode = (BindingMode) Enum.Parse (typeof (BindingMode), str_value, true);
- break;
- case "Path":
- if (str_value == null)
- throw new XamlParseException (String.Format ("Invalid type '{0}' for Path.", value == null ? "null" : value.GetType ().ToString ()));
- b.Path = new PropertyPath (str_value);
- break;
- case "Source":
- // if the expression was: Source="{StaticResource xxx}" then 'value' will be populated
- // If the expression was Source="5" then 'str_value' will be populated.
- b.Source = value ?? str_value;
- break;
- case "StringFormat":
- b.StringFormat = (string) value ?? str_value;
- break;
- case "Converter":
- IValueConverter value_converter = value as IValueConverter;
- if (value_converter == null && value != null)
- throw new Exception ("A Binding Converter must be of type IValueConverter.");
- b.Converter = value_converter;
- break;
- case "ConverterParameter":
- b.ConverterParameter = value ?? str_value;
- break;
- case "NotifyOnValidationError":
- bool bl;
- if (!Boolean.TryParse (str_value, out bl))
- throw new Exception (String.Format ("Invalid value {0} for NotifyValidationOnError.", str_value));
- b.NotifyOnValidationError = bl;
- break;
- case "TargetNullValue":
- b.TargetNullValue = value ?? str_value;
- break;
- case "ValidatesOnExceptions":
- if (!Boolean.TryParse (str_value, out bl))
- throw new Exception (String.Format ("Invalid value {0} for ValidatesOnExceptions.", str_value));
- b.ValidatesOnExceptions = bl;
- break;
- case "ValidatesOnDataErrors":
- if (!bool.TryParse (str_value, out bl))
- throw new Exception (string.Format ("Invalid value {0} for ValidatesOnDataErrors", str_value));
- b.ValidatesOnDataErrors = bl;
- break;
- case "ValidatesOnNotifyDataErrors":
- if (!bool.TryParse (str_value, out bl))
- throw new Exception (string.Format ("Invalid value {0} for ValidatesOnNotifyDataErrors", str_value));
- b.ValidatesOnNotifyDataErrors = bl;
- break;
- case "RelativeSource":
- RelativeSource rs = value as RelativeSource;
- if (rs == null)
- throw new Exception (String.Format ("Invalid value {0} for RelativeSource.", value));
- b.RelativeSource = rs;
- break;
- case "ElementName":
- b.ElementName = (string) value ?? str_value;
- break;
- case "UpdateSourceTrigger":
- b.UpdateSourceTrigger = (UpdateSourceTrigger) Enum.Parse (typeof (UpdateSourceTrigger), str_value, true);
- break;
- default:
- Console.Error.WriteLine ("Unhandled Binding Property: '{0}' value: {1}", prop, value != null ? value.ToString () : str_value);
- break;
- }
- }
- private string GetNextPiece (ref string remaining, out char next)
- {
- bool inString = false;
- int end = 0;
- remaining = remaining.TrimStart ();
- if (remaining.Length == 0) {
- next = Char.MaxValue;
- return null;
- }
- piece = piece ?? new StringBuilder ();
- piece.Length = 0;
- // If we're inside a quoted string we append all chars to our piece until we hit the ending quote.
- while (end < remaining.Length && (inString || (remaining [end] != '}' && remaining [end] != ',' && remaining [end] != '='))) {
- if (remaining [end] == '\'')
- inString = !inString;
- // If this is an escape char, consume it and append the next char to our piece.
- if (remaining [end] == '\\') {
- end ++;
- if (end == remaining.Length)
- break;;
- }
- piece.Append (remaining [end]);
- end++;
- }
- if (end == remaining.Length && !remaining.EndsWith ("}"))
- throw new Exception ("Binding did not end with '}'");
- if (end == 0) {
- next = Char.MaxValue;
- return null;
- }
- next = remaining [end];
- remaining = remaining.Substring (end + 1);
- // Whitespace is trimmed from the end of the piece before stripping
- // quote chars from the start/end of the string.
- while (piece.Length > 0 && char.IsWhiteSpace (piece [piece.Length - 1]))
- piece.Length --;
- if (piece.Length >= 2) {
- char first = piece [0];
- char last = piece [piece.Length - 1];
- if ((first == '\'' && last == '\'') || (first == '"' && last == '"')) {
- piece.Remove (piece.Length - 1, 1);
- piece.Remove (0, 1);
- }
- }
- return piece.ToString ();
- }
- protected abstract object LookupNamedResource (DependencyObject dob, string name);
- protected abstract FrameworkTemplate GetParentTemplate ();
- }
- }