2

我如何将以下代码编写为 XAML

假设我们有这段代码

        var myValue = someMethodeReturn(); // the return will fit

        // could also be an other nonbindable property
        var myTextBlock = new TextBlock();
        myTextBlock.Inlines = myValue;

你将如何转换

       var myValue = someMethodeReturn(); 

myTextBlock.Inlines = myValue;

仅作为XAML

第一部分肯定看起来像,第二部分看起来像 ???={Binding myProperty}<TextBlock.Inlines><???/></TextBlock.Inlines>???会是什么样子?

视觉结果应该是这样的(如果你执行你的解决方案)

    <TextBlock  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="LightGray" TextWrapping="WrapWithOverflow" >
        <TextBlock.Inlines>
            <Run>meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr  lange run 1</Run>
            <Run Foreground="Green" FontFamily='Palatino Linotype' Typography.Variants='Superscript'>meine run2</Run>
            <Run>meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr  lange run</Run>
            <Run Foreground="LimeGreen" Background="Yellow">meine run3</Run>
            <Run>meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr  lange run</Run>
        </TextBlock.Inlines>
    </TextBlock>

我在 TagesItemsControl之间进行了测试,TextBlock.Inlines但它默认返回 TextBlocks,我无法设置RunInLine作为ItemTemplate

我想我只需要一个Control返回 aList<Inline>但我不知道哪个Control能够做到这一点

任何建议,将不胜感激

我尝试了以下想法

第一的

<TextBlock  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="LightGray" TextWrapping="WrapWithOverflow" >
    <TextBlock.Inlines>
        <ContentControl Content="{Binding myBinding}"/>
    </TextBlock.Inlines>
</TextBlock>

仅返回“(Auflistung)”作为文本

第二

    <TextBlock  HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="LightGray" TextWrapping="WrapWithOverflow" >
        <TextBlock.Inlines>
            <ItemsControl ItemsSource="{Binding myBinding}"/>
        </TextBlock.Inlines>
    </TextBlock>

返回一个包含在 a 中的 TextBox 列表ContenPresenter

4

3 回答 3

1

要添加字符串值,您可以使用

myTextBlock.Inlines.Add(new Run(myValue));

如果 myValue 是一个数组循环并添加多个运行元素

运行类的 Msdn 文档http://msdn.microsoft.com/en-us/library/system.windows.documents.run.aspx

于 2013-03-08T14:42:45.033 回答
1

我的想法是使用 ItemsControl 并将 ItemPanel 设置为 WrapPanel,然后为每个项目插入 TextBlocks 或 ContentPresenters。原来那些 TextBlocks 不会像我预期的那样包装得很好:

在此处输入图像描述

好吧,您至少有一个 ViewModel,那么在将文本项提交到源集合之前如何将它们通过绞肉机?之后看起来很正确:

在此处输入图像描述

现在,如果它感觉也不错;)!也许你可以使用其中的一些,至少。

视图模型:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    private ObservableCollection<MyRunModel> _myRuns = new ObservableCollection<MyRunModel>();
    public ObservableCollection<MyRunModel> MyRuns { get { return _myRuns; } set { _myRuns = value; OnPropertyChanged("MyRuns"); } }


    public ViewModel()
    {
        List<MyRunModel> runs = new List<MyRunModel>();
        runs.Add(new MyRunModel() { Text = "Meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr lange run1" });
        runs.Add(new MyRunModel() { Text = "Meine run2", Foreground = ForegroundDescription.HighlightDark });
        runs.Add(new MyRunModel() { Text = "Meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr lange run3" });
        runs.Add(new MyRunModel() { Text = "Meine run4", Foreground = ForegroundDescription.HighlightLight, Background = BackgroundDescription.Highlight });
        runs.Add(new MyRunModel() { Text = "Meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr lange run5" });

        CommitMyRuns(runs);
    }

    /// <summary>
    /// Splits up every run into words (delimited by space), and adds the parts 
    /// to the collection that can be bound to the UI. Retains formatting information.
    /// </summary>
    /// <param name="runs"></param>
    private void CommitMyRuns(List<MyRunModel> runs)
    {
        int runCount = runs.Count;
        for (int i = 0; i < runCount; i++)
        {
            string[] parts = runs[i].Text.Split(' ');
            int partCount = parts.Length;
            for (int j = 0; j < partCount; j++)
            {
                bool isLast = j == parts.Length - 1;
                MyRunModel run = new MyRunModel()
                {
                    Text = parts[j] + (isLast ? string.Empty : " "),  // add space that was lost in split
                    Foreground = runs[i].Foreground, // keep formatting
                    Background = runs[i].Background
                };
                MyRuns.Add(run);
            }
            MyRuns.Add(new MyRunModel() { Text = " " }); // add a space after each of the original runs (unformatted)
        }
    }

}
public class MyRunModel
{
    public string Text { get; set; }
    // do not use UI types (e.g. Brush) directly in viewmodel
    public ForegroundDescription Foreground { get; set; }
    public BackgroundDescription Background { get; set; }
}

