Binding the Width of columns to DependencyProperty with a IValueConverter - wpf

I am trying to make the width of a column in a Grid element variable. For this I have a DependencyProperty "ItemWidth" and bind the Width-element from the Button to this DP. Because of the TwoWay-Binding, I need a converter that converts doubles to DataGridLength.
My MainWindow.xaml looks like this:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:utils="clr-namespace:WpfApplication1" Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.Resources>
<utils:ColumnWidthConverter x:Key="columnWidthConverter"/>
</Grid.Resources>
<Button Grid.Row="0" Grid.Column="0" Width="{Binding Path=ItemWidth, Mode=TwoWay, Converter={StaticResource columnWidthConverter}}" Click="Shorter_Click">shorter</Button>
<Button Grid.Row="0" Grid.Column="1" Width="{Binding Path=ItemWidth, Mode=TwoWay, Converter={StaticResource columnWidthConverter}}" Click="Longer_Click">longer</Button>
</Grid>
</Window>
The ColumnWidthConverter.cs is as follows:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows;
namespace WpfApplication1
{
class ColumnWidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
else
{
DataGridLengthConverter cv = new DataGridLengthConverter();
object result = cv.ConvertFrom(value);
return result;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return null;
else
{
DataGridLengthConverter cv = new DataGridLengthConverter();
return cv.ConvertTo(value, typeof(double));
}
}
}
}
And the MainWindow.xaml.cs looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public double ItemWidth
{
get { return (double)GetValue(ItemWidthProperty); }
set { SetValue(ItemWidthProperty, value); }
}
public static readonly DependencyProperty ItemWidthProperty =
DependencyProperty.Register("ItemWidth", typeof(double), typeof(MainWindow), new UIPropertyMetadata(0.0));
private void Shorter_Click(object sender, RoutedEventArgs e)
{
this.ItemWidth -= 100;
}
private void Longer_Click(object sender, RoutedEventArgs e)
{
this.ItemWidth += 100;
}
}
}
So the Width of the Buttons should change when I click one of the Buttons. But this does not happen. Can you tell me why that is and some sort of solution?

You set no source in the binding, hence it is relative to the DataContext, which you do not appear to have set anywhere, if you add it that should work. e.g.
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}" ...
You might want to (i.e. you definitely should) look into debugging data bindings if you are not familiar with it.
You also bind properties which have no need for the converter, in fact the converter will probably cause problems here, did you not mean to bind the ColumnDefinition.Width?

i use the following for my GridSplitter
public class DoubleToGridLengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double i = (double)value;
GridLength result = new GridLength(i);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
GridLength g = (GridLength)value;
return (double)g.Value;
}
}
xaml
Width="{Binding Source={x:Static Properties:Settings.Default}, Path=GridSplitter, Mode=TwoWay, Converter={StaticResource GridLengthConverter}}"

Related

Selecting an already selected RadioButton will select all RadioButtons

