如何为StringFormat使用动态值

时间:2017-08-08 14:55:35

标签: c# wpf xaml data-binding

我有一个组合框,它绑定到MyObject类型的对象列表:

public class MyObject
{
    public string Template { get; set; }
    public string Parameter { get; set; }
}

字符串“Template”是一个应该与String.Format一起使用的字符串,即它可能包含应该用字符串“Parameter”替换的“{0}”。

我想在标签中显示结果,而不必在viewmodel中添加新字段。我正在寻找类似于此的XAML:

<ComboBox Name="cbMyObjects" ItemsSource="{Binding Path=MyObjects}"/>
<Label Name="lblDisplay2" Content="{Binding ElementName=cbMyObjects, Path=SelectedItem.Parameter}" ContentStringFormat="{Binding ElementName=cbMyObjects, Path=SelectedItem.Template}" />

即。如果列表中有一个对象,使得Template =“Weight:{0}”,参数=“3kg”,则标签应显示“Weight:3kg”

3 个答案:

答案 0 :(得分:1)

我接受了Michael Coxon的回答并使用转换器制作了一个版本,以避免使用ToString()

基本上,您可以使用MultiBindingIMultiValueConverter以相当通用的方式解决您的问题,string.Format()基本上是<Window x:Class="SandBox.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:SandBox" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:properties="clr-namespace:SandBox.Properties" Title="{x:Static properties:Resources.TitleSandbox}" mc:Ignorable="d"> <ComboBox HorizontalAlignment="Center" VerticalAlignment="Center" ItemsSource="{Binding MyObjects}"> <ComboBox.ItemTemplate> <DataTemplate> <TextBlock> <TextBlock.Text> <MultiBinding Converter="{local:TemplateConverter}"> <Binding Path="Template" /> <Binding Path="Parameter" /> <Binding Path="Double" /> </MultiBinding> </TextBlock.Text> </TextBlock> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> </Window>

的WPF适配器

的Xaml:

public class MainWindowViewModel
{
    public MainWindowViewModel()
    {
    }

    public IEnumerable<MyObject> MyObjects
    {
        get
        {
            yield return new MyObject { Template = "The parameter value is {0} with double value of {1:F2}", Parameter = "asdF1", Double = 1.0 / 3.0 };
            yield return new MyObject { Template = "The parameter value is {0} with double value of {1:F2}", Parameter = "asdF2", Double = 4.5 };
            yield return new MyObject { Template = "The parameter value is {0} with double value of {1:F2}", Parameter = "asdF3", Double = 78 };
            yield return new MyObject { Template = "The parameter value is {0} with double value of {1:F2}", Parameter = "asdF4", Double = Double.PositiveInfinity };
        }
    }
}

public class MyObject
{
    public string Template { get; set; }
    public string Parameter { get; set; }

    public double Double { get; set; }
}

视图模型:

/// <summary>
/// Permit {local:TemplateConverter} markup
/// </summary>
public class TemplateConverterExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
        => new TemplateConverter();
}

public class TemplateConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Length >= 1 && values[0] is string template)
        {
            return string.Format(template, values.Skip(1).ToArray());
        }
        throw new ArgumentException("Give at least a template");

    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        => throw new NotImplementedException("Todo, eventually");
}

转换器:

    // Fill the contact list
procedure TForm1.FillContactList(Source: TAddressBookSource);
var
  I: Integer;
  Contacts: TAddressBookContacts;
begin
  Contacts := TAddressBookContacts.Create;
  try
    AddressBook1.AllContacts(Source, Contacts);
    ListViewContacts.BeginUpdate;
    try
      ListViewContacts.Items.Clear;
      for I := 0 to Contacts.Count - 1 do
        AddListViewItem(Contacts.Items[I]);
    finally
      ListViewContacts.EndUpdate;
    end;
  finally
    Contacts.Free;
  end;
end;

示例:

Sample

答案 1 :(得分:0)

为什么不覆盖ToString()MyObject

上执行您想要的操作
public override string ToString()
{
    return string.Format(this.Template, this.Parameter); 
}

然后,如果绑定到SelectedItem,则会在引擎盖下调用ToString()方法。

答案 2 :(得分:0)

所以我不确定这是否是你要找的,但我设法使用我在评论中提出的ToString()方法和MainWindow类的属性来使用它。 ..以下所有代码......

看起来ToString()使用值和您建议用于标签的模板填充组合框。

MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel >
            <ComboBox Name="cbMyObjects" ItemsSource="{Binding MyObjects, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"/>
            <Label Name="lblDisplay2" Content="{Binding ElementName=cbMyObjects, Path=SelectedItem.Parameter}" ContentStringFormat="{Binding ElementName=cbMyObjects, Path=SelectedItem.Template}" />
        </StackPanel>
    </Grid>
</Window>

MainWindow.xaml.cs

namespace WpfApp1
{
    using System.Collections.Generic;
    using System.Windows;

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        public IEnumerable<MyObject> MyObjects
        {
            get
            {
                yield return new MyObject { Template = "The parameter value is {0}", Parameter = "asdF1" };
                yield return new MyObject { Template = "The parameter value is {0}", Parameter = "asdF2" };
                yield return new MyObject { Template = "The parameter value is {0}", Parameter = "asdF3" };
                yield return new MyObject { Template = "The parameter value is {0}", Parameter = "asdF4" };
            }
        }
    }
}

MyObject.cs

public class MyObject
{
    public string Template { get; set; }
    public string Parameter { get; set; }

    public override string ToString() => string.Format(this.Template, this.Parameter);
}