有没有办法在 XAML 中创建条件绑定?
示例:
<Window x:Name="Me" DataContext="{Binding ElementName=Me}">
<TextBlock>
<TextBlock.Text>
<SelectBinding Binding="{Binding MyValue}">
<Case Value="Value1" Value="value is 1!">
<Case Value="Value2" Value="value is 2!">
<Case Value="Value3" Value="value is 3!">
</SelectBinding >
</TextBlock.Text>
</TextBlock>
</Window>
底线,我想根据
Binding
的另一个值设置 TextBlock 值,该值可以是案例列表,其中每个案例(或多个案例)都被寻址到适当的输出/设置器。
也许我可以在我的情况下使用
DataTrigger
,我只是不知道该怎么做,因为我在这里没有使用任何DataTemplate
。
更新
在我的场景中,我有一个具有多个控件的
UserControl
。
我希望根据 UserControl.DataContext 数据项中的某个属性,用户控件中的其他控件应该相应地受到影响。基本上与我上面的示例相同,只是每种情况都会导致一个 Setter
列表。
使用
DataTrigger
(编辑 - 原版有轻微错误)
<TextBlock>
<TextBlock.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding MyValue}" Value="Value1">
<Setter Property="TextBlock.Text" Value="value is 1!"/>
</DataTrigger>
<DataTrigger Binding="{Binding MyValue}" Value="Value2">
<Setter Property="TextBlock.Text" Value="value is 2!"/>
</DataTrigger>
<DataTrigger Binding="{Binding MyValue}" Value="Value3">
<Setter Property="TextBlock.Text" Value="value is 3!"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
您有多种选择...
我真的认为这是一种风格/设计选择 - 以上没有本质上更好或更坏,它们只是适合不同的场景。
尝试使用Josh编写的Switch Converter:
SwitchConverter –
XAML 的“switch 语句”- http://josheinstein.com/blog/index.php/2010/06/switchconverter-a-switch-statement-for-xaml/
编辑:
这是 SwitchConverter 的代码,因为 Josh 的 网站似乎已关闭 -
/// <summary>
/// A converter that accepts <see cref="SwitchConverterCase"/>s and converts them to the
/// Then property of the case.
/// </summary>
[ContentProperty("Cases")]
public class SwitchConverter : IValueConverter
{
// Converter instances.
List<SwitchConverterCase> _cases;
#region Public Properties.
/// <summary>
/// Gets or sets an array of <see cref="SwitchConverterCase"/>s that this converter can use to produde values from.
/// </summary>
public List<SwitchConverterCase> Cases { get { return _cases; } set { _cases = value; } }
#endregion
#region Construction.
/// <summary>
/// Initializes a new instance of the <see cref="SwitchConverter"/> class.
/// </summary>
public SwitchConverter()
{
// Create the cases array.
_cases = new List<SwitchConverterCase>();
}
#endregion
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// This will be the results of the operation.
object results = null;
// I'm only willing to convert SwitchConverterCases in this converter and no nulls!
if (value == null) throw new ArgumentNullException("value");
// I need to find out if the case that matches this value actually exists in this converters cases collection.
if (_cases != null && _cases.Count > 0)
for (int i = 0; i < _cases.Count; i++)
{
// Get a reference to this case.
SwitchConverterCase targetCase = _cases[i];
// Check to see if the value is the cases When parameter.
if (value == targetCase || value.ToString().ToUpper() == targetCase.When.ToString().ToUpper())
{
// We've got what we want, the results can now be set to the Then property
// of the case we're on.
results = targetCase.Then;
// All done, get out of the loop.
break;
}
}
// return the results.
return results;
}
/// <summary>
/// Converts a value.
/// </summary>
/// <param name="value">The value that is produced by the binding target.</param>
/// <param name="targetType">The type to convert to.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Represents a case for a switch converter.
/// </summary>
[ContentProperty("Then")]
public class SwitchConverterCase
{
// case instances.
string _when;
object _then;
#region Public Properties.
/// <summary>
/// Gets or sets the condition of the case.
/// </summary>
public string When { get { return _when; } set { _when = value; } }
/// <summary>
/// Gets or sets the results of this case when run through a <see cref="SwitchConverter"/>
/// </summary>
public object Then { get { return _then; } set { _then = value; } }
#endregion
#region Construction.
/// <summary>
/// Switches the converter.
/// </summary>
public SwitchConverterCase()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SwitchConverterCase"/> class.
/// </summary>
/// <param name="when">The condition of the case.</param>
/// <param name="then">The results of this case when run through a <see cref="SwitchConverter"/>.</param>
public SwitchConverterCase(string when, object then)
{
// Hook up the instances.
this._then = then;
this._when = when;
}
#endregion
/// <summary>
/// Returns a <see cref="System.String"/> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String"/> that represents this instance.
/// </returns>
public override string ToString()
{
return string.Format("When={0}; Then={1}", When.ToString(), Then.ToString());
}
}
我根据接受的答案制作了一个简化的、更新的转换器。 它还允许进行字符串比较和设置默认大小写:
[ContentProperty("Cases")]
public class SwitchConverter : IValueConverter
{
public SwitchConverter()
{
Cases = new List<SwitchConverterCase>();
}
public List<SwitchConverterCase> Cases { get; set; }
public StringComparison StringComparisonType { get; set; } = StringComparison.InvariantCulture;
public object Default { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null || Cases == null)
{
return DependencyProperty.UnsetValue;
}
SwitchConverterCase result = Cases.FirstOrDefault(c => string.Equals(value.ToString(), c.When, StringComparisonType));
return result != null ? result.Then : Default;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
SwitchConverterCase
班:
[ContentProperty("Then")]
public class SwitchConverterCase
{
public SwitchConverterCase()
{
}
public SwitchConverterCase(string when, object then)
{
When = when;
Then = then;
}
public string When { get; set; }
public object Then { get; set; }
public override string ToString() => $"When={When}; Then={Then}";
}
使用示例:
<con:SwitchConverter x:Key="StyleConverter"
Default="{x:Static FontWeights.Normal}">
<con:SwitchConverterCase When="pageHeader"
Then="{x:Static FontWeights.Bold}" />
<con:SwitchConverterCase When="header"
Then="{x:Static FontWeights.SemiBold}" />
<con:SwitchConverterCase When="smallText"
Then="{x:Static FontWeights.Light}" />
<con:SwitchConverterCase When="tinyText"
Then="{x:Static FontWeights.Thin}" />
</con:SwitchConverter>
<TextBlock FontWeight="{Binding Style, Converter={StaticResource StyleConverter}}" />
或内嵌:
<TextBlock>
<TextBlock.FontWeight>
<Binding Path="Style">
<Binding.Converter>
<con:SwitchConverter Default="{x:Static FontWeights.Normal}">
<con:SwitchConverterCase When="pageHeader"
Then="{x:Static FontWeights.Bold}" />
<!-- etc -->
</con:SwitchConverter>
</Binding.Converter>
</Binding>
</TextBlock.FontWeight>
</TextBlock>
你可以按照丹的建议使用转换器......
public class MyValueConverter : IValueConverter
{
public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
string myValue = value.ToString();
string output;
switch(myValue)
{
case "Value1":
output = "Value is 1";
break;
case "Value2":
output = "Value is 2";
break;
case "Value3":
output = "Value is 3";
break;
default:
output = "Invalid Value";
break;
}
return output;
}
public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
//Put reverse logic here
throw new NotImplementedException();
}
}
然后您可以在您的 xaml 中使用它...
<TextBlock
Text="{Binding MyValue, Converter={StaticResource MyValueConverter}}"/>
此问题的另一个解决方案是使用
MultiBinding
和 MultiValueConverter
,如下所示:
<ContentPage>
<ContentPage.Resources>
<ResourceDictionary>
<x:String x:Key="Value1">Value1</x:String>
<x:String x:Key="Value2">Value2</x:String>
<x:String x:Key="Value3">Value3</x:String>
<x:String x:Key="Result1">value is 1!</x:String>
<x:String x:Key="Result2">value is 2!</x:String>
<x:String x:Key="Result3">value is 3!</x:String>
<local:SelectMultiValueConverter x:Key="SelectMultiValueConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView>
</VerticalStackLayout>
<Label>
<Label.Text>
<MultiBinding Converter="{StaticResource SelectMultiValueConverter}">
<Binding Path={Binding MyValue}" />
<Binding Source="{StaticResource Value1}" />
<Binding Source="{StaticResource Result1}" />
<Binding Source="{StaticResource Value2}" />
<Binding Source="{StaticResource Result2}" />
<Binding Source="{StaticResource Value3}" />
<Binding Source="{StaticResource Result3}" />
</MultiBinding>
</Label.Text>
</Label>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
使用以下实现将输入值视为字符串:
public class SelectMultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 0) return null;
int idx = 1;
for (; (idx + 1 < values.Length; idx +=2)
if (Compare(values[0], values[idx])) return values[idx + 1];
return idx < values.Length ? values[idx] : null;
}
private bool Compare(object v1, object v2)
{
if (v1 == null && v2 == null) return true;
if (v1 == null || v2 == null) return false;
return v1.ToString() == v2.ToString();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
需要对
Compare()
函数进行进一步的工作以支持其他类型,例如数字和日期。