Storing the Text Entries of a combo box - c#

I have a text box that will retain the last 10 entries entered, similar to the search box in Internet Explorer. The user can click on the dropdown menu to see last 10 entries. The drop down menu is a combo box. I created an Observable collection of strings that is bound to the combo box Itemssource.Below is the code.
Xaml
<Grid x:Name="TextBox_grid" Margin="0,0,40,0" Width="360" Height="23">
<ComboBox Name="cb" Margin="0,0,-29,0" Style="{DynamicResource Onyx_Combo}" ItemsSource="{Binding TextEntries, ElementName=TheMainWindow, Mode=OneWay}" IsEditable="False" Visibility="Visible" />
<Rectangle Fill="#FF131210" Stroke="Black" RadiusX="2" RadiusY="2"/>
<TextBox Name=UniversalTextBox Margin="0" Background="{x:Null}" BorderBrush="{x:Null}" FontSize="16" Foreground="#FFA0A0A0" TextWrapping="Wrap" PreviewKeyDown="TextBox_PreviewKeyDown"/>
</Grid>
Code
public partial class Window1 : Window
{
private ObservableCollection<string> m_TextEntries = new ObservableCollection<string>();
public Window1()
{
InitializeComponent();
}
public ObservableCollection<string> TextEntries
{
get { return m_TextEntries; }
}
private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
if (e.Key == Key.Enter)
{
PopulateHistoryList(textBox.Text);
e.Handled = true;
}
if (e.Key == Key.Escape)
{
e.Handled = true;
}
}
private void PopulateHistoryList(string text)
{
m_TextEntries.Add(text);
}
private event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
The above code will populate the TextEntries collection when the Enter Key is pressed on the textbox. I need two things
How do I set the Selected Item of the combo box and how can I bind that to my text box.
The combobox(dropmenu) should only show the last 10 entries from the drop down menu.
Thanks in advance,

Using Expesssion Blend, binding the value of a property of one control to the property value of another control is easy, and it is known as ElementProperty Binding, here is a screenshot of where you access the ability to create this within Blend, note that the Textbox is the selected element in the Objects and Timeline panel, and it's the 'little box' to the right of the Text property in the properties panel which has been clicked to produce the context menu pictured...
Once you have selected 'Element Property Binding' for the text property of your textbox, your cursor will become a little bullseye icon, which you now will use to indicate what you want to bind to, by clicking it in either the design canvas or the Objects and Timeline panel, while the cursor appears that way...
Here we see the 'SelectedValue' property of the combo box being selected as the source of what is displayed in the textbox. Once done, the textbox will automagically be immediately set to display whatever is selected in the combo. Be sure to take a look at what Blend is doing in your XAML when you do this, as it will help you better understand what is actually going on, and might even teach you a thing or two about the binding syntax of XAML.
As for the list only ever having the last ten entries...there are several ways to do this, each one more or less appropriate, depending on the surrounding context, but here is one way; simply run a procedure similar to this one, whenever the box has entries added to it:
// assuming 'listItems' is your ObservableCollection
string[] items = listItems.ToArray();
// prepare a new array for the current ten
string[] tenItems = new string[10];
// copy a subset of length ten, to the temp array, the set your ObservableCollection to this array.
Array.Copy(items, (items.Length - 10), tenItems, 0, 10);
Note: The Array .Copy assumes the only way items are getting added to the observable collection is by some form of .Add, which always adds them to the end of the list...

Part of the answer
<TextBlock Text="{Binding ElementName=cb, Path=SelectedValue}" />
<ComboBox x:Name="cb" ItemsSource="{Binding Path=Fields}" SelectedValue="{Binding Path=SelectedValue}" />
And if you set the datacontext of the window
DataContext="{Binding RelativeSource={RelativeSource self}}">

Related

Making controls transparent to mouse interaction in WPF

