Преобразование постоянно обновляемых единиц в текстовые поля по команде
У меня есть три текстовых блока, текст которых связан с тремя различными свойствами.
<TextBlock Style="{StaticResource textBlockStyle2}"
Text="{Binding Path=TWD,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged},
StringFormat={}{0:F1} M}" />
<TextBlock Style="{StaticResource textBlockStyle2}"
Text="{Binding Path=Alt,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged},
StringFormat={}{0:F1} M}" />
<TextBlock Style="{StaticResource textBlockStyle2}"
Text="{Binding Path=Dep,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged},
StringFormat={}{0:F1} M}" />
Это свойства в viewmodel:
private double _TWD;
public double TWD
{
get { return _TWD; }
set { _TWD = value; OnPropertyChanged("TWD"); }
}
private double _Alt;
public double Alt
{
get { return _Alt; }
set { _Alt = value; OnPropertyChanged("Alt"); }
}
private double _Dep;
public double Dep
{
get { return _Dep; }
set { _Dep = value; OnPropertyChanged("Dep"); }
}
Теперь они выражены в метрах, для чего и используется "M" в свойстве StringFormat текстовых блоков. То, что я пытаюсь сделать, это когда я "нажимаю" (с помощью команды) на отдельном текстовом блоке (это будет внутри кнопки, использующей шаблон элемента управления), я хочу преобразовать значения в вышеуказанных текстовых блоках в футы и добавить 'F' после значения. Еще один клик преобразует его обратно в метры и так далее.
Я думал о добавлении команды, которая просто преобразовала значения на основе bool isMeters
, Тем не менее, значения в текстовом блоке постоянно обновляются (каждую секунду), и я не хочу вызывать функцию каждый раз, когда значения меняются. Есть ли более простой способ, о котором я не думаю, чтобы достичь этой функциональности?
Замечания:
1 meter = 3.2808 ft
1ft = 0.3048 meter
2 ответа
Я получил это работает с помощью конвертера.
public class MetersToFeetConverter : IValueConverter
{
/// <summary>
/// Converts meters to feet.
/// </summary>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
value = (double)value * 3.2808;
return (value.ToString() + " F");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}
Тогда в viewmodel:
private bool _isMeters = true;
public bool IsMeters
{
get { return _isMeters; }
set { _isMeters = value; OnPropertyChanged("IsMeters"); }
}
//called when I click the button to convert
public void ConvertData(object parameter)
{
if (_isMeters == false)
{
IsMeters = true;
}
else
{
IsMeters = false;
}
}
Тогда привязка xaml к текстовым полям выглядит так, используя datatrigger:
<Style.Triggers>
<DataTrigger Binding="{Binding IsMeters, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="False">
<Setter Property="Text" Value="{Binding Path=TWD, Converter={StaticResource metersToFeetConverter}}" />
</DataTrigger>
</Style.Triggers>
Примечание: ответ @haindl тоже сработал, просто не видел его, пока я так не сделал.
Вы могли бы использовать <MultiBinding>
с IMultiValueConverter
для каждого свойства в каждом TextBlock, но, на мой взгляд, это просто испортило бы весь XAML, поэтому я действительно не рекомендовал бы это.
Но определенно более жизнеспособным способом могло бы быть наличие пары двойных и строковых свойств. Первая - это необработанная стоимость, которая всегда может быть в метрах. Последний будет представлять текущую единицу, которая должна отображаться в представлении.
Так что ваша ViewModel будет выглядеть примерно так:
// This is set by the command.
private bool _isMeters = true;
private double _Alt;
public double Alt
{
get { return _Alt; }
set { _Alt = value; OnPropertyChanged("Alt"); OnPropertyChanged("AltInCurrentUnit"); }
}
// Rename the suffix as you wish.
public string AltInCurrentUnit => GetInCurrentUnit(_Alt);
// This method is used by all "InCurrentUnit"-properties.
private string GetInCurrentUnit(double meters) =>
// If you don't like expression bodied methods or ternaries then reformat as you wish.
_isMeters ?
$"{meters:F1} M" :
$"{(meters * 3.2808):F1} F";
И ваш взгляд просто должен быть:
<TextBlock Style="{StaticResource textBlockStyle2}" Text="{Binding AltInCurrentUnit}" />
Если ваши свойства обновляются каждую секунду, то, возможно, вам не нужны какие-либо специальные PropertyChanged
звонки, если единица изменена командой.
И, конечно, теперь вы можете опустить OnPropertyChanged("Alt")
если вам больше не нужно связывать это необработанное свойство в представлении.