I am trying to create a method that will clear all of the ComboBoxes on my window. This is what I have tried so far:
private void ClearAllComboboxes(ComboBox cmb)
{
cmb.SelectedIndex = -1;
}
And then I call the method like below, but I can only insert one ComboBox to clear at a time.
private void btnClearAll_Click(object sender, RoutedEventArgs e)
{
ClearAllComboboxes(cmbBarlocks);
}
So what I am trying to do is clear all of the comboboxes with as little coding as possible. Can someone please tell me how and what would be the best possible way to do this? Thank you :)
I assume that you are using MVVM and you have SelectedItem property for every combobox in your viewmodel.
In viewmodel, you can just set SelectedItem=null for each combobox.
It will clear your combobox selection.
If you are not using MVVM, then you can use following code in code behind:
private void ClearAllComboboxes()
{
List<ComboBox> comboBoxes = new List<ComboBox>();
GetLogicalChildCollection<ComboBox>(container, comboBoxes);
comboBoxes.ForEach(combobox => combobox.SelectedIndex = -1);
}
private static void GetLogicalChildCollection<T>(DependencyObject parent,List<T> logicalCollection) where T : DependencyObject
{
var children = LogicalTreeHelper.GetChildren(parent);
foreach (object child in children)
{
if (child is DependencyObject)
{
DependencyObject depChild = child as DependencyObject;
if (child is T)
{
logicalCollection.Add(child as T);
}
GetLogicalChildCollection(depChild, logicalCollection);
}
}
}
Let me assume All your comboboxes are inside a container(let it be stackPanel), the you can set selected index to -1 for all of them using the following snippet:
foreach (Control ctrl in stkContainer.Children)
{
if (ctrl.GetType() == typeof(ComboBox))
{
ComboBox cbo = ctrl as ComboBox;
ClearAllComboboxes(cbo);
}
}
If you want to clear the combobox means you have to re-define your method signature as:
private void ClearAllComboboxes(ComboBox cmb)
{
cmb.Items.Clear();
}
protected void btnAll_Click(object sender, EventArgs e)
{
ClearInputs(Page.Controls);
}
//For Clear All Control Values
void ClearInputs(ControlCollection ctrls)
{
foreach (Control ctrl in ctrls)
{
if (ctrl is ComboBox )
((ComboBox )ctrl).ClearSelection();
ClearInputs(ctrl.Controls);
}
}
In your handler try this, it worked when I had a similar issue with ListBox
void ClearCombos(params ComboxBox[] boxes)
{
foreach(var box in boxes)
box.ItemsSource = null;
}
and call it ClearCombos(x,y,z); where x,y,z are the boxes you want to clear
Related
I have many forms with a lot of textboxes. And I want to add to that forms a button with IsDefault = true. Then fill any property and press enter. If I will not set UpdateSourceTrigger=PropertyChanged on textbox, it will not see my input.
The problem is that I do not want to add UpdateSourceTrigger=PropertyChanged to each textbox, combobox, checkbox, and etc.
Is there any way to trigger everything to write it's data to the source without adding UpdateSourceTrigger=PropertyChanged?
Call the BindingExpression.UpdateSource method in the click event handler for each of the Controls (TextBox, CheckBox, etc.) that you have in your Window/UserControl, like this:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e) {
this.UpdateSourceTrigger(this);
MessageBox.Show($"Field1: {this.vm.Field1}\nField2: {this.vm.Field2}\nField3: {this.vm.Field3}");
}
public void UpdateSourceTrigger(UIElement element) {
if (element == null) return;
var children = LogicalTreeHelper.GetChildren(element);
foreach (var e in children) {
if (e is TextBox txtBox) {
var binding = txtBox.GetBindingExpression(TextBox.TextProperty);
binding?.UpdateSource();
}
if (e is CheckBox chkBox) {
var binding = chkBox.GetBindingExpression(CheckBox.IsCheckedProperty);
binding?.UpdateSource();
}
// add other types, like ComboBox or others...
// ...
this.UpdateSourceTrigger(e as UIElement);
}
}
I have a 2 ListViews with same items in both of them. What I want to do is that when a selection is made in one ListView, the same selection should be reflected in the other ListView also. The two ListViews are bound to two different ViewModels but both the ViewModels implement the same interface.
I've overridden the Equals methods in both ViewModels.
The two ListViews are on different XAML pages. The first ListView say LV1 is in Page1.xaml and LV2 is in Page2.xaml. What I want is that when I am changing the selection in LV2 the selection in LV1 should also change( one way only ). I've set x:FieldModifier="public" on LV1 and exposing through a static property of Page1 like this:
public sealed partial class Page1 : Page
{
public static Page1 page1 { get; private set; }
}
And on Page2, I have this :
private async void LV2_ItemClick(object sender, ItemClickEventArgs e)
{
var selected = e.ClickedItem as ISomeCommonInterface;
//Comparision is successful --> Contains() always returns corect value;
if (Page1.page1.LV1.Items.ToList().Contains(selected))
{
Page1.page1.LV1.SelectedItem = null; // this works
Page1.page1.LV1.SelectedItem = selected; // this doesn't work
}
}
I've found that inside the if condition, assignment to null changes the SelectedItem of LV1 to null but the next line doesn't change it to selected ( it remains null ).
add after assignment:
Page1.page1.LV1.Select();
This works for me:
private void LV1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selected = (sender as ListView).SelectedItem as string;
int index = -1;
for (int i = 0; i < LV2.Items.Count(); i++)
{
if (LV2.Items[i] as string == selected){
index = i;
break;
}
}
// The if becomes obsolete here, it could be replaced by
// if(index >= 0)
if (LV2.Items.ToList().Contains(selected))
{
LV2.SelectedIndex = index;
}
}
There is probably an easier way of getting the index of LV1's SelectedItem in LV2, but it should be enough to get you on the right track.
You can check out the minimal testing app I created that shows that SelectedItem works too.
Method 1 - SelectionMode="Multiple" - both ListViews in sync
You should subscribe the SelectionChanged event on both ListViews - item may not get selected only by click - and there (when selection is changed) you should sync the selection.
private void SyncSelection(object sender, SelectionChangedEventArgs e)
{
ListView listViewToAdd = ReferenceEquals(sender, firstListView) ? secondListView : firstListView;
foreach (var item in e.AddedItems)
{
if (!listViewToAdd.SelectedItems.Contains(item))
{
listViewToAdd.SelectedItems.Add(item);
}
}
foreach (var item in e.RemovedItems)
{
listViewToAdd.SelectedItems.Remove(item);
}
}
Method 2 - SelectionMode="Multiple" - update one after selecting in the other
You should subscribe the SelectionChanged event only on the ListView where items could be selected.
private void SyncSelection(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
{
secondListView.SelectedItems.Add(item);
}
foreach (var item in e.RemovedItems)
{
secondListView.SelectedItems.Remove(item);
}
}
Method 3 - SelectionMode="Single"
Subscribe the SelectionChanged event on both if you want to make them be in sync or only on the selectable one if you only want to update the second based on the first.
private void SyncSelection(object sender, SelectionChangedEventArgs e)
{
ListView senderListView = (ListView)sender;
ListView listViewToAdd = ReferenceEquals(sender, firstListView) ? secondListView : firstListView;
listViewToAdd.SelectedItem = senderListView.SelectedItem;
}
You may need to replace var with your interface to make it work.
What i want to do is that when i select an item in the listBox and then make right click on the item with the mouse it will show me a menu like Edit,Copy,Cut,Rename then if i click on for example Copy it will do something and if on Edit something else.
What i did in the form1 top is:
ContextMenuStrip menuStrip;
In the constructor:
menuStrip = new ContextMenuStrip();
menuStrip.ItemClicked += menuStrip_ItemClicked;
menuStrip.Items.Add("Cut");
menuStrip.Items.Add("Copy");
menuStrip.Items.Add("Paste");
Then in the menuStrip_ItemClicked event:
ListBox item;
void menuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
ListView.SelectedListViewItemCollection selectedItems =
lstDisplayHardware.SelectedItems;
if (e.ClickedItem.Text == "Copy")
{
String text = "";
foreach (ListViewItem item in selectedItems)
{
text += item.SubItems[1].Text + Environment.NewLine;
}
Clipboard.SetText(text);
}
}
And the event of the click:
private void lstDisplayHardware_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
item = lstDisplayHardware.GetItemAt(e.X, e.Y);
menuStrip.Show(lstDisplayHardware, e.Location);
}
}
lstDisplayHardware is my listView in my other project and in this one it should be listBox1.
The problem is that i took this example from my other project there i used it on a listView. But now i want to make it on a listBox.
Maybe i should use a listView also here ? Not sure when to use listView or listBox. In this project i'm using listBox to show list of my youtube videos so it's just a list string.
Assuming you only want a single value from the ListBox...
void menuStrip_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
if(item != null && item.SelectedIndex > -1)
{
Clipboard.SetText(item.Items[item.SelectedIndex].ToString());
}
}
I think you forgot to bind the context menu to the ListBox!?
Try this after adding your items to the context menu:
listBox1.ContextMenuStrip = menuStrip;
I have a listbox, I have set a stackpanel and textblock in that. I want the last textblock's text because I have a set a value on last textbox text by using a converter.
The code posted below is tried by me and is not working
private void listname_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string textt = (((sender as ListBox) as StackPanel).Children[1] as TextBlock).Text;
//StackPanel sPanel = (sender as StackPanel) as StackPanel;
//var tbxCollection = from tbx in sPanel.Children.OfType<TextBlock>()
// where tbx.Name == "bl"
// select tbx;
If you want to search your ContentControl (ListBoxItem) for Controls, then you can use VisualTreeHelper class for this purpose.
The code below will help you to search for a specific Control(s) in DependencyObject - parent:
private static void SearchForControls<T>(DependencyObject parent, ref List<T> controlList) where T : DependencyObject
{
int numberOfChildreen = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numberOfChildreen; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T) controlList.Add((T)child);
else SearchForControls<T>(child, ref controlList);
}
}
With this pice of code you can manage to complete your task like this:
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBoxItem item = (sender as ListBox).ItemContainerGenerator.ContainerFromIndex((sender as ListBox).SelectedIndex) as ListBoxItem;
List<StackPanel> controlList = new List<StackPanel>();
SearchForControls<StackPanel>(item, ref controlList);
string text = (controlList[0].Children[1] as TextBlock).Text;
}
In above code, in controlList you will get all StackPanels from you SelectedItem (accessed by SelectedIndex). For this example I assume that you have one StackPanel - hopefuly this will help you. Try to debug it and you will see how it works.
it would be better and easier to subscribe to textblocks Tap event instead
<DataTemplate>
<Textblock name="myTxtBlock" Tap="myTxtBlock_Tap"/>
</DataTemplate>
in code:
private void myTxtBlock_Tap(object sender, GestureEventArgs e)
{
string text=(Sender as Textblock).Text;
}
I have a ListView called CouncilListView and a TextBox called EmailTextBox which is in the ListView.
How can I access this TextBox from the CodeBehind?
I tried some forms of FindControl like :
this.Page.FindControl("EmailTextBox");
this.Page.FindControl("CouncilListView").FindControl("EmailTextBox");
this.CouncilListView.Findcontrol("EmailTextBox");
this.FindControl("EmailTextBox");
but I get this error:
Object reference not set to an instance of an object.
This is hypothetical, since I can't see your complete page codebehind and ListView code, but:
The reason is that the Textbox is part of the Listview; so you need to find it in the ListView. One possible way of doing this is below.
public void GetTextBoxValuesFromListView()
{
Textbox tb = null;
ListViewItem Item = null;
foreach (ListViewDataItem item in CouncilListView.Items)
{
Item = item;
tb = ((TextBox) (Item.FindControl("EmailTextBox")));
if (tb.Text != null)
{
//Do something
}
}
}
I had some issues with ListViews I had questions on some time back, they may be of use to you:
ListView DataItem Shows Null
Dictionary<T> of List<T> and ListViews in ASP.NET
I solved it this way:
protected void CouncilListView_ItemInserted(Object sender, ListViewInsertedEventArgs e)
{
foreach (DictionaryEntry Emailentry in e.Values)
{
if (Emailentry.Key == "Email") //table field name is "email"
{
message.To.Add(new MailAddress(Emailentry.Value.ToString()));
}
}
}