WPF TextBlock,带有自定义StringFormat和可变数量的Run / Inline

时间:2015-02-27 12:31:15

标签: wpf wpf-controls

我有一个需要显示的短语列表。这些短语具有静态文本和需要在屏幕上突出显示的可变位数(粗体,颜色不同)。

以下是如果我要从xaml构建所有内容的示例。

    <TextBlock Grid.Row="2">
        <Run Text="Your"/>
        <Run Text="{Binding Text1}"/>
        <Run Text="has a limit of $"/>
        <Run Text="{Binding Limit}" FontWeight="Bold" Foreground="Red"/>
        <Run Text="for period "/>
        <Run Text="{Binding StartDate}" FontWeight="Bold" Foreground="Blue"/>
        <Run Text=" : "/>
        <Run Text="{Binding EndDate}" FontWeight="Bold" Foreground="Blue"/>
        <Run Text=". Your up to date expenses are $"/>
        <Run Text="{Binding Expenses}" FontWeight="Bold" Foreground="Red"/>
    </TextBlock>

    <TextBlock Grid.Row="3">
        <Run Text="Your"/>
        <Run Text="{Binding Text2}"/>
        <Run Text="has a limit of $"/>
        <Run Text="{Binding Limit2}" FontWeight="Bold" Foreground="Red"/>
        <Run Text="for period "/>
    </TextBlock>

我想要实现的是以某种方式将文本与{0}绑定在其中并绑定ItemsSource,为Inlines设置TextBlock,并且,绑定ItemsSource可能对于每个内联应具有的样式(字体粗细和文本颜色):

文字:您的{0}期限为$ {1}。

填充内联的值:abc,1000

要应用{none,none},{bold,red}

的样式

首先这可能吗?如果是这样,你能指出我正确的方向或给我一些提示吗?

感谢。

2 个答案:

答案 0 :(得分:1)

我会为此创建一个自定义TextBlock后代,并以编程方式创建内联。

首先,创建一个模型来控制文本的显示:

public class TextModel
{
    public string Text { get; set; }
    public Color Color { get; set; }
    public FontWeight Weight { get; set; }
}

您可能希望对此实施INotifyPropertyChanged,但这会使事情变得复杂。

接下来,您需要一组这些:

public class TextModelCollection : ObservableCollection<TextModel>
{
}

最后,创建一个派生自TextBlock的自定义类:

public class MyCustomTextBlock : TextBlock
{
    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register("Items", typeof(TextModelCollection),
        typeof(MyCustomTextBlock), new PropertyMetadata(OnItemsChanged));

    public TextModelCollection Items
    {
        get
        {
            return (TextModelCollection) GetValue(ItemsProperty);
        }
        set
        {
            SetValue(ItemsProperty, value);
        }
    }

    public MyCustomTextBlock()
    {
        RefreshInlines();
    }

    static void OnItemsChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        ((MyCustomTextBlock) d).RefreshInlines();
    }
}

然后你只需要一个方法(此处称为RefreshInlines),它将在自定义属性更改时刷新文本块的内联集合。

void RefreshInlines()
{
    Inlines.Clear();
    foreach (TextModel text in Items)
    {
        var run = new Run(text.Text);
        run.Foreground = new SolidColorBrush(text.Color);
        run.FontWeight = text.Weight;
        Inlines.Add(run);
    }
}

由于TextModelCollection是一个可观察的集合,您需要注册列表更改,以便在添加或删除项目时刷新内联。我没有在这里显示代码,但它基本上与OnItemsChanged方法相关联。

答案 1 :(得分:0)

实际上有两个问题:

第一

您正在寻找MultiBindingStringFormat

这个用于文本以静态文本开头时:

<TextBlock>
   <TextBlock.Text>
       <MultiBinding StringFormat="Write Static Text Here {1} Something else {1}">
          <Binding Path="Text2" />
          <Binding Path="Text2" />
       </MultiBinding>
   </TextBlock.Text>
</TextBlock>

这个是用于文本以变量文本开头的时候:

<TextBlock>
   <TextBlock.Text>
       <MultiBinding StringFormat="{}{0} Write Static Text Here {1} Something else">
          <Binding Path="Text2" />
          <Binding Path="Text2" />
       </MultiBinding>
   </TextBlock.Text>
</TextBlock>

第二

您需要使用ItemsControl之类的内容(ListBox DataGrid等)

<ItemsControl ItemsSource="{Binding MyList}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
             put anything here to display as an element of MyList
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

您还需要在MyList窗口中为DataContext创建一个集合。例如:

public MainWindow()
{
    InitializeComponent();
    var vm = new MainVm();
    DataContext = vm;
}

MainVm应来自DependencyObject,其中包含以下内容:

public ObservableCollection<string> MyList { get { return _myList; } }
private ObservableCollection<string> _myList = new ObservableCollection<string>();

了解更多信息,请访问Google MVVM。