Я хочу добавить постоянное значение во входящее связанное целое число. На самом деле у меня есть несколько мест, где я хочу привязаться к одному и тому же исходному значению, но добавить разные константы. Так что идеальным решением было бы что-то вроде этого ...
<TextBox Canvas.Top = "{Binding ElementName=mySource, Path=myInt, Constant=5}"/>
<TextBox Canvas.Top = "{Binding ElementName=mySource, Path=myInt, Constant=8}"/>
<TextBox Canvas.Top = "{Binding ElementName=mySource, Path=myInt, Constant=24}"/>
(ПРИМЕЧАНИЕ: это пример, демонстрирующий идею, мой фактический сценарий привязки не связан со свойством холста TextBox. Но это показывает идею более четко)
На данный момент единственное решение, которое я могу придумать, - это предоставить множество различных исходных свойств, каждое из которых добавляет другую константу к одному и тому же внутреннему значению. Так что я мог бы сделать что-то вроде этого ...
<TextBox Canvas.Top = "{Binding ElementName=mySource, Path=myIntPlus5}"/>
<TextBox Canvas.Top = "{Binding ElementName=mySource, Path=myIntPlus8}"/>
<TextBox Canvas.Top = "{Binding ElementName=mySource, Path=myIntPlus24}"/>
Но это довольно мрачно, потому что в будущем мне, возможно, придется добавлять новые свойства для новых констант. Также, если мне нужно изменить добавленную стоимость, мне нужно изменить исходный объект, что довольно глупо.
Должен быть более общий способ, чем этот? Есть какие-нибудь идеи у экспертов WPF?





Я считаю, что вы можете сделать это с помощью преобразователя значений. Вот запись в блоге, который адресует передачу параметра преобразователю значений в xaml. И этот блог дает некоторые детали реализации преобразователя значений.
Я никогда не использовал WPF, но у меня есть возможное решение.
Может ли ваш путь привязки отображаться на карту? Если это так, он должен иметь возможность принимать аргумент (ключ). Вам нужно будет создать класс, который реализует интерфейс Map, но на самом деле просто возвращает базовое значение, которое вы инициализировали «Map», добавленное к ключу.
public Integer get( Integer key ) { return baseInt + key; } // or some such
Без некоторой возможности передать число из тега я не понимаю, как вы собираетесь заставить его возвращать разные дельты от исходного значения.
Использование преобразователя значений - хорошее решение проблемы, поскольку оно позволяет изменять исходное значение, поскольку оно привязано к пользовательскому интерфейсу.
Я использовал следующее в нескольких местах.
public class AddValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
object result = value;
int parameterValue;
if (value != null && targetType == typeof(Int32) &&
int.TryParse((string)parameter,
NumberStyles.Integer, culture, out parameterValue))
{
result = (int)value + (int)parameterValue;
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Пример
<Setter Property = "Grid.ColumnSpan"
Value = "{Binding
Path=ColumnDefinitions.Count,
RelativeSource = {RelativeSource AncestorType=Grid},
Converter = {StaticResource addValueConverter},
ConverterParameter=1}"
/>
Я использую созданный мною MathConverter для выполнения всех простых арифметических операций. Код конвертера - здесь, и его можно использовать так:
<TextBox Canvas.Top = "{Binding SomeValue,
Converter = {StaticResource MathConverter},
ConverterParameter=@VALUE+5}" />
Вы даже можете использовать его с более сложными арифматическими операциями, такими как
Width = "{Binding ElementName=RootWindow, Path=ActualWidth,
Converter = {StaticResource MathConverter},
ConverterParameter=((@VALUE-200)*.3)}"
Хороший преобразователь, но это не работает, если значение является отрицательным числом. Быстрый обходной путь - использовать какой-нибудь другой знак минуса, а не «-», и соответственно изменить списки операндов в коде MathConverter. Реальное решение, конечно, потребует добавления дополнительной логики при синтаксическом анализе ..
@MaximZabolotskikh Отрицательное число - это просто 0 - @VALUE, поэтому пользователи могут легко ввести его как это. Или, как лучшее решение, просто проверьте символ -, когда мы ожидаем числовой токен, и, если он найден, проанализируйте его должным образом. Я думаю, что, возможно, действительно сделал это в копии конвертера, который я храню в своей библиотеке WPF ...
0 - @VALUE работать не будет. Чтобы быть более точным, у меня есть список, начинающийся с 0, и я хочу показать текст «элемент x из y», поэтому я привязываю index (x) как «@VALUE + 1». Однако пустой список вернет -1 в качестве индекса, поэтому он станет -1 + 1, математический преобразователь разбивается по операндам, чем для минус второго числа не найдено, что-то вроде этого. Так что нужно провести еще немного синтаксического анализа. Но в основном цель моего комментария заключалась в том, чтобы указать на возможную проблему всем, кто может использовать этот код в будущем. В любом случае, это полезный конвертер.
Общее предупреждение: я просто потратил вечность, выясняя, что эти запятые необходимы
Я бы использовал конвертер с несколькими привязками, например, в следующем примере:
Код C#:
namespace Example.Converters
{
public class ArithmeticConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double result = 0;
for (int i = 0; i < values.Length; i++)
{
if (!double.TryParse(values[i]?.ToString(), out var parsedNumber)) continue;
if (TryGetOperations(parameter, i, out var operation))
{
result = operation(result, parsedNumber);
}
}
return result;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
return new[] { Binding.DoNothing, false };
}
private static bool TryGetOperations(object parameter, int operationIndex, out Func<double, double, double> operation)
{
operation = null;
var operations = parameter?.ToString().Split(',');
if (operations == null || operations.Length == 0) return false;
if (operations.Length <= operationIndex)
{
operationIndex = operations.Length - 1;
}
return Operations.TryGetValue(operations[operationIndex]?.ToString(), out operation);
}
public const string Add = "+";
public const string Subtract = "-";
public const string Multiply = "*";
public const string Divide = "/";
private static IDictionary<string, Func<double, double, double>> Operations = new Dictionary<string, Func<double, double, double>>
{
{ Add, (x, y) => x + y },
{ Subtract, (x, y) => x - y },
{ Multiply, (x, y) => x * y },
{ Divide, (x, y) => x / y }
};
}
}
Код XAML:
<UserControl
xmlns:converters = "clr-namespace:Example.Converters">
<UserControl.Resources>
<converters:ArithmeticConverter x:Key = "ArithmeticConverter" />
</UserControl.Resources>
...
<MultiBinding Converter = "{StaticResource ArithmeticConverter}" ConverterParameter = "+,-">
<Binding Path = "NumberToAdd" />
<Binding Path = "NumberToSubtract" />
</MultiBinding>
Тот факт, что преобразователь значений может принимать параметр, кажется хорошим подходом к решению проблемы. Спасибо за вклад.