Unable to bind to a collection of my ViewModel - wpf

All - Trying to do 2 things: I have a simple app and am trying to bind my Viewmodel collection to my view. Have 2 approaches in mind but am getting stuck on both of them:
Approach 1: Using Grid as a container to bind the textblock property.
Approach 2: Binding an attribute of the object directly to a textblock on my view (not using grid as a container and its Datacontext property)
Rule_Model_1.cs
public class Rule_Model_1
{
public string topMessage { get; set; }
public List<string> recipients { get; set; }
public string bottomMessage { get; set; }
public string hypLink { get; set; }
public OCCBlock blockType { get; set; }
public enum OCCBlock
{
HardBlock,
SoftBlock,
ModifyAndSend
}
}
Rule_VM_1.cs
class Rule_VM_1
{
#region Properties
public List<Rule_Model_1> rule { get; set; }
#endregion
#region Constructor
public Rule_VM_1()
{
#region Initializing a Rule
rule = new List<Rule_Model_1>();
rule.Add(new Rule_Model_1()
{
topMessage = "Lorem ipsum dolor sit amet.",
recipients = new List<string> {"pr#hotmail.com", "pra#gmail.com"},
bottomMessage = "Lorem ipsum dolor sit amet",
hypLink = "http://www.abc.com",
blockType = Rule_Model_1.OCCBlock.HardBlock
});
#endregion
}
#endregion
}
Rule_UI.xaml.cs
public partial class Rule_UI_1 : UserControl
{
Rule_VM_1 rulevm1;
public Rule_UI_1()
{
InitializeComponent();
rulevm1 = new Rule_VM_1();
DataContext = rulevm1;
}
}
Rule_UI.xaml
<UserControl x:Class="OCC_WPF_POC.Rule_UI_1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d">
<GroupBox Header="Rule Details">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" DataContext="{Binding rule}">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="200"></RowDefinition>
<RowDefinition Height="50"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding topmessage}" />
</Grid>
</Grid>
</GroupBox>
The view still shows nothing. Also as mentioned above - how do i have both the approaches working? Any code samples is greatly appreciated
Image Attached

The problem is that you need a list view to bind to a collection property (rule). This should work:
<ListBox Grid.Column="1" ItemsSource="{Binding rule}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding topmessage}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
To bind to the grid, you can set the DataContext using an indexer []:
<Grid Grid.Column="1" DataContext="{Binding rule[0]}">
<TextBlock Grid.Row="0" Text="{Binding topmessage}" />
</Grid>
And without the Grid:
<TextBlock Text="{Binding rule[0].topmessage}" />

Related

Fill textbox with a property with Binding MVVM

