Reputation: 3707
I am trying to bind a data class to a ListView control in WPF, but can't seem to get it working. I can bind it at run-time and get it working using the following:
this.DataContext = DataSet;
But, if I try the following in the WPF/XAML it doesn't work:
DataContext="DiscoveredItemContainer"
I have tried various permutations, but nothing I try works. I could just use the run-time version, as it works, but it is bugging me that I can't make the XAML bind the control correctly. Perhaps this can't work since the dataset is dynamic in nature, but that is just a thought.
I am not sure if the code will help answer the question or not, but I will post what is relevant, I hope any how. I left out the using declarations.
This is the XAML for the form
<Window x:Class="Viking.Test.DataBindTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Items="clr-namespace:Viking.Test.Discovery"
xmlns:data="clr-namespace:Viking.Test"
Title="Data Binding Test" Height="300" Width="500"
DataContext="DiscoveredItemContainer">
<DockPanel Name="_DockPanel" Height="Auto" Width="Auto">
<Menu Name="_Menu" DockPanel.Dock="Top" Height="22" Width="Auto" VerticalContentAlignment="Center" VerticalAlignment="Top">
<MenuItem Name="_File" Header="File">
<MenuItem Name="_AddOne" Header="Add One" Click="AddOne_Click" />
</MenuItem>
</Menu>
<ListView Name="listView1" Height="Auto" Width="Auto" ItemsSource="{Binding Path=DiscoveredItems}">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Field1" DisplayMemberBinding="{Binding Field1}" Width="100" />
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</Window>
Here is the partial class that goes with the XAML
namespace Viking.Test
{
public partial class DataBindTest : Window
{
private DiscoveredItemList DiscoveredItemContainer;
public DataBindTest()
{
InitializeComponent();
DiscoveredItemContainer = new DiscoveredItemList();
// Uncomment the following line to get the databinding to work
// this.DataContext = DiscoveredItemContainer;
}
private void AddOne_Click(object sender, RoutedEventArgs e)
{
DiscoveredItemContainer.AddRandomItem();
}
} // End of Class
} // End of Namespace
The following is the class that contains the dataset
namespace Viking.Test.Discovery
{
public class DiscoveredItem
{
public DiscoveredItem()
{
}
public string Field1 { get; set; }
} // End of Class
} // End of Namespace
Finally, this is the class that will expose the variable that is ObservableCollection to bind the data to the class
namespace Viking.Test.Discovery
{
class DiscoveredItemList
{
public ObservableCollection<DiscoveredItem> DiscoveredItems { get; set; }
private Random RandomGen;
public DiscoveredItemList()
{
DiscoveredItems = new ObservableCollection<DiscoveredItem>();
RandomGen = new Random();
}
public void AddRandomItem()
{
DiscoveredItem di = new DiscoveredItem();;
di.Field1 = RandomGen.Next(1,10).ToString();
DiscoveredItems.Add(di);
}
} // End of Class
} // End of Namespace
I have seen a great number of articles of binding a control to another control that is on the form, or binding during run-time (which is how I can get this to work) or binds to static resources.
Any insight as to why I can't get this approach to work is appreciated.
Upvotes: 0
Views: 3772
Reputation: 3476
By setting your DataContext in XAML, you've decided to instantiate a new DiscoveredItemList instead of binding to the one in your codebehind. Therefore your codebehind won't have a direct reference to the DiscoveredItemList, but you can always search for it by name.
The first thing you need to do is remove:
DataContext="DiscoveredItemContainer"
and replace with:
<Window.Resources>
<Items:DiscoveredItemList x:Key="Context"></Items:DiscoveredItemList>
</Window.Resources>
This instantiates a new object that your xaml can now bind to. Your list view should bind to it this way:
<ListView Name="listView1" Height="Auto" Width="Auto" DataContext="{StaticResource Context}" ItemsSource="{Binding DiscoveredItems}">
...
</ListView>
You must also gut out all the references to DiscoveredItemContainer in your code behind, and when you want to access the Items:DiscoveredItemList, such as to add a new random item, do this:
private void AddOne_Click(object sender, RoutedEventArgs e)
{
var list = this.Resources["Context"] as DiscoveredItemList;
list.AddRandomItem();
}
You could perhaps store a local reference to the item if you want to.
Here's the complete code for your copy/pasting pleasure. Note that I've tested this and "it works for me" :P
namespace Viking.Test
{
public partial class DataBindTest : Window
{
public DataBindTest()
{
InitializeComponent();
}
private void AddOne_Click(object sender, RoutedEventArgs e)
{
var list = this.Resources["Context"] as DiscoveredItemList;
list.AddRandomItem();
}
} // End of Class
} // End of Namespace
//The following is the class that contains the dataset
namespace Viking.Test.Discovery
{
public class DiscoveredItem
{
public DiscoveredItem() { }
public string Field1 { get; set; }
} // End of Class
public class DiscoveredItemList
{
public ObservableCollection<DiscoveredItem> DiscoveredItems { get; set; }
private Random RandomGen;
public DiscoveredItemList()
{
DiscoveredItems = new ObservableCollection<DiscoveredItem>();
RandomGen = new Random();
}
public void AddRandomItem()
{
DiscoveredItem di = new DiscoveredItem(); ;
di.Field1 = RandomGen.Next(1, 10).ToString();
DiscoveredItems.Add(di);
}
} // End of Class
}
XAML:
<Window x:Class="Viking.Test.DataBindTest" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Items="clr-namespace:Viking.Test.Discovery" xmlns:data="clr-namespace:Viking.Test" Title="Data Binding Test" Height="300" Width="500" >
<Window.Resources>
<Items:DiscoveredItemList x:Key="Context"></Items:DiscoveredItemList>
</Window.Resources>
<DockPanel Name="_DockPanel" Height="Auto" Width="Auto" >
<Menu Name="_Menu" DockPanel.Dock="Top" Height="22" Width="Auto" VerticalContentAlignment="Center" VerticalAlignment="Top">
<MenuItem Name="_File" Header="File">
<MenuItem Name="_AddOne" Header="Add One" Click="AddOne_Click" />
</MenuItem>
</Menu>
<ListView Name="listView1" Height="Auto" Width="Auto" DataContext="{StaticResource Context}" ItemsSource="{Binding DiscoveredItems}">
<ListView.View>
<GridView AllowsColumnReorder="True">
<GridViewColumn Header="Field1" DisplayMemberBinding="{Binding Field1}" Width="100" />
</GridView>
</ListView.View>
</ListView>
</DockPanel>
</Window>
Reference: Silverlight - Setting DataContext in XAML rather than in constructor?
Upvotes: 3
Reputation: 71
you should replace
DataContext="DiscoveredItemContainer"
by
DataContext="{Binding DiscoveredItemContainer}"
Upvotes: 1