data binding TextBox TextChanged is not working - c#

I'm have two TextBoxes (XAML)
<s:SurfaceTextBox Name="CodePostal" TextChanged="CodePostalChanged" />
<s:SurfaceTextBox Name="Commune" Text="{Binding Path=CommuneGeographique}" />
And in the (.cs file)
private MyModelContainer db;
private ObservableCollection<Commune> _CommunesList = new ObservableCollection<Commune>();
private ObservableCollection<Commune> CommunesList
{
get { return _CommunesList; }
set { _CommunesList = value; }
}
In the constructor, I have this :
InitializeComponent();
getCommunes("Test");
And getCommunes(string search), is a Linq query
db = new MyModelContainer();
CommunesList.Clear();
Commune.DataContext = _CommunesList;
var myCommunes = from d in db.Communes
where d.CommunePostale.Equals(search)
select d;
foreach (Commune c in myCommunes)
{
CommunesList.Add(c);
}
Commune.DataContext = CommunesList;
At this point everything works fine and the Commune TextBox displays what I want.
My problem is that when I try to call the getCommunes() method on a TextChanged
private void CodePostalChanged(object sender, TextChangedEventArgs textChangedEventArgs)
{
getCommunes("Toto");
}
Nothing happens and the TextBox is cleared.
(It should display something else, but its empty even if the CommuneList has an element)

because you don't bind your textbox with good property, CommuneGeographique ??
<s:SurfaceTextBox Grid.Column="1" Name="Commune" Text="{Binding Path=CommuneGeographique}" />

Related

UWP ComboBox SelectedValue not being set

I obviously don't grasp using SelectedValue to change which item a combo box is showing in UWP
The XAML is simple
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ComboBox x:Name="comboBoxColor" />
</Grid>
The code-behind isn't very deep
public MainPage()
{
this.InitializeComponent();
}
public void page_Loaded(object sender, RoutedEventArgs e)
{
populateDdlMultiColor();
comboBoxColor.SelectedValue = Colors.Red;
//comboBoxColor.SelectedIndex = 0 works tho
}
private void populateDdlMultiColor()
{
comboBoxColor.ItemsSource = ColorDict();
comboBoxColor.DisplayMemberPath = "Key";
comboBoxColor.SelectedValuePath = "Value";
}
private Dictionary<string,Color> ColorDict()
{
Dictionary<string, Color> L = new Dictionary<string, Color>();
L.Add("reddish",Colors.Red);
return L;
}
This is obviously tinker-toy but it fails the same way my code fails: After setting the SelectedValue, the combo box is on index -1 and SelectedValue is null. If I set SelectedIndex to a proper value [see comment] the combo box works - it has been loaded.
Thanks for your feedback. This is a known issue that SelectedValue doesn't work with enumeration type.
For now, as a workaround, you can use SelectedIndex or SelectedItem like you've done. However, please note that Dictionary is implemented as a hash table. There's no such concept of an "index" within a Dictionary. The order is undefined and we can't rely on it. So for your scenario, using SelectedItem might be better.
For more info, you can see this answer.
Thanks to Jay Zuo for putting me on the right track! In my scenario, it's then easy enough to convert the colors to integers as a workaround to the known issue. Won't work for every enumeration, but anyone building color dropdowns [in UWP] may find this handy. Note the Dictionary change.
public MainPage()
{
this.InitializeComponent();
}
public void page_Loaded(object sender, RoutedEventArgs e)
{
populateDdlMultiColor();
comboBoxColor.SelectedValue = ColorInt(Colors.Red);
}
private void populateDdlMultiColor()
{
comboBoxColor.ItemsSource = ColorDict();
comboBoxColor.DisplayMemberPath = "Key";
comboBoxColor.SelectedValuePath = "Value";
}
private Dictionary<string,int> ColorDict()
{
Dictionary<string, int> L = new Dictionary<string, int>();
L.Add("reddish",ColorInt(Colors.Red));
return L;
}
private int ColorInt(Color c)
{
return (c.A*16777216) + (c.R*65536) + (c.G*256) + c.B ;
}

