WPF: can't bind object to listbox - wpf

Trying to bind a listbox to an object. Code runs without errors but for some reason sample data doesn't appear in listbox
XAML: ucDataBindingObject.xaml
<UserControl x:Class="TheProject.UserControls.ucDataBindingObject"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Name="DataBindingObject"
Width="Auto"
Height="Auto"
mc:Ignorable="d">
<Grid Width="130"
Height="240"
Margin="0">
<ListBox Name="lbObject"
Width="110"
Height="80"
Margin="10,7,-9.6,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
DisplayMemberPath="Name"
ItemsSource="{Binding ElementName=ucDataBindingObject,
Path=Clients}" />
</Grid>
</UserControl>
C#: ucDataBindingObject.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
namespace TheProject.UserControls
{
public partial class ucDataBindingObject : UserControl
{
public List<Client> Clients { get; set; }
public ucDataBindingObject()
{
Clients = new List<Client>();
Clients.Add(new Client(1, "David")); // sample data
Clients.Add(new Client(2, "Helen"));
Clients.Add(new Client(3, "Joe"));
InitializeComponent();
}
}
C# Client.cs
using System;
using System.Linq;
namespace TheProject.UserControls
{
public class Client
{
public int ID { get; set; }
public string Name { get; set; }
public Client(int id, string name)
{
this.ID = id;
this.Name = name;
}
}
}

Update your ItemsSource Binding as
ItemsSource="{Binding Path=Clients}"
and in the constructor of your view, set its DataContext after InitializeComponents as
this.DataContext = this;
there is no element named ucDataBindingObject, its the class name of your usercontrol
OR change the elementname in binding to DataBindingObject, which you named your usercontrol

Related

Applying DataTemplates to Sample/Design Data in Expression Blend

I have a ListView that is supposed to display objects of class Sensor, for which I created a simple (for now) DataTemplate.
In order to further design this DataTemplate in Expression Blend, I created Sample Data from Class as shown in the docs (although I am using Blend for Visual Studio 2013, but it seems to be the same).
I can successfully get the Sample Data I created being displayed in a ListView, but it is not using the DataTemplate I created, since the elements displayed seem to belong to a different, "design" namespace:
The qualified name of my class is Miotec.BioSinais.ModeloDomínio.Sensor;
(But) the qualified name of the displayed class is _.di0.Miotec.BioSinais.ModeloDomínio.Sensor.
What am I doing wrong? (code and screenshot below)
<Window
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dominio="clr-namespace:Miotec.BioSinais.ModeloDomínio;assembly=Miotec.BioSinais"
mc:Ignorable="d"
x:Class="Miotec.ProtótipoColeta.ColetaConfigView"
x:Name="Window"
Title="ColetaConfigView"
Width="640" Height="480">
<Window.Resources>
<DataTemplate DataType="{x:Type dominio:Sensor}">
<Border>
<TextBlock Text="{Binding Nome}"/>
</Border>
</DataTemplate>
</Window.Resources>
<DockPanel x:Name="LayoutRoot">
<Grid x:Name="PainelCentral">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DockPanel x:Name="PainelSetupsSensores" Background="#FFB8E6E8"/>
<DockPanel x:Name="PainelSensoresDisponiveis" Background="#FFC5E2A8"
Grid.RowSpan="2" Grid.Column="1"
DataContext="{Binding ReceiverAtivo}"
d:DataContext="{d:DesignData /SampleData/ReceiverSimuladoSampleData.xaml}">
<ListView ItemsSource="{Binding Sensores}" Margin="10"/>
</DockPanel>
</Grid>
</DockPanel>
</Window>
====
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Miotec.BioSinais.ModeloDomínio
{
public abstract class Sensor : INotifyPropertyChanged
{
public abstract string Nome { get; set; }
public virtual int NívelBateria { get; set; }
public virtual int NívelSinalWireless { get; set; }
public virtual EstadoSensor Estado { get; protected set; }
public ObservableCollection<Canal> Canais { get; protected set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void RaisePropertyChanged (string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
==============

WPF: How to bind object to ComboBox

Trying to learn how to bind objects to various types of controls. In this instance, I want to get sample data in my object to appear in ComboBox. The code runs but what appears instead of values (David, Helen, Joe) is text "TheProtect.UserControls.Client")
XAML: (ucDataBindingObject.xaml)
<UserControl x:Class="TheProject.UserControls.ucDataBindingObject"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Width="Auto"
Height="Auto"
mc:Ignorable="d">
<Grid Width="130"
Height="240"
Margin="0">
<ComboBox Width="310"
HorizontalAlignment="Left"
VerticalAlignment="Top"
ItemsSource="{Binding Path=Clients}" />
</Grid>
</UserControl>
C#: ucDataBindingObject.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
namespace TheProject.UserControls
{
public partial class ucDataBindingObject : UserControl
{
public List<Client> Clients { get; set; }
public ucDataBindingObject()
{
Clients = new List<Client>();
Clients.Add(new Client(1, "David")); // sample data
Clients.Add(new Client(2, "Helen"));
Clients.Add(new Client(3, "Joe"));
InitializeComponent();
this.DataContext = this;
}
}
C# Client.cs
using System;
using System.Linq;
namespace TheProject.UserControls
{
public class Client
{
public int ID { get; set; }
public string Name { get; set; }
public Client(int id, string name)
{
this.ID = id;
this.Name = name;
}
}
}
There are several ways to tell the framework what to display
1) Use DisplayMemberPath on the ComboBox (this will display the named property):
<ComboBox ItemsSource="{Binding Path=Clients}"
DisplayMemberPath="Name"
/>
2) Set ItemTemplate on the ComboBox. This is like #1, except allows you to define a template to display, rather than just a property:
<ComboBox ItemsSource="{Binding Path=Clients}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Green" BorderThickness="1" Padding="5">
<TextBlock Text="{Binding Path=Name,StringFormat='Name: {0}'}" />
</Border>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
3) Add a ToString() override to source class. Useful if you always want to display the same string for a given class. (Note that the default ToString() is just the class type name, which is why you see "TheProtect.UserControls.Client".)
public class Client
{
// ...
public override string ToString()
{
return string.Format("{0} ({1})", Name, ID);
}
}
4) Add a DataTemplate to the XAML resources. This is useful for associating a given class type with a more complex or stylized template.
<UserControl xmlns:local="clr-namespace:TheProject.UserControls">
<UserControl.Resources>
<DataTemplate DataType="local:Client">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</UserControl.Resources>
// ...
</UserControl>
In DisplayMemberPath, give the name of the property which you want to show in the comboBox. In SelectedValuePath, give the name of the property which you want to select. When you do a ComboBox.SelectedValue, you will get the value of this property.
Trying to get selected value from combobox returns System.Data.Entity.DynamicProxies.x
private void Button_Click(object sender, RoutedEventArgs e){
string _scanner0 = int.Parse(mycmb.SelectedValue.ToString());
string _scanner1 = mycbr.SelectedItem.ToString();
string _scanner2 = mycbr.SelectedValuePath.ToString();
string _scanner3 = mycbr.text.ToString();
}
all these Returns System.Data.Entity.DynamicProxies.x
What should i do?

WPF ComboBox not Firing on selection

I have a ComboBox, shown below. Why isn't the code-behind always firing?
XAML:
<ComboBox Height="23"
Name="cbAppendCreate"
VerticalAlignment="Top"
Width="120"
Margin="{StaticResource ConsistentMargins}"
ItemsSource="{Binding Path=CbCreateAppendItems}"
SelectedValue="{Binding Path=CbAppendCreate,UpdateSourceTrigger=PropertyChanged}" />
CodeBehind:
private string cbAppendCreate;
public string CbAppendCreate {
get {
//....
return cbAppendCreate
}
set { //This doesn't fire when selecting the first of 2 Items,
//but always fires when selecting the 2nd of two items
//....
cbAppendCreate = value;
}
}
I'll post my working code here, it's very simple. I've just created a default WPF app using VS2012 template. Here's MainWindow.xaml content:
<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">
<StackPanel>
<ComboBox Height="23"
Name="cbAppendCreate"
VerticalAlignment="Top"
Width="120"
ItemsSource="{Binding Path=CbCreateAppendItems}"
SelectedValue="{Binding Path=CbAppendCreate,UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Text="{Binding CbAppendCreate}"></TextBlock>
</StackPanel>
Here's code-behind:
namespace WpfApplication1
{
public class DataSource
{
public List<string> CbCreateAppendItems { get; set; }
public string CbAppendCreate { get; set; }
public DataSource()
{
CbCreateAppendItems = new List<string>() { "create", "append" };
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new DataSource();
}
}
}
When I select different values in combo-box, the TextBlock updates to the same value, hence the VM's property is also updated.

wpf binding list, listbox and control twoway

Is there any way to update listbox items text after updating it in textboxes? I wanna do it only with bindings if it is possible. Listbox is reading from list, but list isn't updating so it's never gonna change, unless I add new item to list. Here is code
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DockPanel VerticalAlignment="Top" HorizontalAlignment="Left">
<Button Name="dodaj" Width="40" Margin="5" Click="dodaj_Click">Dodaj</Button>
<Button Name="usun" Width="40" Margin=" 5" Click="usun_Click">Usuń</Button>
</DockPanel>
<DockPanel HorizontalAlignment="Left" VerticalAlignment="Center" DataContext="{Binding ElementName=lista, Path=osoba, Mode=TwoWay}">
<ListBox Name="lb" ItemsSource="{Binding}" Width="200" Height="230">
</ListBox>
</DockPanel>
<DockPanel HorizontalAlignment="Right" VerticalAlignment="top">
<WrapPanel>
<StackPanel>
<Label>Imię</Label>
<Label>Nazwisko</Label>
<Label>Email</Label>
<Label>Telefon</Label>
</StackPanel>
<StackPanel DataContext="{Binding ElementName=lb, Path=SelectedItem, UpdateSourceTrigger=LostFocus}" TextBoxBase.TextChanged="zmiana">
<TextBox Width="200" Margin="3" Name="imie" Text="{Binding Path=imie}"></TextBox>
<TextBox Width="200" Name="nazwisko" Text="{Binding Path=nazwisko}"></TextBox>
<TextBox Width="200" Margin="3" Name="email" Text="{Binding Path=email}"></TextBox>
<TextBox Width="200" Name="telefon" Text="{Binding Path=telefon}"></TextBox>
</StackPanel>
</WrapPanel>
</DockPanel>
</Grid>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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.ComponentModel;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lista.Add(new dane("imie1", "nazwisko1", "email1", "tel1"));
lista.Add(new dane("imie2", "nazwisko2", "email2", "tel2"));
lb.DataContext = lista;
}
public class dane : INotifyPropertyChanged
{
public dane(string imie, string nazwisko, string email, string telefon)
{
this._imie = imie;
this.nazwisko = nazwisko;
this.osoba = nazwisko + " " + imie;
this.email = email;
this.telefon = telefon;
}
private string _imie;
public string imie
{
set
{
_imie = value;
OnPropertyChanged("Imie");
}
get
{
return _imie;
}
}
public string nazwisko { set; get; }
public string osoba { set; get; }
public string email { set; get; }
public string telefon { set; get; }
public override string ToString()
{
return osoba;
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string value)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(value));
}
}
}
public ObservableCollection<dane> lista = new ObservableCollection<dane>();
//public List<dane> lista = new List<dane>();
/*public ObservableCollection<dane> lista
{
get { return (ObservableCollection<dane>)GetValue(listaProperty); }
set { SetValue(listaProperty, value); }
}
public static readonly DependencyProperty listaProperty =
DependencyProperty.Register("lista", typeof(ObservableCollection<dane>), typeof(Window), new UIPropertyMetadata(null));
*/
private void dodaj_Click(object sender, RoutedEventArgs e)
{
lista.Add(new dane("...", "", "", ""));
MessageBox.Show(lista[0].ToString());
}
private void usun_Click(object sender, RoutedEventArgs e)
{
lista.RemoveAt(lb.SelectedIndex);
}
}
}
Listbox shows instances of your dane class by their ToString() representation. You should bind listbox to osoba property directly with DisplayMemberPath. And also value of osoba property is not udated then you change imia and nazwisko. You should recalculate it on its getter and also raise PropertChanged("osoba") then properties nazwisko or imia are being changed.