I have two radio buttons and are binding them to an enum
Like in How to bind RadioButtons to an enum?
namespace RadioButtons
{
public enum WorkModeEnum
{
Auto,
Manual,
}
}
<Window
x:Class="RadioButtons.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:RadioButtons"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
ContentRendered="Window_ContentRendered"
mc:Ignorable="d">
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<StackPanel.Resources>
<local:EnumToBooleanConverter x:Key="ComparisonConverter" />
</StackPanel.Resources>
<RadioButton Content="Auto" IsChecked="{Binding Path=WorkMode, Mode=TwoWay, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:WorkModeEnum.Auto}}" />
<RadioButton Content="Manual" IsChecked="{Binding Path=WorkMode, Mode=TwoWay, Converter={StaticResource ComparisonConverter}, ConverterParameter={x:Static local:WorkModeEnum.Manual}}" />
</StackPanel>
</Grid>
</Window>
Code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace RadioButtons
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel _vm;
public MainWindow()
{
InitializeComponent();
}
private void Window_ContentRendered(object sender, EventArgs e)
{
_vm = new ViewModel();
DataContext = _vm;
}
}
}
The converter code looks like this
public class EnumToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((Enum)value).HasFlag((Enum)parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
ViewModel
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace RadioButtons
{
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
WorkMode = WorkModeEnum.Manual;
}
private WorkModeEnum _WorkMode;
public WorkModeEnum WorkMode
{
get { return _WorkMode; }
set
{
_WorkMode = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
It works, except for when the user click on the Manual button when it's already selected!
Then both of the buttons will show selected!
Why and how fix it?
The whole project is accessible (hopefully, I have never done this before) at
https://github.com/Andis59/RadioButtons
Your problem is the Converter. You are using a normal Enum but the converter treat it as [Flags] (which are a kind of different).
Enum.HasFlag(flag) will always return true if the ordinal value of the given flag is 0. Your WorkModeEnum.Auto has that ordinal value of 0 and causing this.
You could fix this by changing the WorkModeEnum definition to
public enum WorkModeEnum
{
Auto = 1,
Manual = 2,
}
but it is much better to fix the Converter
public class EnumToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((Enum)parameter).Equals((Enum)value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}

WPF datagrid not fetching hexadecimal values properly, it displays a message Byte[] Array for hexadecimal Values?

WPF datagrid is not fetching hexadecimal values properly, it displays a message Byte[] Array for hexadecimal Values?
Do I need to change anything in the coding?
Here is how you can do it using a converter:
MainWindow.xaml
<Window x:Class="ByteArrayHex.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ByteArrayHex"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<StackPanel.Resources>
<local:ByteArrayToHexConverter x:Key="ByteArrayToHexConverter" />
</StackPanel.Resources>
<TextBlock Margin="5" Text="{Binding ba, Converter={StaticResource ByteArrayToHexConverter}}" Background="Beige" />
</StackPanel>
</Window>
MainWindow.xaml.cs
using System;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Windows;
using System.Windows.Data;
namespace ByteArrayHex
{
public partial class MainWindow : Window
{
public byte[] ba { get; set; }
public MainWindow()
{
InitializeComponent();
this.ba = new byte[] { 0x49, 0x4A, 0x4B, 0x4C, 0x4D };
this.DataContext = this;
}
}
public class ByteArrayToHexConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
byte[] ba = value as byte[];
if (ba == null)
return null;
SoapHexBinary shb = new SoapHexBinary(ba);
return shb.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

What has happened to MultiBinding between .NET 3.5 and .NET 4.5?

We are currently in the process of converting a project from version 3.5 to version 4.5 of .NET.
We set a text box IsEnabled flagged using a multi binding with a multi binding converter. Each of the bindings has their own converter.
All worked well in .NET 3.5 but in .NET 4.5 the target type that is passed to the child converter is of type object instead of bool.
Is this a known issue? has MS refactored the multi binding to not pass the target type to child converters.
I created a simplified project that demonstrates the issue. I created the project in VS2008 and then converted it to VS2012 and .NET 4.5.
Window XAML:
<Window x:Class="TestMultiBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestMultiBinding"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:NotConverter x:Key="NotConverter"/>
<local:MultiBoolConverter x:Key="MultiBoolConverter"/>
</Window.Resources>
<StackPanel>
<TextBox>
<TextBox.IsEnabled>
<MultiBinding Converter="{StaticResource MultiBoolConverter}">
<Binding Path="ConditionOne" />
<Binding Path="ConditionTwo" Converter="{StaticResource NotConverter}"/>
</MultiBinding>
</TextBox.IsEnabled>
</TextBox>
</StackPanel>
</Window>
c#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Globalization;
namespace TestMultiBinding
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
public class ViewModel
{
public bool ConditionOne { get { return true; } }
public bool ConditionTwo { get { return false; } }
}
/// <summary>
/// Converts a boolean to its inverse (useful for radio buttons).
/// </summary>
[ValueConversion(typeof(bool), typeof(bool))]
public class NotConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType != typeof(bool) && targetType != typeof(bool?)) { throw new ArgumentException("Can only convert booleans.", "targetType"); }
//return !(bool)value;
return !true.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Convert(value, targetType, parameter, culture);
}
}
/// <summary>
/// Converts multiple boolean values to one. Uses AND by default. Possible extension: Pass the desired operation as parameter
/// </summary>
[ValueConversion(typeof(bool), typeof(bool))]
public class MultiBoolConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
try
{
// todo: support other operations like OR, XOR
return values.Cast<bool>().Aggregate(true, (res, cur) => res && cur);
}
catch (Exception ex)
{
System.Diagnostics.Trace.TraceError("MultiBoolConverter({0}): {1}", parameter, ex.Message);
return DependencyProperty.UnsetValue;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
System.Diagnostics.Trace.TraceError("MultiBoolConverter: does not support TwoWay or OneWayToSource bindings.");
return null;
}
}
}
Is there a reason you are testing that the targetType is bool?
I'm surprised it worked in 3.5, as the NonConverter is converting from bool to object (as the MultiBinding takes an array of object as it's inout).
I did some digging using reflector, and the underlying logic did change.
This is from the internal void TransferValue(object newValue, bool isASubPropertyChange) method of BindingExpression
In 3.5:
internal void TransferValue(object newValue, bool isASubPropertyChange)
{
DependencyObject targetElement = this.TargetElement;
if (targetElement == null || this.Worker == null)
return;
Type propertyType = this.TargetProperty.PropertyType;
In 4.5, all calls to propertyType are replaced by the below definition of effectiveTargetType:
internal void TransferValue(object newValue, bool isASubPropertyChange)
{
DependencyObject targetElement = this.TargetElement;
if (targetElement == null || this.Worker == null)
return;
Type effectiveTargetType = this.GetEffectiveTargetType();
...
}
internal Type GetEffectiveTargetType()
{
Type type = this.TargetProperty.PropertyType;
for (BindingExpressionBase bindingExpressionBase = this.ParentBindingExpressionBase; bindingExpressionBase != null; bindingExpressionBase = bindingExpressionBase.ParentBindingExpressionBase)
{
if (bindingExpressionBase is MultiBindingExpression)
{
type = typeof (object);
break;
}
}
return type;
}
I'm not sure what TargetProperty is set to in this case, but you can see why it's now being set to object for MultiBindings.
And, FYI, it appears this change occurred in .NET 4.0.

How to get specific icon in a container (like dll) in XAML?

I can set in XAML the icon container:
<Image Source="Shell32.dll.ico" />
But how can I set in XAML the icon index in the container ? something like:
<Image Source="Shell32.dll,5" />
Or like:
<Image Source="Shell32.dll" Index="5" />
etc...
This is how it goes: first the IValueConverter:
using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Data;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
[ValueConversion(typeof(string), typeof(ImageSource))]
public class HabeasIcon : IValueConverter
{
[DllImport("shell32.dll")]
private static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string[] fileName = ((string)parameter).Split('|');
if (targetType != typeof(ImageSource))
return Binding.DoNothing;
IntPtr hIcon = ExtractIcon(Process.GetCurrentProcess().Handle, fileName[0], int.Parse(fileName[1]));
ImageSource ret = Imaging.CreateBitmapSourceFromHIcon(hIcon, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
return ret;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{ throw new NotImplementedException(); }
}
The XAML:
<Image Source="{Binding Converter={StaticResource iconExtractor}, ConverterParameter=c:\\Windows\\System32\\shell32.dll|72}"/>

WPF textblock binding with List<string>

does anyone know if there is a simple way to bind a textblock to a List.
What I've done so far is create a listview and bind it to the List and then I have a template within the listview that uses a single textblock.
what I'd really like to do is just bind the List to a textblock and have it display all the lines.
In Winforms there was a "Lines" property that I could just throw the List into, but I'm not seeing it on the WPF textblock, or TextBox.
Any ideas?
did I miss something simple?
Here's the code
<UserControl x:Class="QSTClient.Infrastructure.Library.Views.WorkItemLogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="500" Height="400">
<StackPanel>
<ListView ItemsSource="{Binding Path=Logs}" >
<ListView.View>
<GridView>
<GridViewColumn Header="Log Message">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</StackPanel>
and the WorkItem Class
public class WorkItem
{
public string Name { get; set; }
public string Description { get; set; }
public string CurrentLog { get; private set; }
public string CurrentStatus { get; private set; }
public WorkItemStatus Status { get; set; }
public ThreadSafeObservableCollection<string> Logs{get;private set;}
I'm using Prism to create the control and put it into a WindowRegion
WorkItemLogView newView = container.Resolve<WorkItemLogView>();
newView.DataContext = workItem;
regionManager.Regions["ShellWindowRegion"].Add(newView);
thanks
Convert your List to a single string with "\r\n" as the delimiter in between. and bind that to the TextBlock. Make sure that the TextBlock is not restricted with its height , so that it can grow based on the number of lines.
I would implement this as a Value Converter to XAML Binding which converts a List of strings to a single string with new line added in between
<TextBlock Text="{Binding Path=Logs,Converter={StaticResource ListToStringConverter}}"/>
The ListToStringConverter would look like this:
[ValueConversion(typeof(List<string>), typeof(string))]
public class ListToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType != typeof(string))
throw new InvalidOperationException("The target must be a String");
return String.Join(", ", ((List<string>)value).ToArray());
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
if you use the converter it works for the first time perfect,
but if one or more logging comes to the logging list, there is no update on your binding, because the converter works only at the first time.
all controls that are no item controls doesn't subscribe to the listchanged event!
here is a little code for this scenario
using System;
using System.Collections.ObjectModel;
using System.Windows;
namespace BindListToTextBlock
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private WorkItem workItem;
public MainWindow() {
this.WorkItems = new ObservableCollection<WorkItem>();
this.DataContext = this;
this.InitializeComponent();
}
public class WorkItem
{
public WorkItem() {
this.Logs = new ObservableCollection<string>();
}
public string Name { get; set; }
public ObservableCollection<string> Logs { get; private set; }
}
public ObservableCollection<WorkItem> WorkItems { get; set; }
private void Button_Click(object sender, RoutedEventArgs e) {
this.workItem = new WorkItem() {Name = string.Format("new item at {0}", DateTime.Now)};
this.workItem.Logs.Add("first log");
this.WorkItems.Add(this.workItem);
}
private void Button_Click_1(object sender, RoutedEventArgs e) {
if (this.workItem != null) {
this.workItem.Logs.Add(string.Format("more log {0}", DateTime.Now));
}
}
}
}
the xaml
<Window x:Class="BindListToTextBlock.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:BindListToTextBlock="clr-namespace:BindListToTextBlock"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<Grid.Resources>
<BindListToTextBlock:ListToStringConverter x:Key="ListToStringConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Grid.Row="0"
Content="Add item..."
Click="Button_Click" />
<Button Grid.Row="1"
Content="Add some log to last item"
Click="Button_Click_1" />
<ListView Grid.Row="2"
ItemsSource="{Binding Path=WorkItems}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Log Message">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Logs, Converter={StaticResource ListToStringConverter}}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
the converter
using System;
using System.Collections;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
namespace BindListToTextBlock
{
public class ListToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
if (value is IEnumerable) {
return string.Join(Environment.NewLine, ((IEnumerable)value).OfType<string>().ToArray());
}
return "no messages yet";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
return DependencyProperty.UnsetValue;
}
}
}
EDIT
here is a quick solution for the update propblem (this can be also made with a attached property)
public class CustomTextBlock : TextBlock, INotifyPropertyChanged
{
public static readonly DependencyProperty ListToBindProperty =
DependencyProperty.Register("ListToBind", typeof(IBindingList), typeof(CustomTextBlock), new PropertyMetadata(null, ListToBindPropertyChangedCallback));
private static void ListToBindPropertyChangedCallback(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var customTextBlock = o as CustomTextBlock;
if (customTextBlock != null && e.NewValue != e.OldValue) {
var oldList = e.OldValue as IBindingList;
if (oldList != null) {
oldList.ListChanged -= customTextBlock.BindingListChanged;
}
var newList = e.NewValue as IBindingList;
if (newList != null) {
newList.ListChanged += customTextBlock.BindingListChanged;
}
}
}
private void BindingListChanged(object sender, ListChangedEventArgs e)
{
this.RaisePropertyChanged("ListToBind");
}
public IBindingList ListToBind
{
get { return (IBindingList)this.GetValue(ListToBindProperty); }
set { this.SetValue(ListToBindProperty, value); }
}
private void RaisePropertyChanged(string propName)
{
var eh = this.PropertyChanged;
if (eh != null) {
eh(this, new PropertyChangedEventArgs(propName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
here is the usage for the CustomTextBlock (not tested)
<TextBlock Text="{Binding Path=ListToBind, RelativeSource=Self, Converter={StaticResource ListToStringConverter}}"
ListToBind={Binding Path=Logs} />
#Fueled hope this helps
I'll shamelessly post a link to my answer of a very similar question: Binding ObservableCollection<> to a TextBox.
Like punker76 said, if you bind your Text to a collection it will update when you set the collection, but not when the collection changes. This link demonstrates an alternative to punker76's solution (the trick is to multi-bind to the collection's count too).
For concat collection of objects :
/// <summary>Convertisseur pour concaténer des objets.</summary>
[ValueConversion(typeof(IEnumerable<object>), typeof(object))]
public class ConvListToString : IValueConverter {
/// <summary>Convertisseur pour le Get.</summary>
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
return String.Join(", ", ((IEnumerable<object>)value).ToArray());
}
/// <summary>Convertisseur inverse, pour le Set (Binding).</summary>
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
throw new NotImplementedException();
}
}
Juste think to overide the ToString() of your object.

Resources