Getting the content of a checkbox within and Items Collection within a ListBox with wpf C#

I am pretty new to C#, I've been having this problem for a little while now. I have a ListBox named "listBox" which is bound to an Items Collection which has over 100 checkbox, each with a different content (or checkbox label).
I am trying to loop through each checkbox, and if it is checked, print the content into the console. I am able to detect if something is checked or not, however is definitely NOT the most efficient way of doing it. See my code below:
private void SomeButton_Click(object sender, RoutedEventArgs e)
{
string checkState = "";
for (int i = 0; i < listBox.Items.Count - 1; i++)
{
checkState = listBox.Items[i].ToString().Substring(listBox.Items[i].ToString().Length - 5, 5);
if (checkState != "False")
{
Console.WriteLine("Item " + i + " is checked");
}
}
}
This code does work for detecting if something is checked or not properly. However it'd be more efficient if I was able to get the actual true/false property from the checkboxes in the ItemsCollection. I have tried numerous ways to attempt to get the checked state, as well as the checkbox content, but sadly I am coming up dry in every attempt. Here are a few of the things I have tried to get the content from one of these checkboxes:
Console.WriteLine(listBox.Items[i].ToString());
Console.WriteLine(listBox.Items.GetItemAt(i).ToString());
Console.WriteLine(listBox.Items.GetItemAt(i).Equals(0).ToString());
Any help would be greatly appreciated.
What you ideally want is to have a class of data objects in your collection, not a collection of UI objects.
public class MyDataObject : INotifyPropertyChanged
{
public string Caption { get; set; }
public bool IsChecked { get; set; }
}
and
var items = new ObservableCollection<MyDataObject>();
// TODO: populate collection
listBox.ItemsSource = items;
Now when you bind it, listbox.Items contains your ObservableCollection<MyDataObject>, and you can just check the values from there
private void SomeButton_Click(object sender, RoutedEventArgs e)
{
foreach(MyDataObject item in listBox.Items)
{
if (item.IsChecked)
Console.WriteLine("Item " + item.Caption + " is checked");
}
}
As a side note, if you don't need selection behavior an ItemsControl might be a better fit for a series of controls than a ListBox. The XAML would probably look something like this :
<ItemsControl x:Name="myItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Caption}" Checked="{Binding IsChecked}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
var items = new ObservableCollection<MyDataObject>();
items.Add(new MyDataObject() { Caption = "A" });
items.Add(new MyDataObject() { Caption = "B" });
items.Add(new MyDataObject() { Caption = "C" });
items.Add(new MyDataObject() { Caption = "D" });
items.Add(new MyDataObject() { Caption = "E" });
myItemsControl.ItemsSource = items;

Two ListPicker, one TextBox. Result not displayed. Master-Detail?

