优秀的价值观优雅解决方案

我正在开发一个WPF应用程序,其窗口大小和组件位置必须在初始化时动态计算,因为它们基于我使用的主UserControl大小和一些其他小尺寸设置。 所以,目前,我已将这些常量值放在我的Window代码中,如下所示:

public const Double MarginInner = 6D; public const Double MarginOuter = 10D; public const Double StrokeThickness = 3D; public static readonly Double TableHeight = (StrokeThickness * 2D) + (MarginInner * 3D) + (MyUC.RealHeight * 2.5D); public static readonly Double TableLeft = (MarginOuter * 3D) + MyUC.RealHeight + MarginInner; public static readonly Double TableTop = MarginOuter + MyUC.RealHeight + MarginInner; public static readonly Double TableWidth = (StrokeThickness * 2D) + (MyUC.RealWidth * 6D) + (MarginInner * 7D); public static readonly Double LayoutHeight = (TableTop * 2D) + TableHeight; public static readonly Double LayoutWidth = TableLeft + TableWidth + MarginOuter; 

然后,我只是在我的XAML中使用它们,如下所示:

   

嗯……没什么好说的。 它的工作原理……但它看起来太丑了,我想知道是否有更好的解决方案。 我不知道……可能是一个设置文件,绑定,内联XAML计算或其他任何东西……它会使它看起来更好。

我通常将所有静态的应用程序设置放在一个称为通用的静态或单例类中,如ApplicationSettings (如果值仅由MainWindow使用,则为MainWindow

如果这些值是用户可配置的,则它们将进入app.config并加载到静态类的构造函数中。 如果没有,我只是在我的静态类中对它们进行硬编码,以便以后很容易找到/更改它们。

 public static class ApplicationSettings { public static Double MarginInner { get; private set; } public static Double MarginOuter { get; private set; } public static Double StrokeThickness { get; private set; } static ApplicationSettings() { MarginInner = 6D; MarginOuter = 10D; StrokeThickness = 3D; } } 

对于XAML中的计算值,我通常使用我编写的MathConverter ,它允许我使用数学表达式编写绑定,并将其传递给要使用的值。

我在博客上发布的版本只是一个IValueConverter ,但很容易扩展到IMultiValueConverter因此它可以接受多个绑定值。

          

通常我会在某个地方隐藏所有这些凌乱的XAML,所以它不会使我的主XAML代码混乱,只需在需要的地方应用样式。

这是我用于IMultiValueConvter的转换器代码的IMultiValueConvter

 // Does a math equation on a series of bound values. // Use @VALUEN in your mathEquation as a substitute for bound values, where N is the 0-based index of the bound value // Operator order is parenthesis first, then Left-To-Right (no operator precedence) public class MathMultiConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { // Remove spaces var mathEquation = parameter as string; mathEquation = mathEquation.Replace(" ", ""); // Loop through values to substitute placeholders for values // Using a backwards loop to avoid replacing something like @VALUE10 with @VALUE1 for (var i = (values.Length - 1); i >= 0; i--) mathEquation = mathEquation.Replace(string.Format("@VALUE{0}", i), values[i].ToString()); // Return result of equation return MathConverterHelpers.RunEquation(ref mathEquation); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public static class MathConverterHelpers { private static readonly char[] _allOperators = new[] { '+', '-', '*', '/', '%', '(', ')' }; private static readonly List _grouping = new List { "(", ")" }; private static readonly List _operators = new List { "+", "-", "*", "/", "%" }; public static double RunEquation(ref string mathEquation) { // Validate values and get list of numbers in equation var numbers = new List(); double tmp; foreach (string s in mathEquation.Split(_allOperators)) { if (s != string.Empty) { if (double.TryParse(s, out tmp)) { numbers.Add(tmp); } else { // Handle Error - Some non-numeric, operator, or grouping character found in string throw new InvalidCastException(); } } } // Begin parsing method EvaluateMathString(ref mathEquation, ref numbers, 0); // After parsing the numbers list should only have one value - the total return numbers[0]; } // Evaluates a mathematical string and keeps track of the results in a List of numbers private static void EvaluateMathString(ref string mathEquation, ref List numbers, int index) { // Loop through each mathemtaical token in the equation string token = GetNextToken(mathEquation); while (token != string.Empty) { // Remove token from mathEquation mathEquation = mathEquation.Remove(0, token.Length); // If token is a grouping character, it affects program flow if (_grouping.Contains(token)) { switch (token) { case "(": EvaluateMathString(ref mathEquation, ref numbers, index); break; case ")": return; } } // If token is an operator, do requested operation if (_operators.Contains(token)) { // If next token after operator is a parenthesis, call method recursively string nextToken = GetNextToken(mathEquation); if (nextToken == "(") { EvaluateMathString(ref mathEquation, ref numbers, index + 1); } // Verify that enough numbers exist in the List to complete the operation // and that the next token is either the number expected, or it was a ( meaning // that this was called recursively and that the number changed if (numbers.Count > (index + 1) && (double.Parse(nextToken) == numbers[index + 1] || nextToken == "(")) { switch (token) { case "+": numbers[index] = numbers[index] + numbers[index + 1]; break; case "-": numbers[index] = numbers[index] - numbers[index + 1]; break; case "*": numbers[index] = numbers[index] * numbers[index + 1]; break; case "/": numbers[index] = numbers[index] / numbers[index + 1]; break; case "%": numbers[index] = numbers[index] % numbers[index + 1]; break; } numbers.RemoveAt(index + 1); } else { // Handle Error - Next token is not the expected number throw new FormatException("Next token is not the expected number"); } } token = GetNextToken(mathEquation); } } // Gets the next mathematical token in the equation private static string GetNextToken(string mathEquation) { // If we're at the end of the equation, return string.empty if (mathEquation == string.Empty) { return string.Empty; } // Get next operator or numeric value in equation and return it string tmp = ""; foreach (char c in mathEquation) { if (_allOperators.Contains(c)) { return (tmp == "" ? c.ToString() : tmp); } else { tmp += c; } } return tmp; } } 

但老实说,如果这些值只用于单一forms,那么我只需在View后面的代码中的Loaded事件中设置值:)

把那些静态的放在app.config中,它们会更清洁。

使用app.config,首先必须引用System.Configuration

然后你可以做( 可能涉及一些类型转换 ):

  ConfigurationManager.AppSettings["MarginInner"]; 

要检索:

      

然后可能有一个静态类来保存动态计算,如:

 public class CalculationHelper { //your dynamic properties in here } 

mattytommo的答案仅解决您所拥有的常量值(边距和笔触粗细),而不是计算字段。

我将与Matty所说的一样,添加一个设置类,从app.config文件中检索常量值,并进行所需的相应计算,然后我可以在XAML中引用相应的属性

 { Settings.MainWindow.LayoutWidth } 

编辑:

看起来Matty有同样的情况,尽管他在我发帖之间进行了编辑;)