silverlight binding combobox in nested controls

I have 2 user controls one named Filters and one named FilterItem
Filter looks like this:
<UserControl xmlns:my="clr-namespace:AttorneyDashboard.Views.UserControls" x:Class="AttorneyDashboard.Views.UserControls.Filters"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:helpers="clr-namespace:AttorneyDashboard.Helpers"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="590" x:Name="FiltersRoot">
<Grid>
<ListBox x:Name="myListBox" ItemsSource="{Binding Path=FilterItems, ElementName=FiltersRoot}" >
<ListBox.ItemTemplate>
<DataTemplate>
<my:FilterItem ColumnsList="{Binding Path=Columns_, ElementName=FiltersRoot}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Collections.ObjectModel;
using System.Diagnostics;
using AttorneyDashboard.Helpers;
namespace AttorneyDashboard.Views.UserControls
{
public class MyItems
{
public string Header { get; set; }
}
public partial class Filters : UserControl
{
public Filters()
{
InitializeComponent();
}
private DependencyProperty FilterItemsProperty = DependencyProperty.Register("FilterItems", typeof(ObservableCollection<FilterDescriptor>), typeof(Filters), new PropertyMetadata(null, new PropertyChangedCallback(OnChangeFilterItems)));
public ObservableCollection<FilterDescriptor> FilterItems
{
get
{
return (ObservableCollection<FilterDescriptor>)GetValue(FilterItemsProperty);
}
set
{
SetValue(FilterItemsProperty, value);
}
}
public static void OnChangeFilterItems(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
public List<MyItems> Columns_
{
get
{
List<MyItems> list = new List<MyItems>();
list.Add(new MyItems() { Header = "test1" });
list.Add(new MyItems() { Header = "test2" });
list.Add(new MyItems() { Header = "test3" });
return list;
}
}
}
}
FilterItems looks like this
<UserControl x:Class="AttorneyDashboard.Views.UserControls.FilterItem"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="23" d:DesignWidth="590" xmlns:my="clr-namespace:AttorneyDashboard.Helpers" x:Name="FilterItemRoot">
<StackPanel Orientation="Horizontal">
<ComboBox Height="23" HorizontalAlignment="Left" Name="FieldName" VerticalAlignment="Top" Width="120" Margin="5,0,0,0" ItemsSource="{Binding Path=ColumnsList, ElementName=FilterItemRoot}" SelectedItem="{Binding PropertyPath, Mode=TwoWay}" DisplayMemberPath="Header"/>
</StackPanel>
</UserControl>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using AttorneyDashboard.Helpers;
using System.Windows.Data;
namespace AttorneyDashboard.Views.UserControls
{
public partial class FilterItem : UserControl
{
public FilterItem()
{
InitializeComponent();
}
private DependencyProperty ColumnsListProperty = DependencyProperty.Register("ColumnsList", typeof(List<MyItems>), typeof(FilterItem), new PropertyMetadata(null, new PropertyChangedCallback(OnChangeColumns)));
public List<MyItems> ColumnsList
{
get
{
return (List<MyItems>)GetValue(ColumnsListProperty);
}
set
{
SetValue(ColumnsListProperty, value);
}
}
public static void OnChangeColumns(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
}
The number of FilterItems is ok (this means that FilterItems binding works ok), but only the Combobox of the last FilterItem is populated...
And I do not know what exactly is wrong...
Update:
I found why but I stll do not know a solution...
It seams that the content of FilterItem is binded before his properties are..
So the combobox in FilterItem is binded before the Columns property is binded...
Your code in FilterItem
private DependencyProperty ColumnsListProperty = DependencyProperty
.Register("ColumnsList", typeof(List<MyItems>), typeof(FilterItem),
new PropertyMetadata(null, new PropertyChangedCallback(OnChangeColumns)));
Please, make it static:
private **static** DependencyProperty ColumnsListProperty = DependencyProperty
.Register("ColumnsList", typeof(List<MyItems>), typeof(FilterItem),
new PropertyMetadata(null, new PropertyChangedCallback(OnChangeColumns)));
Thats it.
P.S. : in Filters make dependency property static too, generally do it anywhere :)
You have placed a x:Name attribute directly on your UserControl elements. Don't do that. Use this pattern instead:-
<UserControl x:Class="AttorneyDashboard.Views.UserControls.FilterItem"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="23" d:DesignWidth="590" xmlns:my="clr-namespace:AttorneyDashboard.Helpers" >
<StackPanel Orientation="Horizontal" x:Name="LayoutRoot">
<ComboBox Height="23" HorizontalAlignment="Left" Name="FieldName" VerticalAlignment="Top" Width="120" Margin="5,0,0,0" ItemsSource="{Binding Path=Parent.ColumnsList, ElementName=LayoutRoot}" SelectedItem="{Binding PropertyPath, Mode=TwoWay}" DisplayMemberPath="Header"/>
</StackPanel>
</UserControl>
You are not in control of name assigned to the user control, that belongs in the scope of the Xaml the uses your UserControl. If your code internally requires that the containing UserControl have a specific name then things are likely to break.

Resources