I have two ListPickers originating from one TextBox.
private void textBox3_GotFocus(object sender, RoutedEventArgs e)
{
string a = "Domestic";
string b = Convert.ToString(textBox2.Text);
string c = "Foreign";
if (b == a)
{
NavigationService.Navigate(new Uri("/ListPickerExchanges1.xaml", UriKind.Relative));
}
else if (b == c)
{
NavigationService.Navigate(new Uri("/ListPickerExchanges2.xaml", UriKind.Relative));
}
Both ListPickers load and give you the option to choose something from the list. But only one ListPicker will displays the selection back into TextBox3 , and it is always the one under the second Else If (b == c) condition.
The ListPickerExchanges1 under the first condition will not display the selection back into textbox3.
But if i change the code under the second Else If condition to navigate to Exchanges1 instead of Exchanges2, then the Exchanges1 listpicker displays back the selection into textbox 3, and Exchanges2 does not.
Which means, Everything under the second condition works, and does not under the first condition.
Here is the code behind ListpickerExchanges1, which is intended to display the selection back into the textbox.
public partial class ListPickerExchanges1 : PhoneApplicationPage
{
public ListPickerExchanges1()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(ListPickerExchanges1_Loaded);
}
private void ListPickerExchanges1_Loaded(object sender, RoutedEventArgse)
{
ListBoxExchanges.ItemsSource = Page2.ListExchanges;
}
public void Selection(object sender, System.Windows.Input.GestureEventArgs e)
{
ListBox myselecteditem4 = (ListBox)sender;
ItemsModeling4 item4 = (ItemsModeling4)myselecteditem4.SelectedItem;
if (item4 != null)
{
NavigationService.Navigate(new Uri("/Broker.xaml?name4=" + item4.Exchanges, UriKind.RelativeOrAbsolute));
}
}
..............................................................................................................................................................
Update: Additional Code behind Navigation and Selection
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string name4 = "";
NavigationContext.QueryString.TryGetValue("name4", out name4);
textBox3.Text = string.Format("{0}", name4);
}
..............................................................................................................................................................
public Page2()
{
InitializeComponent();
ListExchanges = new ObservableCollection<ItemsModeling4>();
this.Loaded += new RoutedEventHandler(Page44_Loaded);
}
..............................................................................................................................................................
private void Page44_Loaded(object sender, RoutedEventArgs e)
{
if (ListExchanges.Count == 0)
{
string[] arrangeExchanges = new string[] { "Option1", "Option2", "Option3", "Option4" };
foreach (string item4 in arrangeExchanges)
{
ListExchanges.Add(new ItemsModeling4 { Exchanges = item4 });
}
}
}
public static ObservableCollection<ItemsModeling4> ListExchanges { get; private set; }
..............................................................................................................................................................
public class ItemsModeling4
{
public string Exchanges { get; set; }
}
..............................................................................................................................................................
Xaml
<ListBox x:Name="ListBoxExchanges" Background="Transparent"
Tap="Selection">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Height="Auto" FontFamily="Segoe WP Semibold" FontSize="50" HorizontalAlignment="Left" Margin="12,0,0,0"
Text="{Binding Exchanges}" VerticalAlignment="Top" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What am i doing wrong here?
It Seems like a Master - Detail binding issue. I just don't see where or how to fix it.
The system doesn't give any errors, and I've checked everything with the debugger and everything seems fine.
The listpickers work independently and i don't see where the code might intervene and stop the one from working. It all seems good to me.
help
But if i change the code under the second Else If condition to navigate to Exchanges1 instead of Exchanges2, then the Exchanges1 listpicker displays back the selection into textbox 3, and Exchanges2 does not.
Are you sure that you are comparing culturaly correct strings? Try this compare instead for both of them.
if (String.Equals(a, b, InvariantCultureIgnoreCase))
See StringComparison Enumeration (System) and Best Practices for Using Strings in the .NET Framework for more info.
Otherwise strings can be tricky with spaces. Try
String.Equals(a.Trim(), b.Trim());
to remove any spaces the user may be adding \r\n maybe?
Frankly since the code knows about the choices it may be better to simply provide a ComboBox with the selectable choices for the user instead of using a TextBox.

Remove the last entered character in combobox

