I am trying to add new item in to Combobox .For ex : if the ComboBox itemssource having "one","two",and "three ". I am able to type by setting IsEditable property to true . New item "Four" which is need to save in combobox . Please share regarding this .
<Window.Resources>
<local:OrderInfoRepositiory x:Key="ordercollection"/>
</Window.Resources>
<ComboBox x:Name="combo" IsEditable="True" ItemsSource="{Binding ComboItems,Source={StaticResource ordercollection}}" Height="50" Width="150"/>
code behind :
void combo_PreviewKeyDown(object sender, KeyEventArgs e)
{
var combo=(sender as ComboBox);
(combo.DataContext as OrderInfoRepositiory).ComboItems.Add(combo.Text);
}
private ObservableCollection<string> comboItems = new ObservableCollection<string>();
public ObservableCollection<string> ComboItems
{
get { return comboItems; }
set
{
comboItems = value;
RaisePropertyChanged("ComboItems");
}
}
public OrderInfoRepositiory()
{
orderCollection = new ObservableCollection<OrderInfo>();
OrderInfoCollection = GenerateOrders();
foreach (OrderInfo o in orderCollection)
{
comboItems.Add(o.Country);
}
}
PreviewKeyDown
Your ComboBox is not bound to the EventHandler comboBox_PreviewKeyDown.
Are you really want to use PreviewKeyDown?
With PreviewKeyDown comboBox.Text still has the Text before excluding your pressed key. Use KeyDown instead.
Each Keypress will add the new and the old typed letters.
Typing "Hello World" will end in H, He, Hel, Hell, etc.
Check for Key.Return to add the Item on completion or use a button. Then you can still use the PreviewKeyDown Event.
void combo_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return)
{
var combo = (sender as ComboBox);
(combo.DataContext as OrderInfoRepository).ComboItems.Add(combo.Text);
}
}
DataContext
You are casting DataContext to OrderInfoRepositiory but there is no assignment in your code.
Add to your ComboBox:
DataContext="{Binding Source={StaticResource ordercollection}}"
Then you can change your ItemsSource:
ItemsSource="{Binding ComboItems}"
I prefer setting OrderInfoRepositiory in my underlying ViewModel, then you do not need the StaticResource and just bind to the property.
<ComboBox x:Name="combo" IsEditable="True" DataContext="{Binding Source={StaticResource ordercollection}}" ItemsSource="{Binding ComboItems}" Height="50" Width="150" KeyDown="combo_PreviewKeyDown"/>
Related
I want to populate a ComboBox based on selection of other ComboBox.
Both combo boxes are populate from database using WCF.
My problem is that on first selection it's not working (just after second selection it's work and it's show results from first selection).
XAML
<ComboBox
x:Name="selClientCombo"
SelectionChanged="listEchipamente"
IsEditable="True"
SelectedIndex="-1"
HorizontalAlignment="Left"
Margin="455,35,0,0"
VerticalAlignment="Top"
Width="215"
ItemsSource="{Binding Mode=OneWay}"/>
<ComboBox
x:Name="selEchipamentCombo"
HorizontalAlignment="Left"
Margin="457,65,0,0"
VerticalAlignment="Top"
Width="213"
ItemsSource="{Binding}"/>
code
private void listEchipamente(object sender, SelectionChangedEventArgs e)
{
List<string> echipamenteWCF = client.getEchipament(selClientCombo.Text).ToList();
MessageBox.Show(" Client Selected !");
if (selEchipamentCombo.Items.Count >0)
{
selEchipamentCombo.Items.Clear();
}
for (int i = 0; i < echipamenteWCF.Count(); i++)
{
selEchipamentCombo.Items.Add(echipamenteWCF[i]);
}
}
At the time SelectionChanged is fired, the Text has not been updated (and hence it holds the previous value).
You should access the underlying data item to get the Text instead:
if(selClientCombo.SelectedItem == null) return;
List<string> echipamenteWCF =
client.getEchipament(selClientComo.SelectedItem.ToString()).ToList();
...
I supposed the ToString() will resolve the display Text. You can always cast SelectedItem to the actual type and access its string property (being shown as Text) easily. You can also access the SelectedValue with condition that some SelectedValuePath is set for the ComboBox.
I have a longlistselector like the below image. now I wanna get the text of the item user's tapped. I've searched a lot but no solution found ;(
pay attention to the image please to give a sample code
http://amiryari.persiangig.com/image/stackoverflow-question.jpg
1) Wire up the SelectionChanged event on the LongListSelector control:
<phone:LongListSelector ItemsSource="{Binding MyListItems}"
SelectionChanged="LongListSelector_SelectionChanged">
2) Retrieve the selected item from the AddedItems collection in the SelectionChangedEventArgs:
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
var item = e.AddedItems[0];
}
}
3) If your item is an object, and the text is displayed through a property, then you would have access to the text through the property on your object:
MyListItemObject item = e.AddedItems[0] as MyListItemObject;
MessageBox.Show(item.FullName);
If your list is bound to a list of strings, then it would simply be the first item in the AddedItems collection:
string fullName = e.AddedItems[0].ToString();
MessageBox.Show(fullName);
You can always listen for the SelectionChanged event and obtain the string. There is another way if you are using a DataTemplate to style your items in the list. Declare Tapped event in DataTemplate like this:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ContactImage}"/>
<TextBlock x:Name="NameTextBlock" Text="{Binding ContactName}" Tapped="NameTextBlock_Tapped"/>
</StackPanel>
</DataTemplate/>
Now in our code:
private void LongListSelector_SelectionChanged(object sender, BlahBlah e)
{
var tb = sender as Textblock;
string cName = tb.Text; //This is the string you wanted.
MessageBox.Show(cName);
}
May be I missed something, but I've already beat my head with this one.
I have defined CollectionViewSource:
<CollectionViewSource x:Key="packagesViewSource" d:DesignSource="{d:DesignInstance my:Package, CreateList=True}" />
and ListBox:
<ListBox Name="lstbPackages"
SelectionChanged="lstbPackages_SelectionChanged"
ItemsSource="{Binding Source={StaticResource packagesViewSource}}"
DisplayMemberPath="Name"
SelectedValue="{Binding Path=PackageId, UpdateSourceTrigger=Explicit}"
SelectedItem="{Binding Path=Package}"
SelectedValuePath="IdPackage"
/>
Also, I have code-behind packagesViewSource initialization:
private IQueryable<Packages> GetPackagesQuery()
{
IQueryable<Package> query = dc.PackagesList;
// Returns an ObjectQuery.
return query;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
...
packagesViewSource =((System.Windows.Data.CollectionViewSource)(this.FindResource("packagesViewSource")));
queryPackages = this.GetPackagesQuery();
packagesViewSource.Source = queryPackages.ToList();
...
}
And the line
packagesViewSource.Source = queryPackages.ToList();
involves event
private void lstbPackages_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
...
}
and as you could guess
lstbPackages.SelectedItem != null
there.
What I do wrong?
Try adding the following to your ListBox xaml.
IsSynchronizedWithCurrentItem="false"
when you assign a source to your ListBox, a DefaultView of your packagesViewSource CollectionViewSource is created. and it has first element selected. So when assigning the source, do it in 3 step:
Get DefaultView for your resource, then
MoveCurrentToPosition(-1) on this view, then
assign the View with correct current position to ListBox.
I'm trying to initiate an action based on a selection in a ComboBox I created in WPF. I'm pretty new to WPF and C#. My ComboBox has
<ComboBox x:Name="SampleComboBox" Width="100" ItemsSource="{Binding Path=NameList}" />
Where NameList is a List property in the code behind. Now I want to generate an action based on the selection in the ComboBox and not sure where to start. Thanks.
You'll need to add a method to handle the SelectionChanged event. You can either do this in code:
this.MyComboBox.SelectionChanged += new SelectionChangedEventHandler(OnSelectionChanged);
or in XAML:
<ComboBox x:Name="SampleComboBox" Width="100"
ItemsSource="{Binding Path=NameList}" SelectionChanged="OnSelectionChanged" />
where you can then do something with the selected items:
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBoxItem cbi = (ComboBoxItem) (sender as ComboBox).SelectedItem;
}
You can get the selected object by writing SampleComboBox.SelectedItem.
This will return an instance of an item in your source list.
Are these a finite set of values in this NameList that is the ItemsSource for this?
Why not amend that xaml to read:
<ComboBox x:Name="SampleComboBox" Width="100" SelectedItem="{Binding TheItem}" ItemsSource="{Binding Path=NameList}" />
and then in your ViewModel for this, have something like:
public static readonly DependencyProperty TheItemProperty=
DependencyProperty.Register("TheItem", typeof(string), typeof(OrderEditorViewModel),
new PropertyMetadata((s, e) => {
switch (e.NewValue) {
case "SomeValue":
// Do something
break;
case "SomeOtherValue":
// Do another thing
break;
default:
// Some default action
break;
}
}));
public string TheItem{
get { return (string)GetValue(TheItemProperty); }
set { SetValue(TheItemProperty, value); }
}
You can do your actions based on the selection in that switch statement which will be invoked whenever the selection is changed.
I have a list box displaying the names of help topics which can be added to and the names of the topics changed. Originally it was just displaying strings, but to get the inline editing working I changed it to use a custom type consisting of a string and an InEdit property so the UI can determine whether to display the TextBlock or TextBox:
XAML:
<ListBox ItemsSource="{Binding HelpTopics, Mode=TwoWay}"
SelectedValuePath="Description"
SelectedValue="{Binding SelectedPageId, Mode=TwoWay}"
SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Description, Mode=TwoWay}"
VerticalAlignment="Center"
MouseLeftButtonUp="TopicTextBlock_MouseLeftButtonUp"
Visibility="{Binding InEdit, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=contra}"/>
<TextBox Text="{Binding Description, Mode=TwoWay}"
Visibility="{Binding InEdit, Converter={StaticResource boolToVisibilityConverter}, ConverterParameter=pro}"
LostFocus="EditTopicTextBox_LostFocus"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Margin="5" Content="Add Topic" Command="{Binding AddTopicCommand}"/>
HelpTopics is an ObservableCollection<EditableHelpTopic>.
SelectedPageId is a string.
boolToVisibilityConverter is a converter that does what it says.
What works:
Adding a topic creates a new item and adds it to the list and put the item in to edit mode.
Double clicking on an existing item puts that item into edit mode sets the focus to the TextBox and selects all the text so it can be overwritten.
When the TextBox loses focus the edit is saved and the display returns to the TextBlock.
What doesn't work:
When a new topic is added the TextBox should have focus and the text selected so the user can enter a new name.
So my question is is there a point in the code or an event where I know that the TextBox has been created and is visible so I can set focus and select its contents. I've tried hooking into the SelectionChanged event but when that fires the TextBox hasn't yet been displayed. I also added an event to the OnAddTopicExecute method in the view model which I handled in the view, but again that fired before the TextBox was visible.
Below is the code that supports the above XAML. I've tried to cut it down, but there still seems to be a lot of it, so you can skip this if you're not interested ;)
Code behind:
private DateTime lastClickTime = DateTime.MinValue;
private Point lastClickPosition;
private void TopicTextBlock_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
UIElement element = sender as UIElement;
if ((DateTime.Now - this.lastClickTime).TotalMilliseconds > 300)
{
this.lastClickPosition = e.GetPosition(element);
this.lastClickTime = DateTime.Now;
}
else
{
Point position = e.GetPosition(element);
if (Math.Abs(this.lastClickPosition.X - position.X) < 4 && Math.Abs(this.lastClickPosition.Y - position.Y) < 4)
{
var textBlock = sender as TextBlock;
var editableHelpTopic = textBlock.DataContext as EditableHelpTopic;
editableHelpTopic.InEdit = true;
var parent = textBlock.Parent as Grid;
TextBox textBox = parent.Children.First(c => c.GetType() == typeof(TextBox)) as TextBox;
textBox.Focus();
textBox.SelectAll();
}
}
}
private void EditTopicTextBox_LostFocus(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
var editableHelpTopic = textBox.DataContext as EditableHelpTopic;
editableHelpTopic.InEdit = false;
if (!textBox.Text.Equals(editableHelpTopic.Description))
{
this.editViewModel.RenameTopic(textBox.Text);
}
}
View Model:
public EditViewModel()
{
...
this.AddTopicCommand = new DelegateCommand(this.OnAddTopicExecute, this.OnAddTopicCanExecute);
...
}
where DelegateCommand is an implemetation of ICommand.
private void OnAddTopicExecute(object parameter)
{
var newTopic = new EditableHelpTopic
{
Description = "NewTopic",
InEdit = true
};
this.HelpTopics.Add(newTopic);
this.SelectedPageId = newTopic.Description;
}
Definitions:
public class EditableHelpTopic : INotifyPropertyChanged
{
public bool InEdit { ... }
public string Description { ... }
}
It turned out to be simpler than I thought.
I just needed to add a Loaded event handler to the TextBox:
private void EditTopicTextBox_Loaded(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
var editableHelpTopic = textBox.DataContext as EditableHelpTopic;
if (editableHelpTopic.InEdit)
{
textBox.Focus();
textBox.SelectAll();
}
}