public enum ForegroundDescription
{
    None = 0,
    HighlightDark,
    HighlightLight
}

public enum BackgroundDescription
{
    None = 0,
    Highlight
}

xml:

<Window.DataContext>
    <local:ViewModel />
</Window.DataContext>

<Window.Resources>
    <SolidColorBrush x:Key="ForegroundHighlightDarkBrush" Color="Green" />
    <SolidColorBrush x:Key="ForegroundHighlightLightBrush" Color="LimeGreen" />
    <SolidColorBrush x:Key="BackgroundHighlightBrush" Color="Yellow" />
</Window.Resources>

<Grid>
    <TextBlock>
        <TextBlock.Inlines>
            <ItemsControl ItemsSource="{Binding MyRuns}" HorizontalContentAlignment="Stretch">
                <ItemsControl.ItemTemplate>
                    <DataTemplate DataType="{x:Type local:MyRunModel}">
                        <TextBlock x:Name="presenter" TextWrapping="Wrap" Text="{Binding Text}"/>
                        <DataTemplate.Triggers>
                            <DataTrigger Binding="{Binding Foreground}" Value="HighlightDark">
                                <Setter TargetName="presenter" Property="TextElement.Foreground" Value="{StaticResource ForegroundHighlightDarkBrush}" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Foreground}" Value="HighlightLight">
                                <Setter TargetName="presenter" Property="TextElement.Foreground" Value="{StaticResource ForegroundHighlightLightBrush}" />
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Background}" Value="Highlight">
                                <Setter TargetName="presenter" Property="TextElement.Background" Value="{StaticResource BackgroundHighlightBrush}" />
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal" />
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </TextBlock.Inlines>
    </TextBlock>
</Grid>

子类化文本框以使内联可绑定可能是一种可能性。看到这个答案

于 2013-03-11T21:35:23.193 回答
1

创建可绑定Inlines的附加属性,如下所示:

可绑定的.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;

namespace WpfApplication
{
    public static class Bindable
    {
        public static readonly DependencyProperty InlinesProperty = DependencyProperty.RegisterAttached("Inlines", typeof(IEnumerable<Inline>), typeof(Bindable), new PropertyMetadata(OnInlinesChanged));

        private static void OnInlinesChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {
            var textBlock = source as TextBlock;

            if (textBlock != null)
            {
                textBlock.Inlines.Clear();
                var inlines = e.NewValue as IEnumerable<Inline>;
                if (inlines != null)
                    textBlock.Inlines.AddRange(inlines);
            }
        }

        [AttachedPropertyBrowsableForType(typeof(TextBlock))]
        public static IEnumerable<Inline> GetInlines(this TextBlock textBlock)
        {
            return (IEnumerable<Inline>)textBlock.GetValue(InlinesProperty);
        }

        public static void SetInlines(this TextBlock textBlock, IEnumerable<Inline> inlines)
        {
            textBlock.SetValue(InlinesProperty, inlines);
        }
    }
}

并像这样使用它:

MyViewModel.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace WpfApplication
{
    public class MyViewModel
    {
        // This is against MVVM principle - to contain views (Inlines) in view model, but I don't want to complicate by creating ViewModel class for each Inline derived class.
        public IEnumerable<Inline> Inlines { get; private set; }

        public MyViewModel()
        {
            this.Inlines = new Inline[]
            {
                new Run("meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr  lange run 1"),
                new Run("meine run2") { Foreground = Brushes.Green, Typography = { Variants = FontVariants.Superscript } },
                new Run("meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr  lange run"),
                new Run("meine run3") { Foreground = Brushes.LimeGreen, Background = Brushes.Yellow },
                new Run("meine sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr sehr  lange run")
            };
        }
    }
}

主窗口.xaml

<Window x:Class="WpfApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication">
    <Window.DataContext>
        <local:MyViewModel/>
    </Window.DataContext>
    <TextBlock local:Bindable.Inlines="{Binding Inlines}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="LightGray" TextWrapping="WrapWithOverflow"/>
</Window>
于 2013-03-11T23:09:53.710 回答