I try to figure out how MVVM works and want to start simple.
I made a Model, a View and a ViewModel. I hooked up the view to a window. this works more or less.
in the view i have a textbox which i want to fill with the value of a property. The textbox keeps empty!?
This is what i have:
Model:
namespace Qbox_0001.Model
{
public class RegistratieModel
{
}
public class Registratie : INotifyPropertyChanged
{
//Fields
private string programmaNaam;
//eventhandler die kijkt of een property wijzigt
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
//Properies
public string ProgrammaNaam
{
get { return programmaNaam; }
set
{
if (programmaNaam != value)
{
programmaNaam = value;
RaisePropertyChanged("ProgrammaNaam");
}
}
}
}
}
The View:
<UserControl x:Name="UserControlRegistratie" x:Class="Qbox_0001.Views.RegistratieView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Qbox_0001.Views"
mc:Ignorable="d" Height="1000" Width="860" MaxWidth="860" HorizontalContentAlignment="Left" VerticalContentAlignment="Top">
<Grid x:Name="GridRegistratie">
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDef_Menu" Height="21*" MaxHeight="21" MinHeight="21"/>
<RowDefinition x:Name="RowDef_TabControl" Height="500*" MinHeight="500"/>
<RowDefinition x:Name="Rowdef_Bottom" Height="40*" MaxHeight="40" MinHeight="40"/>
</Grid.RowDefinitions>
<Grid x:Name="Grid_Registratie_WorkArea" Grid.Row="1">
<TabControl x:Name="TabControl_Registratie">
<TabItem Header="Registratie">
<Grid x:Name="Grid_Tab_Registratie">
<Border>
<Grid>
<Grid.RowDefinitions>
<RowDefinition x:Name="GridRowDef_Algemeen" MinHeight="68" Height="68*" MaxHeight="68"/>
<RowDefinition x:Name="GridRowDef_Locatie" MinHeight="120" Height="120*" MaxHeight="120"/>
<RowDefinition x:Name="GridRowDef_AantalDagen" MinHeight="105" Height="105*" MaxHeight="105"/>
<RowDefinition x:Name="GridRowDef_MaxDagen" MinHeight="105" Height="105*" MaxHeight="105"/>
<RowDefinition x:Name="GridRowDef_Lokaal" MinHeight="100" Height="100*" MaxHeight="100"/>
<RowDefinition x:Name="GridRowDef_LicBestand" Height="150*" MaxHeight="150" MinHeight="150"/>
</Grid.RowDefinitions>
<GroupBox x:Name="GroupBox_algemeen" Header="Algemeen" Margin="10,4,10,3">
<Grid>
<Label x:Name="Label_Klant" Content="Klant:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Padding="0,5,5,5"/>
<Label x:Name="Label_Programma" Content="Programma:" HorizontalAlignment="Left" Margin="356,10,0,0" VerticalAlignment="Top"/>
<Label x:Name="Label_Versie" Content="Versie:" HorizontalAlignment="Left" Margin="645,10,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="textBox_KlantNaam" HorizontalAlignment="Left" Height="23" Margin="49,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="288"/>
<!-- the textbox keeps empty -->
<TextBox x:Name="TextBox_ProgrammaNaam" Text="{Binding ElementName=RegistratieViewModel, Path=ProgrammaNaam, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Height="23" Margin="431,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="190" IsEnabled="False" />
<TextBox x:Name="TextBox_Versie" HorizontalAlignment="Left" Height="23" Margin="695,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsEnabled="False" />
</Grid>
</GroupBox>
</Grid>
</Border>
</Grid>
</TabItem>
<TabItem Header="Licentie(s)">
<Grid x:Name="Grid_Tab_Licentie" Background="#FFE5E5E5"/>
</TabItem>
</TabControl>
</Grid>
</Grid>
</UserControl>
In the View.cs:
namespace Qbox_0001.Views
{
/// <summary>
/// Interaction logic for RegistratieView.xaml
/// </summary>
public partial class RegistratieView : UserControl
{
public RegistratieView()
{
InitializeComponent();
this.DataContext = new Qbox_0001.ViewModel.RegistratieViewModel();
}
}
}
The ViewModel
using Qbox_0001.Model; //
using System.Collections.ObjectModel; //
namespace Qbox_0001.ViewModel
{
public class RegistratieViewModel
{
public RegistratieViewModel()
{
loadRegistratieOnderdelen();
}
public ObservableCollection<Registratie> RegistratieOnderdelen //Registratie = "public class Registratie : INotifyPropertyChanged" van de Model
{
get;
set;
}
public void loadRegistratieOnderdelen()
{
ObservableCollection<Registratie> regOnderdelen = new ObservableCollection<Registratie>();
regOnderdelen.Add(new Registratie { ProgrammaNaam = "Test" });
}
}
}
I can see a couple of problems with your code.
You are populating a local ObservableCollection (inside your loadRegistratieOnderdelen() method) with data but since its local, it is not a member of the DataContext and hence unavailable to the View. You have to use public properties like RegistratieOnderdelen which you already declared in your RegistratieViewModel.
Next you are using an ObservableCollection whereas you might just want to use a property of type String. Collections are used when you want to represent lists, for example inside a ListView or an ItemsControl. Your view indicates that you want to bind a single text value so a public property of type String makes more sense.
Best, Nico
The DataContext is a RegistratieViewModel. This class has a RegistratieOnderdelen property that returns a collection of Registratie objects.
You could bind to the ProgrammaNaam property of one such item but you need to specify which item to bind to, for example the first one:
<TextBox x:Name="TextBox_ProgrammaNaam" Text="{Binding Path=RegistratieOnderdelen[0].ProgrammaNaam, UpdateSourceTrigger=PropertyChanged}" ... />

How to add controls inside WPF TabControl via XAML

