I\'m new to WPF and I\'ve found some similar questions but can\'t quite figure out the last part. I have a ViewModel with an ObservableCollection that contains error messag
May be usefull to generate FlowDocument and show this document in FlowDocumentReader. Try to start from this article: Flow Document Overview.
Example of generation:
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;
}
In this example I have added some styles for text in flowdocument. PLease look at 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>
Result:
Simplest way:
Assuming your viewmodel implements INotifyPropertyChange, create an event handler for the ObservableCollection PropertyChanged event. Create a property which aggregates all of the items in the observable colleciton into a single string. Whenever the observable collection changes, fire off a notification event for your new property. Bind to that property
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";
}
}
}
}
I know this code is fraught with errors (i wrote it in SO instead of VS), but it should give you some idea.
Unless you have a great amount of messages a simple converter might be viable:
<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();
}
}
<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>