Reputation: 75
I'm trying to switch over to WPF from Winform and so far it's a pain.
Anyway, I am trying to get this binding thing to work using DataTemplate.
I have a class:
public class TranslatorListItem
{
public string Item { get; set; }
public string OriginalMessage { get; set; }
public string TranslatedMessage { get; set; }
public string Sector { get; set; }
}
Items are added like this:
TranslatorListItem TLI = new TranslatorListItem();
TranslatorLVI.Items.Add(TLI);
My XAML DataTemplate:
<DataTemplate x:Key="MyDataTemplate">
<Border BorderBrush="#FFA4D5E5" BorderThickness="1,1,0,0" Margin="6">
<StackPanel Margin="6,2,6,2">
<TextBox Text="{Binding}" TextWrapping="Wrap" BorderThickness="0" BorderBrush="#00000000" />
</StackPanel>
</Border>
</DataTemplate>
This is how I'm trying to bind the data but it's returning this error: "Two-way binding requires Path or XPath."
<ListView Margin="23,224,27,54" Name="TranslatorLVI" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch"
ItemContainerStyle="{StaticResource MyItemContainerStyle}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Path=Item}" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Original Message" Width="300" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Translated Message" DisplayMemberBinding="{Binding Path=TranslatedMessage}" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Sector" DisplayMemberBinding="{Binding Path=Sector}" />
</GridView>
</ListView.View>
</ListView>
I need TranslatedMessage binding to be editable. So that field wont be Read-Only. I heard I may need to set Two-way binding, but I am not sure how to do so.
Any help is appreciated. Thanks!
Upvotes: 0
Views: 779
Reputation: 19
In my opinion you dont fully use the datatemplate. you just use it to display one property; In fact you can use a DataTemplate to display all data in thie class (TranslatorListItem); such as this
<DataTemplate x:Key="MyDataTemplate">
<Border BorderBrush="#FFA4D5E5" BorderThickness="1,1,0,0" Margin="6">
<TextBox Text="{Binding Item}"
TextWrapping="Wrap"
BorderThickness="0"
BorderBrush="#00000000" />
<TextBox Text="{Binding TranslatedMessage}"
TextWrapping="Wrap"
BorderThickness="0"
BorderBrush="#00000000" />
( ..... follow up)
</Border>
</DataTemplate>
So your ListView can design like this:
<ListView ItemsSource="{Binding}" HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource MyDataTemplate}">
</ListView>
Upvotes: 1
Reputation: 44028
I'm trying to switch over to WPF from Winform and so far it's a pain.
No, it's not. WPF is the best UI Framework in the history of mankind. winforms (or anything else) can't even be compared with it.
Your problem is you're trying to use a winforms approach in WPF and you fail. WPF does not support developers with a winforms mentality.
All the horrible code behind hacks you're used to from winforms are completely unneeded in WPF.
Please read Rachel's Excellent Answer (and linked blog posts) about the mindshift needed when upgrading from winforms to WPF.
As mentioned in @JasRaj's answer, you're missing a DisplayMemberBinding
in this case. I tested your code and added that, like this:
<GridViewColumn Header="Original Message"
DisplayMemberBinding="{Binding OriginalMessage}"
Width="300"/>
And it worked perfectly.
After a second read to your question I realized you wanted to make one of these columns editable.
First of all I will say that while what you want can be achieved with a ListView
, using a DataGrid
is easier.
You need to remove the DisplayMemberBinding
s from the ListView
in order to use a CellTemplate
, and therefore you need to modify the template slightly:
<DataTemplate x:Key="MyDataTemplate">
<Border BorderBrush="#FFA4D5E5" BorderThickness="1,1,0,0" Margin="6">
<TextBox Text="{Binding TranslatedMessage}"
TextWrapping="Wrap"
BorderThickness="0"
BorderBrush="#00000000" />
</Border>
</DataTemplate>
I have placed a ListView
and a DataGrid
side by side so you can compare them:
Here is the XAML:
<UniformGrid Columns="2">
<ListView ItemsSource="{Binding}" HorizontalContentAlignment="Stretch">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Item" DisplayMemberBinding="{Binding Path=Item}"/>
<GridViewColumn Header="Original Message" DisplayMemberBinding="{Binding OriginalMessage}" Width="300"/>
<GridViewColumn Header="Translated Message" CellTemplate="{StaticResource MyDataTemplate}" />
<GridViewColumn Header="Sector"/>
</GridView>
</ListView.View>
</ListView>
<DataGrid ItemsSource="{Binding}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Item" Binding="{Binding Path=Item}" IsReadOnly="True"/>
<DataGridTextColumn Header="Original Message" Binding="{Binding OriginalMessage}" IsReadOnly="True" Width="300"/>
<DataGridTextColumn Header="Translated Message" Binding="{Binding TranslatedMessage}" />
<DataGridTextColumn Header="Sector" Binding="{Binding Sector}"/>
</DataGrid.Columns>
</DataGrid>
</UniformGrid>
Notice how the ListView requires DataTemplates
in order to support edition, and is read-only by default, while the DataGrid
is editable by default, does not need any special templats and requires that you add the IsReadOnly="True"
to columns that are intended to be read-only.
Also, I noticed you're adding items manually to the ListView
using procedural code. This is not desired in WPF. You must use an ObservableCollection<>
and manipulate that collection, and let the WPF Binding engine update the UI for you.
It is recommended and desired that you Separate logic/data from UI in WPF.
If you need further clarification please let me know.
Upvotes: 2
Reputation: 2136
Bind the second columns of Gridview with OriginalMessage property.
like :-
DisplayMemberBinding="{Binding Path=OriginalMessage}"
it should work.
Upvotes: 1