I have the following XAML, a TabControl which binds to an ObservableCollection and creates my tabs just fine.
<Window x:Class="BA_Auditing.AuditWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="BizeAsset - Audit Results" Height="700" Width="1120" WindowStartupLocation="CenterScreen" WindowState="Maximized">
<Grid>
<TabControl Name="ModuleTabControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" ItemsSource="{Binding}" >
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding DISPLAY_NAME}"/>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Search:" HorizontalAlignment="Right"/>
<TextBox x:Name="tbxSearch" Grid.Column="1"/>
</Grid>
<TextBlock Grid.Row="2" Text="Items Selected: 0 of 908" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
Next I'd like to populate each tab area with the next level of controls, which will include a Label, TextBox another TabControl and a TextBlock.
I previously wrote this in WinForms and this is what it looks like:
What XAML do I need add to do this?
That is because I am designing it dynamically via binding rather than literally adding a TabItem
[EDIT]
I have tried to enter controls into the TabControl.ContentTemplate however nothing displays in the body of the TabItem.
I think if you had "clicked" on the "WW - Wastewater" tab you would have seen something being generated (the Search box, etc) - that's because the tab wasn't selected by default.
Anyway, here is a bit of code which gets you a bit closer to what you want - it's just to get you started, you'll need to add the other plumbing code (change notification, etc).
I don't know what you intend to have in the "Services" tab, etc...so don't know if you can handle them all in the same way i.e. as "Assets". Also you might want to explicitly define the names of the grid columns rather than have them auto-generated - there are some techniques elsewhere you can find to do that.
<Window x:Class="WpfApp38.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp38"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl Name="ModuleTabControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5" ItemsSource="{Binding}" SelectedIndex="0" >
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock Text="{Binding DISPLAY_NAME}"/>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Search:" HorizontalAlignment="Right"/>
<TextBox x:Name="tbxSearch" Grid.Column="1"/>
</Grid>
<TabControl Grid.Row="1" ItemsSource="{Binding SubCategories}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DISPLAY_NAME}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<ItemContainerTemplate>
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Assets}">
</DataGrid>
</ItemContainerTemplate>
</TabControl.ContentTemplate>
</TabControl>
<TextBlock Grid.Row="2" Text="Items Selected: 0 of 908" />
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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 WpfApp38
{
public class InfrastructureCateogry
{
public string DISPLAY_NAME { get; set; }
public ObservableCollection<AssetCategory> SubCategories { get; set; }
}
public class AssetCategory
{
public string DISPLAY_NAME { get; set; }
public ObservableCollection<AssetRecord> Assets { get; set; }
}
public class AssetRecord
{
public string AssetID { get; set; } // make it an int
public string AssetType { get; set; }
public string LastUpdateBy { get; set; } // make this a DateTime object
public string LastUpdateDate { get; set; } // make this a DateTime object
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<InfrastructureCateogry> infrastructurecategories = new ObservableCollection<InfrastructureCateogry>();
public MainWindow()
{
InitializeComponent();
var x = new InfrastructureCateogry()
{
DISPLAY_NAME = "AR - Roads and Bridges",
SubCategories = new ObservableCollection<AssetCategory>
{
new AssetCategory
{
DISPLAY_NAME = "Lines",
Assets = new ObservableCollection<AssetRecord>
{
new AssetRecord
{
AssetID = "20040927104600",
AssetType = "Gravity Main",
LastUpdateDate = "07/05/2015 17:01:55 PM"
},
new AssetRecord
{
AssetID = "20150507170116",
AssetType = "Relined",
LastUpdateDate = "07/05/2015 17:01:15 PM"
}
}
},
new AssetCategory
{
DISPLAY_NAME = "Points"
},
new AssetCategory
{
DISPLAY_NAME = "Plant/Components"
},
new AssetCategory
{
DISPLAY_NAME = "Services"
}
}
};
infrastructurecategories.Add(x);
var x2 = new InfrastructureCateogry();
x2.DISPLAY_NAME = "WW - WasteWater";
infrastructurecategories.Add(x2);
this.DataContext = infrastructurecategories;
}
}
}

WPF: Can only bind to List if DataContext set directly