I am here with another problem.
I have setup my comboBox such that it accepts only those characters which matches with the name of any items in the comboBoxItems.
Now here I am stuck with a problem. Please have a look at my code then I will explain you the problem :
private void myComboBox_KeyUp(object sender, KeyEventArgs e)
{
// Get the textbox part of the combobox
TextBox textBox = cbEffectOn.Template.FindName("PART_EditableTextBox", cbEffectOn) as TextBox;
// holds the list of combobox items as strings
List<String> items = new List<String>();
// indicates whether the new character added should be removed
bool shouldRemoveLastChar = true;
for (int i = 0; i < cbEffectOn.Items.Count; i++)
{
items.Add(cbEffectOn.Items.GetItemAt(i).ToString());
}
for (int i = 0; i < items.Count; i++)
{
// legal character input
if (textBox.Text != "" && items.ElementAt(i).StartsWith(textBox.Text))
{
shouldRemoveLastChar = false;
break;
}
}
// illegal character input
if (textBox.Text != "" && shouldRemoveLastChar)
{
textBox.Text = textBox.Text.Remove(textBox.Text.Length - 1);
textBox.CaretIndex = textBox.Text.Length;
}
}
In the last if condition I am removing the last character from the combobox. But user can use arrow keys or mouse to change the position of the cursor and enter the text at the middle of the text.
So if by entering a character at the middle of the text if the text becomes invalid I mean if it does not match the Items in the ComboBox then I should remove the last entered character. Can anybody suggest me how to get the last inserted character and remove it?
Update :
string OldValue = "";
private void myComboBox_KeyDown(object sender, KeyEventArgs e)
{
TextBox textBox = cbEffectOn.Template.FindName("PART_EditableTextBox", cbEffectOn) as TextBox;
List<String> items = new List<String>();
for (int i = 0; i < cbEffectOn.Items.Count; i++)
{
items.Add(cbEffectOn.Items.GetItemAt(i).ToString());
}
OldValue = textBox.Text;
bool shouldReplaceWithOldValue = true;
string NewValue = textBox.Text.Insert(textBox.CaretIndex,e.Key.ToString()).Remove(textBox.CaretIndex + 1,textBox.Text.Length - textBox.CaretIndex);
for (int i = 0; i < items.Count; i++)
{
// legal character input
if (NewValue != "" && items.ElementAt(i).StartsWith(NewValue, StringComparison.InvariantCultureIgnoreCase))
{
shouldReplaceWithOldValue = false;
break;
}
}
//// illegal character input
if (NewValue != "" && shouldReplaceWithOldValue)
{
e.Handled = true;
}
}
Here I have tried to move all the code in KeyDown event to solve the above problem. This code works just fine but have 1 problem.
If I have any item named Birds & Animals then After typing Birds and a space I cannot type &.
I know what is the problem but don't know the solution.
The Problem is : To type & I have to press shift key and then press the 7 key. But both are sent as different keys.
Solutions that I think about :
1) I should move my code to KeyUp event. But here the problem of long press and fast typing will arise.
2) I think I should replace e.Key with something. But don't know what.
I'm not sure if this is what you're trying to do but I feel like you're trying to do what we typically see in visual studio Intellisense fitlering out results as we type.
Instead of removing the keystrokes, you should be using the validation mechanisms that WPF provides. Here's a sample of how this could work.
Scenarios covered:
Input matches a combox item completely: TypedInput & SelectedItem both show full match.
Input matches some element partially: TypedInput shortlists the popup list. The binding shows the matching text while SelectedItem remains null.
Input doesn't match any item in list either from start or at some
random point: user is visually given feedback (with possibility to
add additional feedback information) with typical red outline. The
TypedInput remains at last valid entry, SelectedItem may or may
not be null depending on if the last TypedInput matched any item or not.
Full Code:
MainWindow.xaml
<Window x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:Sample"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding Source={x:Static l:MainWindowViewModel.CurrentInstance}}">
<StackPanel>
<TextBlock>
<Run Text="Typed valid text" />
<Run Text="{Binding TypedText}"/>
</TextBlock>
<TextBlock>
<Run Text="Valid SelectedItem" />
<Run Text="{Binding SelectedItem}"/>
</TextBlock>
<ComboBox ItemsSource="{Binding FilteredItems}" IsEditable="True" IsTextSearchEnabled="False" SelectedItem="{Binding SelectedItem}">
<ComboBox.Text>
<Binding Path="TypedText" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<l:ContainsValidationRule />
</Binding.ValidationRules>
</Binding>
</ComboBox.Text>
</ComboBox>
</StackPanel>
</Window>
MainWindow.xaml.cs
namespace Sample
{
public partial class MainWindow { public MainWindow() { InitializeComponent(); } }
}
ContainsValidationRule.cs -- Meat of the solution
namespace Sample
{
using System.Globalization;
using System.Linq;
using System.Windows.Controls;
public class ContainsValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var result = MainWindowViewModel.CurrentInstance.Items.Any(x => x.ToLower(cultureInfo).Contains((value as string).ToLower(cultureInfo)));
return new ValidationResult(result, "No Reason");
}
}
}
MainWindowViewModel - Supporting ViewModel Singleton
namespace Sample
{
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
public sealed class MainWindowViewModel : INotifyPropertyChanged
{
private string _typedText;
private string _selectedItem;
private static readonly MainWindowViewModel Instance = new MainWindowViewModel();
private MainWindowViewModel()
{
Items = new[] { "Apples", "Apples Green", "Bananas", "Bananas & Oranges", "Oranges", "Grapes" };
}
public static MainWindowViewModel CurrentInstance { get { return Instance; } }
public string SelectedItem
{
get { return _selectedItem; }
set
{
if (value == _selectedItem) return;
_selectedItem = value;
OnPropertyChanged();
}
}
public string TypedText
{
get { return _typedText; }
set
{
if (value == _typedText) return;
_typedText = value;
OnPropertyChanged();
OnPropertyChanged("FilteredItems");
}
}
public IEnumerable<string> Items { get; private set; }
public IEnumerable<string> FilteredItems
{
get
{
return Items == null || TypedText == null ? Items : Items.Where(x => x.ToLowerInvariant().Contains(TypedText.ToLowerInvariant()));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Instead of KeyUp event, subscribe to TextChanged event on your ComboBox Textbox. In event handler you can get the offset where the change has occured. You can use your validation logic inside the hanlder and delete the character at the offset if it makes Text invalid.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
TextBox textBox = cbEffectOn.Template.FindName("PART_EditableTextBox", cbEffectOn) as TextBox;
textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged);
}
void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
int index = e.Changes.First().Offset;
}
Have you considered using a string variable to hold the last legal text value in the text box portion of the combo box?
Initially, this string would be empty, as the user has not typed anything yet, then as each KeyUp event is handled, if an invalid character is input, then the previous string value is used to replace the text of the text box; otherwise the previous string value is now updated with the new complete string; awaiting anymore input by the user.

Listbox clears all items during datasource change

When I change the datasource of my Listbox all items are cleared, when loading new data into this Listbox it stays clear.
I have another ListBox right new to this one with the same refresh code but that one refreshes perfectly.
private void RefreshContacts()
{
this.ListContacts.DataSource = null;
this.ListContacts.DataSource = this.contacts;
this.BoxCountContacts.Text = this.ListContacts.Items.Count.ToString();
}
Anyone have an idea how to fix the listbox from being cleared and bugged?
Here is the full refresh codes of the two listboxes
private Contact[] contacts, feed; private Boolean isFeed;
internal ArcFeed()
{
this.InitializeComponent();
this.contacts = this.feed = new Contact[0];
}
private void RefreshForm(Boolean isFeed)
{
if (isFeed)
{
this.RefreshFeed();
}
else
{
this.RefreshContacts();
}
}
private void RefreshContacts()
{
this.ListContacts.DataSource = null;
this.ListContacts.DataSource = this.contacts;
this.BoxCountContacts.Text = this.ListContacts.Items.Count.ToString();
}
private void RefreshFeed()
{
this.ListFeed.DataSource = null;
this.ListFeed.DataSource = this.feed;
this.BoxCountFeed.Text = this.ListFeed.Items.Count.ToString();
}
private void OpenFile()
{
if (this.isFeed)
{
this.BoxFileFeed.Text = this.DialogOpen.FileName;
this.feed = ArcBuzz.Load(this.DialogOpen.FileName);
}
else
{
this.BoxFileContacts.Text = this.DialogOpen.FileName;
this.contacts = ArcBuzz.Load(this.DialogOpen.FileName);
}
this.RefreshForm(this.isFeed);
}
All code is debugged and follows it's course properly, I don't see any errors, the correct listbox's datasource are set and changed.
Just to make sure, have you checked that there are actually items in the contacts collection?
Also, if you've got two Listboxes, double check that you are using the right Listbox in each of the refresh code sections.
Sounds stupid, but its silly mistakes like this that get overlooked a lot of the time. With databinding its usually something small like this stopping it working.

Categories

Resources