【问题标题】:How to Display ObservableCollection<string> in a UserControl如何在 UserControl 中显示 ObservableCollection<string>
【发布时间】:2011-06-14 16:22:54
【问题描述】:

我是 WPF 的新手,我发现了一些类似的问题,但不能完全弄清楚最后一部分。我有一个带有 ObservableCollection 的 ViewModel,其中包含错误消息。我想在表单上显示这些并允许用户选择和复制全部或部分消息。 (过去在 WinForm 应用程序中,我为此使用了 RichTextBox,但我不知道如何将一个绑定到 WPF 中的集合。)

我使用以下 xaml 获得了我想要的外观,但没有像使用 RichTextBox 那样选择和复制的内置方法。有谁知道我应该使用哪个控件,或者是否有办法启用选择/复制所有 TextBlocks 的内容,或者将其绑定到 RichTextBox 的方法?

    <Grid Margin="6">
    <ScrollViewer VerticalScrollBarVisibility="Auto"  Height="40" Grid.Column="0" Margin="6">
        <ItemsControl ItemsSource="{Binding ErrorMessages}" >            
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                     <TextBlock Text="{Binding Mode=OneWay}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </ScrollViewer>
</Grid>

[编辑] @Andrey Shvydky - 这不适合评论。 我花了一段时间才弄清楚正确的语法(尤其是 /, 东西),但最终我得到了如下所示的流文档语法。它在表单上看起来是正确的,起初似乎支持全选/复制。但是当我在全选/复制后粘贴时,什么都没有出现。有人知道为什么吗?

 <Grid Margin="6">
    <FlowDocumentScrollViewer>
        <FlowDocument >
            <Paragraph>
                <ItemsControl ItemsSource="{Binding ErrorMessages, Mode=OneWay}" />
                <Run Text="{Binding /, Mode=OneWay}" />
            </Paragraph>
        </FlowDocument>
    </FlowDocumentScrollViewer>
</Grid>

【问题讨论】:

    标签: wpf richtextbox observablecollection copy-paste textblock


    【解决方案1】:

    除非您有大量消息,否则简单的converter 可能是可行的:

    <TextBox IsReadOnly="True">
        <TextBox.Text>
            <Binding Path="Messages" Mode="OneWay">
                <Binding.Converter>
                    <vc:JoinStringsConverter />
                </Binding.Converter>
            </Binding>
        </TextBox.Text>
    </TextBox>
    
    public class JoinStringsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            var strings = value as IEnumerable<string>;
            return string.Join(Environment.NewLine, strings);
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
    

    【讨论】:

    • 由于我正在学习,这听起来是学习和编写我的第一个转换器的好方法。感谢您的建议和代码。
    【解决方案2】:

    可能有助于生成 FlowDocument 并在 FlowDocumentReader 中显示此文档。 尝试从这篇文章开始:Flow Document Overview

    生成示例:

        void ShowErrors(FlowDocumentReader reader, Exception[] errors) {
            FlowDocument doc = new FlowDocument();
            foreach (var e in errors) {
                doc.Blocks.Add(new Paragraph(new Run(e.GetType().Name)) {
                    Style = (Style)this.FindResource("header")
                });
                doc.Blocks.Add(new Paragraph(new Run(e.Message)) {
                    Style = (Style)this.FindResource("text")
                });
            }
            reader.Document = doc;
        }
    

    在这个例子中,我为 flowdocument 中的文本添加了一些样式。请看 XAML:

    <Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <Style x:Key="header" TargetType="{x:Type Paragraph}">
            <Setter Property="FontWeight" Value="Bold"/>
        </Style>
        <Style x:Key="text" TargetType="{x:Type Paragraph}">
            <Setter Property="Margin" Value="30, 0, 0, 0"/>
        </Style>
    </Window.Resources>
    <FlowDocumentReader Name="reader">
    </FlowDocumentReader>
    

    结果:

    【讨论】:

    • 花了我一段时间才弄清楚正确的语法(尤其是 /,但最终我想出了
    • FlowDocument 不支持绑定。在这种情况下,您应该在代码中生成文档并将其分配给 FlowDocumentReader 的 Document 属性。这与 WinForms 中使用 RichTextBox 的方法非常相似。当然,您也可以使用 ItemControl,但 FlowDocumentReader 是实现选择/复制功能的简单方法。
    • 我想在这里删除我的评论。这太难读了,而且不完全适合,所以我在原来的帖子中添加了一个编辑。我没有意识到 FlowDocument 没有直接直接支持绑定,我觉得有点奇怪,因为 元素确实支持绑定。根据您的建议,我看起来很棒,我只是无法粘贴结果,我不知道为什么。我可以全选,然后复制,它似乎可以工作,但是当我粘贴时没有任何显示。
    【解决方案3】:

    最简单的方法:

    假设您的视图模型实现了 INotifyPropertyChange,请为 ObservableCollection PropertyChanged 事件创建一个事件处理程序。创建一个将可观察集合中的所有项目聚合成单个字符串的属性。每当可观察集合发生变化时,为您的新属性触发通知事件。绑定到该属性

    public class ViewModel : INotifyPropertyChange
    {
        public ViewModel()
        {
            MyStrings.CollectionChanged += ChangedCollection;
        }
        public ObservableCollection<string> MyStrings{get;set;}
    
        public void ChangedCollection(args,args)
        {
            base.PropertyChanged("MyAllerts");
        }
    
        public string MyAllerts
        {
            get
            {
                string collated = "";
                foreach(var allert in MyStrings)
                {
                    collated += allert;
                        collated += "\n";
                }
            }
        }
    
    }
    

    我知道这段代码充满了错误(我是用 SO 而不是 VS 编写的),但它应该能给你一些想法。

    【讨论】:

    • 谢谢,我想我在想我遗漏了一些明显的东西,但这似乎是一个合理的解决方法。由于我仍在学习,我可能会采用以下类似的建议并尝试了解有关创建转换器的更多信息。
    • 原始foreach 字符串连接不是您应该做的事情,使用StringBuilder 否则将在每次迭代中创建一个新字符串。 (或者只使用String.Join,它会在内部为您完成所有这些工作)
    • 谢谢 HB。不了解 string.join,通常使用字符串生成器。只是使用一个快速而肮脏的例子。 string.join 实际上是有效的还是只是一个掩蔽的 foreach?
    【解决方案4】:
    <Grid Margin="6">
        <ScrollViewer VerticalScrollBarVisibility="Auto"  Height="40" Grid.Column="0" Margin="6">
            <ItemsControl ItemsSource="{Binding ErrorMessages}" >            
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                         <TextBox Text="{Binding ViewModelMemberRepresentingYourErrorMessage}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </Grid>
    

    【讨论】:

    • 我不确定这会有什么帮助。我的所有错误消息都正确显示在我的代码中(我只是无法复制和过去)。我没有代表单个错误消息的成员,只有集合。我可能不太了解 WPF,无法理解您的观点。
    • @Tod:没有任何解释,我也看不出有任何意义。
    猜你喜欢
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多