I'm learning WPF. Thanks in advance for the help.
I have an object, Directory, that acts as a container for a List of Person objects. I can't figure out why I can't bind my ListBox to the list of Person unless I set the DataContext directly. In other words, I can't use dot notation to access the list as a sub-property of the directory.
Observe the the last line of the C# sharp code below: I set the DataContext to this.directory.People and it works great.
But if I set the DataContext simply to this (to refer to the whole Window) and then try to use dot notation to set my binding like <ListBox ItemsSource="{Binding Path=directory.People}" /> my ListBox is blank.
XAML listed below. Observe the last line of the XAML.
CodeBehind:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
public class Directory
{
public List<Person> People = new List<Person>();
public Directory()
{
this.People.Add(new Person() { Name = "Joseph", Age = 34 });
this.People.Add(new Person() { Name = "Teresa", Age = 29});
this.People.Add(new Person() { Name = "Kulwant", Age = 66 });
this.People.Add(new Person() { Name = "Hyunh", Age = 61});
this.People.Add(new Person() { Name = "Marcio", Age = 65 });
}
}
public partial class MainWindow : Window
{
public Directory directory { get; } = new Directory();
public MainWindow()
{
InitializeComponent();
this.DataContext = this.directory.People;
}
}
XAML:
<Window x:Class="WtfDataTrigger.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:t="clr-namespace:System.Threading;assembly=mscorlib"
xmlns:local="clr-namespace:LearningWPF"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Person}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Name="NameLabel" Margin="2" Content="Name" Grid.Column="0" Grid.Row="0" VerticalAlignment="Center" FontWeight="Bold"/>
<TextBlock Name="NameText" Margin="2" Text="{Binding Path=Name}" Grid.Column="1" Grid.Row="0" VerticalAlignment="Center" />
<Label Name="AgeLabel" Margin="2" Content="Age" Grid.Column="0" Grid.Row="1" VerticalAlignment="Center" FontWeight="Bold" />
<TextBlock Name="AgeText" Margin="2" Text="{Binding Path=Age}" Grid.Column="1" Grid.Row="1" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox ItemsSource="{Binding}" />
</StackPanel>
</Window>
WPF data binding works with public properties only. While directory is a public property (but should be named Directory), People is a public field.
Change
public List<Person> People = new List<Person>();
to
public List<Person> People { get; } = new List<Person>();

Trouble with DataBinding to a ListBox in WP7 which is not displaying the bound content

