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

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.

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;

How to Terminate an Application Properly and Save Data

I have recently come across the App.Current.Terminate method, which I would like to use in an application. Before calling this, however, I need to save some data. For some reason, even though the save seems to be shown as effective, once the application is terminated the old settings are restored. I cannot figure out what is going on. I have a ListPicker, and I am trying to change the theme setting in my application between light and dark, using Jeff Wilcox's ThemeManager.
SettingsPage.xaml
<Grid.Resources>
<DataTemplate x:Name="PickerItemTemplate">
<StackPanel Tap="stk_Tap">
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
...
<toolkit:ListPicker x:Name="ThemeListPicker" Header="Theme"
ItemTemplate="{StaticResource PickerItemTemplate}"/>
SettingsPage.xaml.cs
List<Theme> themeList;
private int currentThemeIndex;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
themeList = new List<Theme>();
themeList.Add(new Theme() { Name = "light", name = "light" }); //Name subject to change
themeList.Add(new Theme() { Name = "dark", name = "dark" }); //Name subject to change
ThemeListPicker.ItemsSource = themeList;
//make sure ThemeListPicker shows current theme when NavigatedTo
if (Settings.LightTheme.Value)
{
ThemeListPicker.SelectedIndex = 0;
currentThemeIndex = 0;
}
else
{
ThemeListPicker.SelectedIndex = 1;
currentThemeIndex = 1;
}
}
private void stk_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if (ThemeListPicker.SelectedIndex != -1)
{
//avoid asking the question if the selected item is the same as the current item
//doesn't quite work properly? Skips when the item is changed for the first time
if(ThemeListPicker.SelectedIndex != currentThemeIndex)
{
MessageBoxResult result = MessageBox.Show("The app must be restarted to apply theme changes."", "", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
var selectedItem = (Theme)(sender as StackPanel).DataContext;
switch (selectedItem.name)
{
case "light":
Settings.LightTheme.Value = true;
currentThemeIndex = 0;
break;
case "dark":
Settings.LightTheme.Value = false;
currentThemeIndex = 1;
break;
default:
Settings.LightTheme.Value = true;
currentThemeIndex = 0;
break;
}
Terminate();
}
}
}
private void Terminate()
{
App.Current.Terminate();
}
Theme.cs
public class Theme
{
public string Name
{
get;
set;
}
public string name //name to use in determining current theme
{
get;
set;
}
}
Settings.cs //writes key/value pair to IsoStore
//Theme - set to true by default
public static readonly Setting<bool> LightTheme = new Setting<bool>("LightTheme", true);
App.xaml.cs
public App()
{
...
//Theme Manager
if (Settings.LightTheme.Value)
ThemeManager.ToLightTheme();
else
ThemeManager.ToDarkTheme();
...
}
The main problem is that the theme never changes. I set a breakpoint in App.xaml.cs to check the current value of Settings.LightTheme.Value on application load, which always stays as true which sets the app to the light theme. In SettingsPage.xaml.cs when a user selects either the light or dark option in the ListPicker, I detect that the value of Settings.LightTheme.Value switches between true and false. Immediately after, since the user must select OK on the MessageBox to restart the application, the app is terminated. Upon restarting, Settings.LightTheme.Value is true. I am not sure how to fix this?
Call IsolatedStorageSettings.Save() before Terminate.
In App.xaml.cs the following method can be found. Simply add your 'theme saving' code to this method.
// Code to execute when the application is closing (eg, user hit Back)
// This code will not execute when the application is deactivated
private void Application_Closing(object sender, ClosingEventArgs e)
{
//theme saving code goes here
}

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.

data binding TextBox TextChanged is not working

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}" />

Categories

Resources