On selection of item in AutoSuggestBox instead of the property value it binds to the property.
This is my xaml.
<AutoSuggestBox x:Name="txtSearchBox" ItemsSource="{Binding}"
PlaceholderText="Search in Distributor" Style="{StaticResource AutoSuggestBoxStyle1}"
Margin="10,25,10,0" DisplayMemberPath="{Binding entityName}" TextMemberPath="{Binding entityName}"
BorderBrush="#000000" BorderThickness="2" TextChanged="txtSearchBox_TextChanged"
SuggestionChosen="txtSearchBox_SuggestionChosen">
<AutoSuggestBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding entityName}"
Tag="{Binding entityId}"/>
</DataTemplate>
</AutoSuggestBox.ItemTemplate>
</AutoSuggestBox>
This is the Code Behind
private void txtSearchBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
List<Master_User_Hierarchy_VM> lstUserHierarchy = new List<Master_User_Hierarchy_VM>();
txtSearchBox.ItemsSource = null;
foreach (Master_User_Hierarchy_VM obj in lstMaster_UserHierarchy_VM)
{
if (sender.Text != "")
{
if (obj.entityName.Contains(sender.Text))
{
lstUserHierarchy.Add(obj);
}
}
}
txtSearchBox.ItemsSource = lstUserHierarchy;
}
else if (args.Reason == AutoSuggestionBoxTextChangeReason.SuggestionChosen)
{
//txtSearchBox.Text = txtSearchBox.Items[0].ToString();
}
}
private void txtSearchBox_SuggestionChosen(AutoSuggestBox sender, AutoSuggestBoxSuggestionChosenEventArgs args)
{
txtSearchBox.Text = ((Master_User_Hierarchy_VM)args.SelectedItem).entityName;
}
This is when I enter a character
When I click an Item in this list
Again I get the selected Item in the suggestions box. When I click it I get the property Name instead of the value
Use
TextMemberPath="entityName"
instead of
TextMemberPath="{Binding entityName}"
The solution is that I used UpdateTextOnSelect="False" & did explicit binding in Code behind.
I did resolve this by following the UWP/Xaml Samples. Here is my implementation.
Model:
public class Partner : EntityBase
{ //Name
public string Name { get; set; }
//Address
public string Street { get; set; }
...
//It is important to return the formated string
public string DisplayName { get { return string.Format("{0}", Name); } }
}
XAML:
SuggestionChosen event is not needed to implement.
<AutoSuggestBox PlaceholderText="Search"
DisplayMemberPath="DisplayName"
TextMemberPath="DisplayName"
QueryIcon="Find"
Width="200"
TextChanged="{x:Bind ViewModel.SupplierAutoSuggest_TextChanged}"
>
<!--If you are using a DataTemplate you need to delete the DisplayMemberPath property, if not you will get an unhandled exception-->
<!--AutoSuggestBox.ItemTemplate>
<DataTemplate x:DataType="models:Partner">
<TextBlock
Text="{Binding Name, Mode=OneWay}"/>
</DataTemplate>
</!-->
</AutoSuggestBox>
TextChanged Event Method (Implemented in the corresponding viewModel Class):
public async void SupplierAutoSuggest_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args)
{
var queryText = sender.Text;
if(args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
{
if(!string.IsNullOrEmpty(queryText))
{
//IEnumerable Returned
var suggestion = await App.Repository.Partners.GetAsync(queryText);
if (suggestion.Any())
sender.ItemsSource = suggestion;
}
}
}
Notice that you can use x:bind for MVVM pattern porpouse
Set DisplayMemberPath to `DisplayMemberPath="entityName", no Binding needed.
Related
is it possible to get text value of a label?
example
for example i tapped the "Dessert" i want to get the specific cat_code value and pass it to a variable which i will use later on
My Codes
Category.cs
public class Catergory
{
public string cat_code { get; set; }
}
MenuCategories.xaml
<ListView x:Name="MyCategory" ItemSelected="MyCategory_ItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label x:Name="categoryname" Text="{Binding cat_code}"
Style="{DynamicResource ListItemTextStyle}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What event should i use here? itemtapped or selecteditem?
and how can i get the value of the cat_code or the text of the label? using those event?
MenuCategories.xaml.cs
public MenuCategories()
{
InitializeComponent();
GetCategoryAsync();
}
public async Task GetCategoryAsync()
{
HttpClient client = new HttpClient();
var response = await client.GetStringAsync("http://ropenrom24-001-site1.etempurl.com/potangina/final/Restserver/index.php/category/view");
var cat = JsonConvert.DeserializeObject<List<Catergory>>(response);
MyCategory.ItemsSource = cat;
}
private void MyCategory_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
//what to code? to get value of the selecteditem
}
The e.SelectedItem holds the item that was selected, so the code can simply be:
private string selectedItem;
private void MyCategory_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var selectedCategory = e.SelectedItem as Catergory;
if (selectedCategory != null)
selectedItem = selectedCategory.cat_code;
}
I am new-bee at WPF, i am trying to populate my combox control which is there within my listbox
XAML :
<Window.Resources>
<DataTemplate x:Key="UserTemplate" >
<StackPanel Orientation="Horizontal" >
<ComboBox Name="rule" ItemsSource="{Binding}" DisplayMemberPath="DataContext.RuleType" Width="85" Height="20"
SelectedValuePath="DataContext.RuleType" SelectedValue="{Binding Path=DataContext.RuleType}"/>
<TextBlock Text="{Binding Path= Name1}" Width="85" Margin="5,5,5,5"></TextBlock>
<Button Content="Delete" Click="cmdDeleteUser_Clicked" Margin="5,5,5,5" />
<Button Content="Add" Click="cmdAddUser_Clicked" Margin="5,5,5,5" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox Name="lbUsers" ItemsSource="{Binding }" ItemTemplate="{StaticResource UserTemplate}"/>
</Grid>
CODE BEHIND:
public ObservableCollection<User> Users;
ObservableCollection<Listdata> listeddata;
ObservableCollection<Records> Record;
public MainWindow()
{
InitializeComponent();
Users = new ObservableCollection<User>() {
new User() { Name = "", Age = "" },
};
DataboundListbox.Records record = new Records();
RuleType = record.record_Rule();
lbUsers.DataContext = Users;
}
private string _Name;
public string Name1
{
get { return _Name; }
set
{
if (value != _Name)
{
_Name = "John";
NotifyPropertyChanged("Name");
}
}
}
private List<string> _RuleType;
public List<string> RuleType
{
get { return _RuleType; }
set
{
if (value != _RuleType)
{
_RuleType = value;
NotifyPropertyChanged("RuleType");
}
}
}
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private void cmdDeleteUser_Clicked(object sender, RoutedEventArgs e)
{
Button cmd = (Button)sender;
if (cmd.DataContext is User)
{
User deleteme = (User)cmd.DataContext;
Users.Remove(deleteme);
}
}
private void cmdAddUser_Clicked(object sender, RoutedEventArgs e)
{
Button cmd = (Button)sender;
if (cmd.DataContext is User)
{
var addedUser = new User() { Name = "", Age = "" };
Users.Add(addedUser);
}
}
private List<string> _prp;
public List<string> prp
{
get { return _prp; }
set
{
if (value != _prp)
{
_RuleType = value;
NotifyPropertyChanged("prp");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
Before I can answer your question there are some confusions that should be cleared up.
If User has already a member named Name then what's Name1 in parent class for?
If RuleType is a list, how come it's set as the SelectedValue of your ComboBox, Shouldn't it be ComboBox.itemsSource instead? If it should, then where is the property defined to keep the ComboBox.SelectedValue?
How come there is an Add button inside the UserTemplate? Delete button is ok but i think Add belongs outside of the ListBox.
If i understand your issue correctly, then this is the solution I can think of.
Fisrt: User needs a property like SelectedRule to keep Combobox.SelectedItem:
public class User : INotifyPropertyChanged
{
// implementation of INotifyPropertyChanged
string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
int _age;
public int Age
{
get
{
return _age;
}
set
{
_age = value;
NotifyPropertyChanged("Age");
}
}
string _selectedRule;
public string SelectedRule
{
get
{
return _selectedRule;
}
set
{
_selectedRule = value;
NotifyPropertyChanged("SelectedRule");
}
}
}
Second: Your DataTemplate should change like this:
<Window.Resources>
<DataTemplate x:Key="UserTemplate" >
<StackPanel Orientation="Horizontal" >
<ComboBox Name="rule" ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=RuleType}" DisplayMemberPath="." Width="85" Height="20"
SelectedItem="{Binding SelectedRule}"/>
<TextBlock Text="{Binding Path= Name}" Width="85" Margin="5,5,5,5"></TextBlock>
<Button Content="Delete" Click="cmdDeleteUser_Clicked" Margin="5,5,5,5" />
</StackPanel>
</DataTemplate>
</Window.Resources>
Finally the ListBox part changes as below:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0" Name="lbUsers" ItemsSource="{Binding}" ItemTemplate="{StaticResource UserTemplate}"/>
<Button Grid.Row="1" Content="Add" Click="cmdAddUser_Clicked" Margin="5,5,5,5" />
</Grid>
If you're gonna bring Add button out like the above code, then you should remove if (cmd.DataContext is User) from cmdAddUser_Clicked method.
Problem :
The main problem is on this two line:
{Binding Path=DataContext.RuleType}
{Binding Path= Name1}
Since you already declare your dataContext, DataContext.RuleType will causes the compiler to search for yourdatacontext.DataContext.RuleType which is obviously not the thing you want.
lbUsers.DataContext = Users;
Your data context is a collection of User class and does not contain Name1. Thus Binding Path=Name1 will return "property not found" error
Solution
In WPF, MVVM ( model view viewmodel) pattern is highly encouraged. One of its main feature is it seperate GUI logic from Business Logic, making the code cleaner and easier to maintain.
Step 1: Create a ViewModel
public class UserViewModel:INotifyPropertyChanged
{
private string name;
private string age;
private string rule;
private List<string> ruleType;
public String Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); }
}
public String Age
{
get { return age; }
set { age = value; NotifyPropertyChanged("Age"); }
}
public String Rule
{
get { return rule; }
set { rule = value; NotifyPropertyChanged("Rule"); }
}
public List<string> RuleType
{
get { return ruleType; }
set { ruleType = value; NotifyPropertyChanged("RuleType"); }
}
public UserViewModel()
{
name = "name";
age = "";
ruleType = new List<string>();
}
#region NotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
}
Step 2 : Link your data context to the viewmodel
public MainWindow()
{
InitializeComponent();
Users = new ObservableCollection<UserViewModel>();
//setup your data here
//example:
UserViewModel userViewModel = new UserViewModel();
//populate your combobox here
userViewModel.RuleType.Add("rule1")
userViewModel.RuleType.Add("rule2");
userViewModel.RuleType.Add("rule3");
Users.Add(new UserViewModel());
lbUsers.DataContext = Users ;
}
Step 3 : Update your xaml
<Window.Resources>
<DataTemplate x:Key="UserTemplate" >
<StackPanel Orientation="Horizontal" >
<ComboBox Name="rule" ItemsSource="{Binding RuleType}" Width="85" Height="20"
SelectedValue="{Binding Rule}"/>
<TextBlock Text="{Binding Path= Name}" Width="85" Margin="5,5,5,5"></TextBlock>
<Button Content="Delete" Click="cmdDeleteUser_Clicked" Margin="5,5,5,5" />
<Button Content="Add" Click="cmdAddUser_Clicked" Margin="5,5,5,5" />
</StackPanel>
</DataTemplate>
</Window.Resources>
When i am typing, bahman already post a quite detailed answer.So i stopped here. If you require any explaination or solution from me just asked will do.
In future if you suspect any error regarding binding, you can search your output window.
If you see your output window you possibly will found this
System.Windows.Data Error: 40 : BindingExpression path error: 'DataContext' property not found on 'object' ''User' (HashCode=9080996)'. BindingExpression:Path=DataContext.RuleType; DataItem='User' (HashCode=9080996); target element is 'ComboBox' (Name=''); target property is 'SelectedValue' (type 'Object')
System.Windows.Data Error: 40 : BindingExpression path error: 'Name1' property not found on 'object' ''User' (HashCode=9080996)'. BindingExpression:Path=Name1; DataItem='User' (HashCode=9080996); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
I created a new TextBlock class which has ItemsSource property and translates that ItemsSource into "Run" object:
public class MultiTypeDynamicTextBlock : TextBlock
{
public interface ISection
{
Inline GetDisplayElement();
}
public class TextOption : ISection
{
private Run mText;
public TextOption(string aText)
{
mText = new Run();
mText.Text = aText.Replace("\\n", "\n");
}
public Inline GetDisplayElement()
{
return mText;
}
}
public class LineBreakOption : ISection
{
public Inline GetDisplayElement()
{
return new LineBreak();
}
public ISection Clone()
{
return new LineBreakOption();
}
}
public class ImageOption : ISection
{
private InlineUIContainer mContainer;
public ImageOption(string aDisplay)
{
Image lImage;
lImage = new Image();
lImage.Source = new BitmapImage(new Uri(Environment.CurrentDirectory + aDisplay));
lImage.Height = 15;
lImage.Width = 15;
mContainer = new InlineUIContainer(lImage);
}
public Inline GetDisplayElement()
{
return mContainer;
}
}
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(ObservableCollection<ISection>), typeof(MultiTypeDynamicTextBlock),
new UIPropertyMetadata(new ObservableCollection<ISection>(),
new PropertyChangedCallback(SetContent)));
public ObservableCollection<ISection> ItemsSource
{
get
{
return GetValue(ItemsSourceProperty) as ObservableCollection<ISection>;
}
set
{
if (ItemsSource != null)
ItemsSource.CollectionChanged -= CollectionChanged;
SetValue(ItemsSourceProperty, value);
SetContent();
ItemsSource.CollectionChanged += CollectionChanged;
}
}
private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
SetContent();
}
private static void SetContent(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DependencyObject lParent = d;
MultiTypeDynamicTextBlock lPanel = lParent as MultiTypeDynamicTextBlock;
if (lPanel != null)
{
lPanel.ItemsSource = e.NewValue as ObservableCollection<ISection>;
}
}
private void SetContent()
{
if (ItemsSource != null)
{
Inlines.Clear();
foreach (ISection lCurr in ItemsSource)
{
Inlines.Add(lCurr.GetDisplayElement());
}
}
}
If I Bind the ItemsSource directly to the DataContext, it works.
But if I bind it to an object that changes at runtime (such as SelectedItem on a ListBox) it doesn't update the text when a new item is selected.
<StackPanel>
<ListBox x:Name="TheList" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel DataContext="{Binding ElementName=TheList, Path=SelectedItem}">
<TextBlock Text="{Binding Title}" FontSize="20"/>
<local:MultiTypeDynamicTextBlock ItemsSource="{Binding Items}"/>
</StackPanel>
</StackPanel>
Any reason why?
In your example, does the SelectedItem has two properties Title and Items? Or is Items a property in your viewmodel? If the answer is the latter, than you can find a solution below.
I don't entirely understand what you mean, but I'll give it a try.
If you mean that the ItemsSource on your custom control isn't set, than you have to point XAML into the right direction.
Below you can find a solution, if this is what you want to achieve.
What I did is pointing the compiler to the right source with this line of code:
ItemsSource="{Binding DataContext.Items, RelativeSource={RelativeSource AncestorType=Window}}"
Here you say that the compiler can find the Binding property in the DataContext of the Window (or any control where you can find the property).
<StackPanel>
<ListBox x:Name="TheList" ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel DataContext="{Binding ElementName=TheList, Path=SelectedItem}">
<TextBlock Text="{Binding Title}" FontSize="20"/>
<local:MultiTypeDynamicTextBlock ItemsSource="{Binding DataContext.Items, RelativeSource={RelativeSource AncestorType=Window}}"/>
</StackPanel>
</StackPanel>
Hopefully this helped.
EDIT
The title property will changes when I select another one from the ListBox.
If Items is set to a new ObservableCollection, do you call the OnPropertyChanged event for Items when the SelectedItem changes?
OnPropertyChanged("Items");
Thank you for your help.
I managed to fix this by updating the MultiTypeDynamicTextBlock as follows:
public class MultiTypeDynamicTextBlock : TextBlock
{
public interface ISection
{
Inline GetDisplayElement();
ISection Clone();
}
public class TextOption : ISection
{
private Run mText;
public TextOption(string aText)
{
mText = new Run();
mText.Text = aText.Replace("\\n", "\n");
}
public Inline GetDisplayElement()
{
return mText;
}
public ISection Clone()
{
return new TextOption(mText.Text);
}
}
public class LineBreakOption : ISection
{
public Inline GetDisplayElement()
{
return new LineBreak();
}
public ISection Clone()
{
return new LineBreakOption();
}
}
public class SectionList
{
private ObservableCollection<ISection> mList;
public Action CollectionChanged;
public ObservableCollection<ISection> Items
{
get
{
ObservableCollection<ISection> lRet = new ObservableCollection<ISection>();
foreach (ISection lCurr in mList)
{
lRet.Add(lCurr.Clone());
}
return lRet;
}
}
public int Count { get { return mList.Count; } }
public SectionList()
{
mList = new ObservableCollection<ISection>();
}
public void Add(ISection aValue)
{
mList.Add(aValue);
}
public SectionList Clone()
{
SectionList lRet = new SectionList();
lRet.mList = Items;
return lRet;
}
}
public MultiTypeDynamicTextBlock()
{
}
public static readonly DependencyProperty ItemsCollectionProperty =
DependencyProperty.Register("ItemsCollection", typeof(SectionList), typeof(MultiTypeDynamicTextBlock),
new UIPropertyMetadata((PropertyChangedCallback)((sender, args) =>
{
MultiTypeDynamicTextBlock textBlock = sender as MultiTypeDynamicTextBlock;
SectionList inlines = args.NewValue as SectionList;
if (textBlock != null)
{
if ((inlines != null) && (inlines.Count > 0))
{
textBlock.ItemsCollection.CollectionChanged += textBlock.ResetInlines;
textBlock.Inlines.Clear();
foreach (ISection lCurr in textBlock.ItemsCollection.Items)
{
textBlock.Inlines.Add(lCurr.GetDisplayElement());
}
}
else
{
inlines = new SectionList();
inlines.Add(new TextOption("No value set"));
textBlock.ItemsCollection = inlines;
}
}
})));
public SectionList ItemsCollection
{
get
{
return (SectionList)GetValue(ItemsCollectionProperty);
}
set
{
SectionList lTemp;
if (value == null)
{
lTemp = new SectionList();
lTemp.Add(new TextOption("No value set for property"));
}
else
{
lTemp = value;
}
SetValue(ItemsCollectionProperty, lTemp);
}
}
private void ResetInlines()
{
Inlines.Clear();
foreach (ISection lCurr in ItemsCollection.Items)
{
Inlines.Add(lCurr.GetDisplayElement());
}
}
}
And I update the fields that were Binded to be of type MultiTypeDynamicTextBlock.SectionList
As long as I am using a copy (Clone) it is working, for some reason when I don't clone it removes the value from the display in the list, if someone knows why I would love to learn but I managed to go around it.
the XAML of the window is:
<StackPanel>
<ListBox x:Name="TheList" ItemsSource="{Binding GeneralItems}" SelectedItem="{Binding SelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Title}" FontSize="20"/>
<local:MultiTypeDynamicTextBlock ItemsCollection="{Binding Items}" Margin="20,0,0,0"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel DataContext="{Binding GeneralItems, Path=SelectedItem}">
<TextBlock Text="{Binding Title}" FontSize="20"/>
<local:MultiTypeDynamicTextBlock DataContext="{Binding Items}" ItemsCollection="{Binding}" Margin="20,0,0,0"/>
</StackPanel>
</StackPanel>
I have a listbox with the following xaml which filled from a XMLReader
<ListBox Name="listBox4" Height="498" SelectionChanged="listBox4_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Epon}" FontSize="32"/>
<TextBlock Text="{Binding Telnum}" FontSize="24" />
<TextBlock Text="{Binding Beruf}" FontSize="16" />
<TextBlock Text="{Binding Odos}" FontSize="16"/>
<TextBlock Text="{Binding Location}" FontSize="16"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I want to call the phone when i'll select the lisbox item so I created the following class
public class PhoneList
{
public string Epon { get; set; }
public string Telnum { get; set; }
public string Beruf { get; set; }
public string Odos { get; set; }
public string Location { get; set; }
public PhoneList(string Telnum, string Epon, string Beruf, string Odos, string Location)
{
this.Telnum = Telnum;
this.Epon = Epon;
this.Beruf = Beruf;
this.Odos = Odos;
this.Location = Location;
}
}
On the event of the selection which is below
private void listBox4_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
PhoneList nPhone = (PhoneList)listBox4.SelectedItem;
string mPhoneCopy = nPhone.Telnum;
string mNameCopy = nPhone.Epon;
var pt = new PhoneCallTask();
pt.DisplayName = mNameCopy;
pt.PhoneNumber = mPhoneCopy;
pt.Show();
}
I get the error InvalidCastException in the first line of the event.
What is causing this error?
From the XAML posted, there is not a collection bound to the ListBox. This either means there is no binding, or the binding is being set in the code behind. The following are merely shots in the dark since no additional code has been posted:
Properly Bind the ListBox
Assuming a collection is part of the DataContext, the collection will need to be bound to the ListBox:
<ListBox ItemsSource="{Binding Path=MyCollection}"... />
A starting resource: MSDN: How to: Bind to a Collection and Display Information Based on Selection
Verify the Object Before Casting
This may be the case where the item selected is empty, i.e., the first item in the list has no value. In that case, check to see if the object is the type you are expecting before doing anything else:
private void listBox4_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var nPhone = listBox4.SelectedItem as PhoneList;
if (nPhone == null)
{
return;
}
string mPhoneCopy = nPhone.Telnum;
string mNameCopy = nPhone.Epon;
var pt = new PhoneCallTask();
pt.DisplayName = mNameCopy;
pt.PhoneNumber = mPhoneCopy;
pt.Show();
}
Other Thoughts
I suspect that there may not be a collection bound to the ListBox`; perhaps there is supposed to be some code-behind to set the binding that isn't being executed?
In the end, if none of the above applies to your case, edit the post with the relevant code that is creating the collection and setting the collection as the ItemsSource of the ListBox.
I'm getting an error where chkBox1 does not exist in the current context, anyone has a solution to this?
Here is the XAML:
<ListBox ItemsSource="{Binding Files}" Margin="0,42,0,115" Name="lstBox1">
<ListBox.ItemTemplate>
<DataTemplate >
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding FileName}" Name="chkBox1" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is the code that has the chkBox1 in it:
private void button2_Click(object sender, RoutedEventArgs e)
{
ViewDiskModel model = this.ContentPanel.DataContext as ViewDiskModel;
if (chkBox1.IsChecked == true)
{
model.DeleteSelectedFiles.Execute(null);
MessageBox.Show("Files Successfully Deleted.");
}
else
{
MessageBox.Show("Please select a file to delete.");
}
}
If there are many Files there will be many check boxes. How would you distinguish between these when you specify a single name?
Do not refer to the View (control) in the ViewModel. Replace the string collection (filename collection) with a collection of File. Make sure the File class has two properties: Name and IsSelected.
Then bind the content of the check box to the Name and the IsChecked Property to the IsSelected property.
That way you only have to check the IsSelected property in the ViewMODEL, not in the view.
Suggestion
class File : INotifyPropertyChanged // implementation not added
{
private string _name;
public string Name
{
get { return _name; }
set
{
if(_name != value)
{
_name = value;
OnPropertyChanged("Name");
}
}
}
private boolean _isSelected;
public boolean IsSelected
{
get { return _isSelected; }
set
{
if(_isSelected != value)
{
_isSelected = value;
OnPropertyChanged("IsSelected");
}
}
}
}
class ViewDiskModel : INotifyPropertyChanged // implementation missing
{
private ObservableCollection<File> _files;
public ObservableCollection<File> Files
{
get
{
return _files;
}
set
{
if(_files != value)
{
_files = value;
OnPropertyChanged("Files");
}
}
}
}
XAML:
<ListBox ItemsSource="{Binding Files}" Margin="0,42,0,115" Name="lstBox1">
<ListBox.ItemTemplate>
<DataTemplate >
<CheckBox IsChecked="{Binding IsSelected, Mode=TwoWay}"
Content="{Binding FileName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then:
private void Button2_Click(object sender, RoutedEventArgs e)
{
ViewDiskModel model = this.ContentPanel.DataContext as ViewDiskModel;
if(model.Files.Any(file => file.IsSelected))
{
model.DeleteSelectedFiles.Execute(null);
MessageBox.Show("Files Successfully Deleted.");
}
else
{
MessageBox.Show("Please select files to delete.");
}
}
DataTemplate controls are not available by name in code behind, because they are not members of your Window or Page (or whatever else) class. This article has a solution. Basically, subscribe to the Loaded event of the control you want, and in the code behind, save the event's sender parameter, which is the control in question.
If checkbox is inside the listbox you can not access it directly. you have to do it like that:
CheckBox chkBox1 = (CheckBox)lstBox1.Controls[index_of_the_list_item].FindControl("chkBox1");
Only then you can operate using that checkbox:
if(chkBox1.checked ){}
You have to use ID to find a control though, not it's name. And somehow you need to know what index of the list you want to check...