I have a DataBinding on a ListBox, bound to an ObservableCollection. Debugging at runtime shows the ObservableCollection does have items in it, and they're not null. My code all looks fine, however for some reason nothing is being displayed in my ListBox. It definitely was working previously, however it no longer is - and I can't figure out why. I've examined previous versions of the code and found no differences that would have any effect on this - minor things like Width="Auto" etc.
I based my code off of the example found here:
http://msdn.microsoft.com/en-us/library/hh202876.aspx
So, my code:
XAML:
<phone:PhoneApplicationPage
x:Class="MyNamespace.MyItemsListPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
shell:SystemTray.IsVisible="True">
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" x:Name="PageTitle" Text="MyPageTitle" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<!-- Bind the list box to the observable collection. -->
<ListBox x:Name="myItemsListBox" ItemsSource="{Binding MyItemsList}" Margin="12, 0, 12, 0" Width="440">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch" Width="440">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Text="{Binding MyItemNumber}"
FontSize="{StaticResource PhoneFontSizeLarge}"
Grid.Column="0"
VerticalAlignment="Center"
Margin="0,10"
Tap="TextBlock_Tap"/>
<TextBlock
Text="{Binding MyItemName}"
FontSize="{StaticResource PhoneFontSizeLarge}"
Grid.Column="1"
VerticalAlignment="Center"
Margin="0,10"
Tap="TextBlock_Tap" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Grid>
</phone:PhoneApplicationPage>
C#:
namespace MyNamespace
{
public partial class MyItemsListPage : PhoneApplicationPage, INotifyPropertyChanged
{
private static ObservableCollection<MyItem> _myItemsList;
private ObservableCollection<MyItem> MyItemsList
{
get
{
return _myItemsList;
}
set
{
if (_myItemsList!= value)
{
_myItemsList= value;
NotifyPropertyChanged("MyItemsList");
}
}
}
public MyItemsListPage ()
{
InitializeComponent();
this.DataContext = this;
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
HelperClass helper = new HelperClass();
MyItemsList = helper.GetItems(this.NavigationContext.QueryString["query"]);
base.OnNavigatedTo(e); // Breakpoint here shows "MyItemsList" has MyItem objects in it.
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
// Used to notify Silverlight that a property has changed.
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
The Helper class is a connector to my read-only local database on the device. It returns an ObservableCollection<MyItem>:
public ObservableCollection<MyItem> GetItems(string itemName)
{
// Input validation etc.
// Selecting all items for testing
var itemsInDB =
from MyItem item in db.Items
select item;
return new ObservableCollection<MyItem>(itemsInDB);
}
And finally the MyItem class:
[Table]
public class MyItem: INotifyPropertyChanged, INotifyPropertyChanging
{
private int _myItemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int MyItemId
{
...
}
private string _myItemName;
[Column(CanBeNull = false)]
public string MyItemName
{
get
{
return _myItemName;
}
set
{
if (_myItemName!= value)
{
NotifyPropertyChanging("MyItemName");
_myItemName= value;
NotifyPropertyChanged("MyItemName");
}
}
}
private int _myItemNumber;
[Column]
public int MyItemNumber
{
get
{
return _myItemNumber;
}
set
{
if (_myItemNumber!= value)
{
NotifyPropertyChanging("MyItemNumber");
_myItemNumber= value;
NotifyPropertyChanged("MyItemNumber");
}
}
}
// Other properties, NotifyPropertyChanged method, etc...
}
This is rather frustrating as my DataBinding elsewhere in the application is working perfectly, so I've no idea why I can't get this to work.
The problem was that my ObservableCollection was private. Changing it to have a public access modifier allowed my ListBox to display the contents:
public ObservableCollection<MyItem> MyItemsList
Simply that you're binding to properties named incorrectly:
Text="{Binding ItemName}" should be Text="{Binding MyItemName}"
Notice you left out "My"

How to filter/find string associated with items from the collection and place that matched string into texblock in Silverlight?

I am wondering if someone can share with information or good sample with filtering listboxitems based on what is typed in the textbox. Perhaps, it can be a different control that fits better to the scenario below.
In my scenario, I need to type a short string in texblock. Then, click ‘check’ button which will find the closest string values of items from the collection and show these matches in a form of the list below the textblock. Selecting any of items from shown list of items will place the selected string/item in the tetxblock. The behavior is very similar to combox box.
Finally, I need to be able to add that selected string/item that was placed in the texblock to another listbox by clicking ‘Add’ button. Any ideas are highly appreciated. Thank you in advance!
Below is my XAML code:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Class="FilterListItems.MainPage"
xmlns:local="clr-namespace:FilterListItems"
Width="640" Height="480">
<UserControl.Resources>
<local:Products x:Key="productCollection" />
<CollectionViewSource x:Key="collProducts" Source="{Binding Source={StaticResource productCollection}, Path=DataCollection}">
</CollectionViewSource>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="10" Grid.Row="0">
<TextBlock Text="Enter Partial Name: " />
<TextBox Width="100" Name="txtName" />
<Button Name="btnSearch" Content="Check" Click="btn_Check" />
<Button Name="btnAdd" Content="Add" Click="btn_Add" Margin="9,0,0,0" />
</StackPanel>
<ListBox Margin="10" Grid.Row="1" Name="lstData" DisplayMemberPath="ProductName" ItemsSource="{Binding Source={StaticResource collProducts}}" Visibility="Collapsed" />
<ListBox Margin="10" Grid.Row="2" Name="2stData" />
C# to generate the collection:
public partial class MainPage : UserControl
{
public MainPage()
{
// Required to initialize variables
InitializeComponent();
}
private void btnSearch_Click(object sender, RoutedEventArgs e)
{
//FilterData();
}
}
public class Product
{
public Product(int id, string name)
{
ProductId = id;
ProductName = name;
}
public int ProductId { get; set; }
public string ProductName { get; set; }
}
public class Products : List<Product>
{
public Products()
{
InitCollection();
}
public List<Product> DataCollection { get; set; }
List<Product> InitCollection()
{
DataCollection = new List<Product>();
DataCollection.Add(new Product(1, "aaa"));
DataCollection.Add(new Product(2, "bbb"));
DataCollection.Add(new Product(3, "ccc"));
DataCollection.Add(new Product(4, "ddd"));
DataCollection.Add(new Product(5, "eee"));
DataCollection.Add(new Product(6, "fff"));
DataCollection.Add(new Product(7, "hhh"));
DataCollection.Add(new Product(8, "ggg"));
return DataCollection;
}
}
Check out the AutoCompleteBox from wpftoolkit
also check
http://www.jeff.wilcox.name/2010/02/wpfautocompletebox/
Bea Stollnitz is a great resource for finding out how to filter collections. You should start with her post on "How do I filter items from a collection?" to get a simple and clear picture. When you are done with that article just use the search on her blog to search for "filter"ing collections using collectionviewsource.

Resources