I am trying to make a WPF listbox replicate the behaviour of an old Winforms CheckedListBox, or the checked list box used in e.g. AnkhSVN. I have seen examples that show how to use a DataTemplate to create a check box for every time (e.g. Wpf CheckedListbox - how to get selected item), but this feels very clunky compared to the winforms control:
The logic of "If the user changes a check state, ensure that check state changes for all selected items" is not present by default.
The hit area to change an item from checked to unchecked is the box /and/ the title, rather than just the box as in Winforms
I can handle the first issue by adding a listener to the PropertyChanged event on each item in the bound collection, and if IsChecked changes, then set IsChecked to the same value for all currently selected items.
However, I cannot find a good solution to the second issue. By splitting the DataTemplate into a Checkbox with no title, and a TextBlock with the title, I can reduce the hit area to change the check state to only the desired square. However, all mouse interaction which hits the TextBlock does nothing - I would like it to behave the same as in a normal listbox, or in the dead space outside of the Textblock: If the user is holding shift, then select everything up to and including this item, if not, then clear the selection and select only this item. I could try to implement something where I handled Mouse* events on the TextBlock, but that seems brittle and inelegant - I'd be trying to recreate the exact behaviour of the ListBox, rather than passing events to the listbox.
Here's what I've got currently:
XAML:
<ListBox x:Name="_lstReceivers" SelectionMode="Extended" Margin="10,41,6,15"
ItemsSource="{Binding Receivers}">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" IsHitTestVisible="True"/>
<TextBlock Text="{Binding Item}" Background="{x:Null}" IsHitTestVisible="False"/><!--Attempt to make it pass mouse events through. Doesn't work. Yuk.-->
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code behind to get the "Change all checks at the same time" logic (removed some error handling for clarity):
private void ListBoxItem_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var item = sender as CheckableItem<Receiver>;
if (item == null)
return;
if (e.PropertyName == nameof(CheckableItem<Receiver>.IsChecked))
{
bool newVal = item.IsChecked;
foreach (CheckableItem<Receiver> changeItem in _lstReceivers.SelectedItems)
{
changeItem.IsChecked = newVal;
}
}
}
By trying various combinations of Background = "{x:Null}" and IsHitTestVisible="False", I did manage to get the entire item to not respond to mouse click events - but I could not make it have only the Checkbox respond to mouse events, while everything else is passed to the ListBox for proper selection processing.
Any help would be greatly appreciated.
Answering my own question again.
Well, I couldn't find a clean way to do it, so I ended up setting the ListBoxItem to have IsHitTestVisible="False", and manually tracing mouse events using PreviewMouseDown.
Final code:
XAML:
<ListBox x:Name="_lstReceivers" SelectionMode="Extended" Margin="10,41,6,15"
ItemsSource="{Binding Receivers}" PreviewMouseDown="_lstReceivers_MouseDown">
<ListBox.ItemTemplate>
<DataTemplate>
<ListBoxItem IsSelected="{Binding IsSelected}" IsHitTestVisible="False">
<StackPanel Orientation="Horizontal" Background="{x:Null}">
<CheckBox IsChecked="{Binding IsChecked}" IsHitTestVisible="True" Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"/>
<TextBlock Text="{Binding Item}" Background="{x:Null}" IsHitTestVisible="False"/>
</StackPanel>
</ListBoxItem>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code behind:
//Logic to handle allowing the user to click the checkbox, but have everywhere else respond to normal listbox logic.
private void _lstReceivers_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Visual curControl = _lstReceivers as Visual;
ListBoxItem testItem = null;
//Allow normal selection logic to take place if the user is holding shift or ctrl
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl) || Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
return;
//Find the control which the user clicked on. We require the relevant ListBoxItem too, so we can't use VisualTreeHelper.HitTest (Or it wouldn't be much use)
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(curControl); i++)
{
var testControl = (Visual)VisualTreeHelper.GetChild(curControl, i);
var rect = VisualTreeHelper.GetDescendantBounds(testControl);
var pos = e.GetPosition((IInputElement)curControl) - VisualTreeHelper.GetOffset(testControl);
if (!rect.Contains(pos))
continue;
else
{
//There are multiple ListBoxItems in the tree we walk. Only take the first - and use it to remember the IsSelected property.
if (testItem == null && testControl is ListBoxItem)
testItem = testControl as ListBoxItem;
//If we hit a checkbox, handle it here
if (testControl is CheckBox)
{
//If the user has hit the checkbox of an unselected item, then only change the item they have hit.
if (!testItem.IsSelected)
dontChangeChecks++;
((CheckBox)testControl).IsChecked = !((CheckBox)testControl).IsChecked;
//If the user has hit the checkbox of a selected item, ensure that the entire selection is maintained (prevent normal selection logic).
if (testItem.IsSelected)
e.Handled = true;
else
dontChangeChecks--;
return;
}
//Like recursion, but cheaper:
curControl = testControl;
i = -1;
}
}
}
//Guard variable
int dontChangeChecks = 0;
//Logic to have all selected listbox items change at the same time
private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
if (dontChangeChecks > 0)
return;
var newVal = ((CheckBox)sender).IsChecked;
dontChangeChecks++;
try
{
//This could be improved by making it more generic.
foreach (CheckableItem<Receiver> item in _lstReceivers.SelectedItems)
{
item.IsChecked = newVal.Value;
}
}
finally
{
dontChangeChecks--;
}
}
This solution works, but I don't like the coupling it introduces between my code and the exact behaviour of the ListBox implementation:
Checking the Keyboard state
It won't handle dragging if the user starts dragging inside a checkbox
It should happen on mouseup, not mousedown. But it's close enough for my needs.
PS: The bound class, even though it's irrelevant and obvious what it would have:
public class CheckableItem<T> : INotifyPropertyChanged
{
public T Item { get; set; }
private bool _isSelected;
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected == value)
return;
_isSelected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));
}
}
private bool _checked;
public bool IsChecked
{
get => _checked;
set
{
if (_checked == value)
return;
_checked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}

Datagrid sort, what happened to row?

I am coding a UserControl that can be use as a ScrollBar with color mark on it (like mostly all IDE).
My UserControl look
<UserControl x:Class="MarkedScrollBar" x:Name="Instance" ...>
<Grid Name="grd" >
<COLUMN/ROW DEF>...</>
<ScrollViewer Name="scrView" Grid.RowSpan="3" Grid.ColumnSpan="2" >
<my:IcuContentPresenter x:Name="presenter" Content="{Binding AdditionnalContent, ElementName=Instance}" ContentUpdated="presenter_ContentUpdated" />
</ScrollViewer>
<Canvas ...(Canvas place on the scrollbar) />
</Grid>
</UserControl>
On my UserControl, everything work fine. I can add content in my IcuContentPresenter (Extension of ContentPresenter to get 1 more event).
In my main window i use my MarkedScroolBar like this :
<my:IcuMarkedScrollBar Grid.Row="0" x:Name="bbb" Grid.Column="0" >
<my:IcuMarkedScrollBar.AdditionnalContent>
<my:IcuDataGrid ItemsSource="{Binding AAA, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Loaded="DataGrid_Loaded" Width="300" LoadingRow="DataGrid_LoadingRow" />
</my:IcuMarkedScrollBar.AdditionnalContent>
</my:IcuMarkedScrollBar>
Again, i have a DataGrid extension to get 1 event (Sorted event, code from here).
Now my problem is that when i sort my datagrid Inside my MarkedScrollBar, i want the mark to follow the content, that the mark is binding to.
First attempt, I try to link the mark with the control having a Dictionary Key=Mark, Value=Control. I was getting the DatagridRow that I wanted to have a mark for my datacontext.
First time the datagrid appear, my mark are all well place, but if I sort, my mark don't follow. I went into debugging and saw that there is a DataGridRow that contains my datacontext item, but it's not the one i save in my Dictionary.
End First attempt
Second attempt, with the DataGridRow changing when I sort, I thought that if I was linking my DataContext item to my mark it would fix the bug.
So now, when I sort my datagrid, I try to find the datagridrow that contains my datacontext item. But it does find anything.
But, when i reexecute the same code manually with a button in the window, it's work. All my mark appear at the good position.
End second attempt
Brief explanation of my extension :
DataGrid : I use it to get the Sorted event, because in Sorting event the row where not already move.
ContentPresenter : I add event on it to get modification to the content, but not to the Property (like datagrid sorting). For that i needed to check the type of the content, so i don't support everything for now.
My code for the ContentPresenter is that :
public class IcuContentPresenter : ContentPresenter
{
public event EventHandler<ControlEventArgs> ContentUpdated;
public IcuContentPresenter()
{
this.Loaded += OnLoaded;
}
protected void OnLoaded(object p_oSender, RoutedEventArgs p_oEvent)
{
Type t = this.Content.GetType();
if (t == typeof(IcuDataGrid))
{
IcuDataGrid oControl = this.Content as IcuDataGrid;
oControl.Sorted += CallEvent;
}
}
void CallEvent(object sender, EventArgs e)
{
if (ContentUpdated != null)
{
ContentUpdated(this, new ControlEventArgs(Content.GetType()));
}
}
public UIElement FindVisualElementForObject(object p_oObject)
{
UIElement oTheOne = null;
if (Content.GetType() == typeof(IcuDataGrid))
{
oTheOne = FindInDatagrid(p_oObject);
}
return oTheOne;
}
private UIElement FindInDatagrid(Object p_oObj)
{
DataGrid oGrid = Content as DataGrid;
var a = (DataGridRow)oGrid.ItemContainerGenerator.ContainerFromItem(p_oObj);
return a;
}
//----------------------------------------------------
// Inner class
//----------------------------------------------------
public class ControlEventArgs : EventArgs
{
public ControlEventArgs(Type value)
{
ControlType = value;
}
public Type ControlType { get; set; }
}
}
To support a control i will have to add them here. On the load of this control, I check the content, if the content is my Datagrid on the event Sorted i call the my Event ContentUpdated to be able to update my mark. But at this moment, it's like my datagrid contains no row with my datacontext item.
When virtualization is enabled, row elements will only be generated for data items which are actually in view. You will need to associate the marks with the underlying data items (row objects) rather than the DataGridRow elements. The Items property on the DataGrid should have the rows in their correctly sorted positions.

Handling WPF Editable combobox when entered text is not a part of datsource

I have a Combobox in WPF, I have set Is Editable="true" which allows me enter any text in the combobox. I would like to restrict users from entering text outside datasource.
Xaml:
<ComboBox Name="service" Margin="0,0,0,4"
IsEditable="True"
Grid.Column="1"
Grid.ColumnSpan="2" Grid.Row="4"
SelectedValuePath="Id"
DisplayMemberPath="Service"
SelectedValue="{Binding Controller.Service1}"
ItemsSource="{Binding}" />
C#:
System.Data.DataView vw = tableAdapterServices.GetData().DefaultView;
service.ItemsSource = vw;
service.SelectedIndex = 0;
I do not want to allow users to enter text which is not present in the datasource, or handle it if the user enters any other text.
Update:
Thanks for the solution #Vishal, LostFocus event is handling the issue, but it gave rise to another issue. I have a button which is used to submit the combobox value along with other textbox values to the server. I am setting default value in the combobox in lostfocus event. But I need to prevent the button click event if some value other that datasource value is added in combobox.
You can check for selectedIndex in Lostfocus event :
private void ComboBox_LostFocus(object sender, EventArgs e)
{
if(((ComboBox)sender).SelectedIndex == -1)
{
//Text entered by user is not a part your ItemsSource's Item
SaveButton.IsEnabled = false;
}
else
{
//Text entered by user is a part your ItemsSource's Item
SaveButton.IsEnabled = true;
}
}
You can try handling the ComboBox's TextInput or PreviewTextInput events, doing the text search yourself, selecting the most appropriate item, and setting "e.Handled = true."
This works for a single character (i.e. if you enter the letter "j", it will select the first item that contains a "j" or "J"), but I'm sure there's a way to do this with your control. Just include a little more logic to achieve this.
private void MyComboBox_PreviewTextInput(object sender, TextCompositionEventArgs e) {
foreach (ComboBoxItem i in MyComboBox.Items) {
if (i.Content.ToString().ToUpper().Contains(e.Text.ToUpper())) {
MyComboBox.SelectedItem = i;
break;
}
}
e.Handled = true;
}
Ok, from what I understand the behaviour of the combobox should disregard an inserted character if there is no item in the datasource that contains the resulted string.
I believe you are doing it in a MVVM style since you are using binding. What you can do is to bind the ComboBox text to a property and the PreviewTextInput event to a command and do the filtering there.
XAML:
<ComboBox Name="service"
Margin="0,0,0,4"
IsEditable="True"
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="4"
SelectedValuePath="Id"
DisplayMemberPath="Service"
SelectedValue="{Binding Controller.Service1}"
ItemsSource="{Binding}"
Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewTextInput">
<cmd:EventToCommand Command="{Binding TextInputCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Combobox>
C# ViewModel:
public RelayCommand<object> TextInputCommand { get; set; }
public bool CanExecuteTextInputCommand(object param)
{
return true;
}
public void ExecuteTextInputCommand(object param)
{
TextCompositionEventArgs e = param as TextCompositionEventArgs;
string currentText = this.Text;
string entireText = string.Format("{0}{1}", currentText, e.Text);
var item = this.Items.Where(d => d.StartsWith(entireText)).FirstOrDefault();
if (item == null)
{
e.Handled = true;
this.Text = currentText;
}
}
Where Items is the ObservableCollection containing the items (in this case it's a list of strings) and Text is the property binded to the Combobox text.
EDIT: Ok so what you need to do to make it work is to go to your project, right click on References, choose Manage NuGet Packages, search and install MVVM Light. Two dlls that start with GalaSoft will be added to your references. After this, in your xaml code add these namespaces:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.WPF4"
What this allows you to do is to bind an event to a ICommand object.

Data binding not giving expected results windows phone

In my windows phone app I've implemented data binding which is not yielding me expected results.
My functionality is I've a list box in which I've two textboxes which are data bound.
When I click the textbox datepicker/timepicker will open and the selected value should reflect in the textbox.
The xaml code for the listbox data template is as follows
<TextBox Visibility="{Binding TBVisibility}" IsReadOnly="{Binding TBReadOnly}" InputScope="{Binding Numeric}" AcceptsReturn="{Binding MultiLine}" Width="{Binding TBWidth}" TextWrapping="Wrap" Text="{Binding Path=TBText, Mode=TwoWay}" GotFocus="TextBox_GotFocus_1" KeyUp="TextBox_KeyUp_1" LostFocus="TextBox_LostFocus_1" />
<TextBox Visibility="{Binding TB2Visibility}" IsReadOnly="True" Width="140" Text="{Binding TB2Text, Mode=TwoWay}" GotFocus="TextBox_GotFocus_2" />
I'm launching the datepicker and timepicker as follows
private void LaunchDatePicker(TFDetails field)
{
datePicker = new CustomDatePicker
{
IsTabStop = false,
MaxHeight = 0,
Value = field.SelectedDate
};
datePicker.DataContext = field;
datePicker.ValueChanged += DatePicker_ValueChanged;
LayoutRoot.Children.Add(datePicker);
datePicker.ClickDateTemplateButton();
}
Where as "field" is the datacontext of the listbox.
The ValueChanged events are as follows
private void DatePicker_ValueChanged(object sender, DateTimeValueChangedEventArgs e)
{
DatePicker currentDP = sender as DatePicker;
TFDetails callingField = currentDP.DataContext as TFDetails;
if (callingField != null)
{
callingField.SelectedDate = currentDP.Value;
callingField.TBText = currentDP.ValueString;
}
}
When I change the time its not reflecting in the textbox. I wrote INotifyChangedProperty also.
May I know what mistake I could possible be doing here.
I actually have the same code in a similar UI page where it works perfectly. i don't know what mistake I'm doing here.
Thanks.
ListBox is a collection control. If you have a DataTemplate for it, bindings in it will use a single elements of collection boud to ItemsSource as a DataContext rather than DataContext od entire ListBox.

c# How to get Listbox selection from Observable Collection

I'm probably not even asking this correctly, I am new to c#, but trying to help my 14 year-old son learn. I've created a listbox with items created with an ObservableCollection. Here is the XAML:
<ListBox x:Name="listBox1" ItemsSource="{Binding}" Margin="105,205,886,63"
IsTabStop="True" SelectionChanged="PrintText"
ScrollViewer.VerticalScrollBarVisibility="Hidden" TabIndex="5" FontSize="36"
Background="Transparent" Foreground="#FF55B64C" FontFamily="Arabic Typesetting"
FontWeight="Bold" IsDoubleTapEnabled="False" SelectionMode="Single" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Name="blockNameList" Text="{Binding name}"/>
<TextBlock Text=" #"/>
<TextBlock Name="blockIdList" Text="{Binding id}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here is how I created the ListBox Items:
var client = new HttpClient();
var uri = new Uri("http://theurlImusing");
Stream respStream2 = await client.GetStreamAsync(uri);
// DataContractJsonSerializer ser2 = new DataContractJsonSerializer(typeof(RootObject));
// RootObject feed2 = (RootObject)ser2.ReadObject(respStream2);
DataContractJsonSerializer ser = null;
ser = new DataContractJsonSerializer(typeof(ObservableCollection<RootObject>));
ObservableCollection<RootObject> feed2 = ser.ReadObject(respStream2) as ObservableCollection<RootObject>;
var cardList = new List<RootObject>();
foreach (RootObject returnfeed in feed2)
{
string cid = returnfeed.id;
string cardname = returnfeed.name;
listBox1.Items.Add(new RootObject { id=cid, name=cardname });
}
I thought I would just use the SelectionChanged="PrintText" property of the listbox so that when I clicked on a listbox item, it would just change a textblock's text value. Ultimately, that is all I am trying to do...set a textblock or textbox to be equal to the "id" value that is clicked on in the ListBox.
void PrintText(object sender, SelectionChangedEventArgs args)
{
//What do I put in here??
}
Thanks very much for any insight! I need it!!
This is something that is much easier to do using data binding. You can bind the TextBlock.Text property directly to the ListBox using an ElementName binding:
<TextBox Text="{Binding ElementName=listBox1,Path=SelectedItem.id}" />
Alternatively, if you set set SelectedValuePath="id" on the ListBox, then binding to SelectedValue will give you the "id" property:
<ListBox x:Name="listBox1" SelectedValuePath="id" ... />
<TextBox Text="{Binding ElementName=listBox1,Path=SelectedValue}" />
As a side note (as #Rachel already noted in comments): you may as well just set the ItemsSource, rather than looping through and adding each manually. All you need is this:
listBox1.ItemsSource = feed2;
Edit
Ok, if you wanted to use the procedural approach, here's how you would do it. (No one would recommend this approach, especially if you're learning/teaching. Try to make full use of data binding, and view-viewmodel separation.)
void PrintText(object sender, SelectionChangedEventArgs args)
{
var listBox = (ListBox)sender;
RootObject selectedItem = listBox.SelectedItem;
someTextBox.Text = selectedItem.id;
}
If all you want to do is click an item in the ListBox and get it to show up in the TextBox, you don't need fancy binding (in that other answer) to do it. You can simply add a MouseUp event in the ListBox XAML:
MouseUp="ListBox1_MouseUp"
This would work similar to the SelectionChanged event you wanted to use.
You then right-click that function name in the XAML page and select "Go to definition". It will create the next function for you:
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
}
Simply add in there to update the TextBox you want with the SelectedItem values from sender:
private void ListBox1_MouseUp(object sender, MouseButtonEventArgs e)
{
ListBox lstBox = (ListBox)sender;
ListBoxItem item = lstBox.SelectedItem;
if (item != null) // avoids exception when an empty line is clicked
{
someBox.Text = item.name;
someOtherBox.Text = item.id;
}
}
I later found that blockNameList and blockIdList are not accessible via intellisense because they are within the DataTemplate of the ListBox, so I put someBox and someOtherBox, as references to other TextBoxes you would have to add to the XAML, outside of the ListBox. You would not re-write data inside the ListBox on the same item by clicking it. Even if you could reach the template's TextBlock to do it, you'd just be re-writing that same item with its own values, since it would be the SelectedItem!
Even though there are those that don't recommend this approach because they like binding everything - and in some cases you want binding to occur so that controls on the page update as a result of dependencies (i.e. do one thing to cause another), I find that manual methods of clicking a button/item/control to update something are just fine and avoid all the model/MVVM BS that has taken over WPF and over-complicated it.

Categories