Xaml 绑定中的 Switch (Select) 语句?

问题描述 投票:0回答:6

有没有办法在 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
列表。

wpf xaml binding switch-statement datatrigger
6个回答
13
投票

使用

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>


7
投票

您有多种选择...

  • 您可以通过将“样式”应用到文本块来使用“数据触发器”(使用“Style.Triggers”)。
  • 您可以创建一个转换器,将您的“MyValue”转换为适当的文本。
  • 您可以在任何数据源上创建另一个属性(理想情况下这将是一个 ViewModel 样式的类)来反映应显示的文本。从代码更新属性并直接绑定到它,而不是将逻辑放在 XAML 中。

我真的认为这是一种风格/设计选择 - 以上没有本质上更好或更坏,它们只是适合不同的场景。


5
投票

尝试使用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());
    }
}

1
投票

我根据接受的答案制作了一个简化的、更新的转换器。 它还允许进行字符串比较和设置默认大小写:

[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>

0
投票

你可以按照丹的建议使用转换器......

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}}"/>

0
投票

此问题的另一个解决方案是使用

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()
函数进行进一步的工作以支持其他类型,例如数字和日期。

© www.soinside.com 2019 - 2024. All rights reserved.