Get names of control in code behind when clicked, wpf - c#

I have a usercontrol and I want to get the names of the control user clicks on this usercontrol.
The Usercontrol xaml is given below:
<Grid Name="Grid1">
<ListView Name ="ListView1">
<listbox.resources>
<Datatemplate>
<Togglebutton Name="Button1">
</Togglebutton>
</Datatemplate>
</listbox.resources>
</Listview>
<Border Name="Border1">
<ContentControl>
</ContentControl>
</Border>
</Grid>
Now in my code behind, I wrote:
this.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(mouseclicked);
private void mouseclicked(object sender, MouseButtonEventArgs e)
{
var source = e?.OriginalSource as FrameworkElement;
if (source != null)
{
var parent = source.Parent as FrameworkElement;
string name = string.Empty;
if (parent != null)
{
name = parent.Name;
}
else
{
name = source.Name;
}
//If clicked outside the usercontrol, then usercontrol should close down
if (!(name.Contains("Border1") || name.Contains("Grid1"))) //very strange values sometimes null or empty
{
//then do something
}
}
}
How can I get the names of the controls used in my Usercontrol in codebehind?

You have gave the grid, border and listview a name in XAML. This you should access in codebehind and check in the mouseclicked event, which element is mouse over.
private void mouseclicked(object sender, MouseButtonEventArgs e)
{
if (ListView1.IsMouseOver && Grid1.IsMouseOver)
{
MessageBox.Show("List view clicked");
}
if (Border1.IsMouseOver && Grid1.IsMouseOver)
{
MessageBox.Show("Border1 clicked");
}
if (Grid1.IsMouseOver)
{
MessageBox.Show("Grid1 clicked");
}
}
This would may be not the best, but could work to get the names of controls the user has clicked.

Related

how to access label name in nested listview datatemplate on a check box event

I have defined a label with name and I'm trying to access it but no luck. Let me explain my problem with my code.
<ListView Name="gridListView" ItemsSource="{Binding... }">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Focusable" Value="false"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Vertical">
<Label x:Name="vLabel" Content="{Binding VCValue}"/>
<ListView Name="checkBoxListView" ItemsSource="{Binding CList}">
<ListView.ItemTemplate>
<DataTemplate>
<CheckBox Margin="5" Click="CheckBox_Click" IsChecked="{Binding SelectedValue, Mode=TwoWay}" Content="{Binding Current, Mode=OneWay }"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
In the above code, I have two listview, gridListView and checkBoxListView. Here, I want to access the label vLabel which is inside the datatemplate of gridListView when the one of the value in checkbox(which is inside checkBoxListView) is clicked.
I understand it can't be accessed directly as its within datatemplate so i tried below code as suggested in other forums but gridListView.SelectedIndex is always -1 so i know i'm not doing the right thing. When I just hardcoded gridListView.SelectedIndex to index 0, 1 or 2 its giving me the right value of vLabel so the below code will work if gridListView.SelectedIndex is correct.
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox chk =(CheckBox)sender;
int index = gridListView.Items.IndexOf(chk.DataContext);
ListViewItem item = gridListView.ItemContainerGenerator.ContainerFromIndex(gridListView.SelectedIndex) as ListViewItem;
if (item!=null)
{
//get the item's template parent
ContentPresenter templateParent = GetFrameworkElementByName<ContentPresenter>(item);
DataTemplate dataTemplate = gridListView.ItemTemplate;
if (dataTemplate != null && templateParent != null)
{
var lab = dataTemplate.FindName("vLabel", templateParent) as Label;
var v = lab.Content;
}
}
private static T GetFrameworkElementByName<T>(FrameworkElement referenceElement) where T : FrameworkElement
{
//I can post this function if need be
....
}
Appreciate any help that will help me access vLabel.
Thanks in advance
you are setting focusable to false, so you cant select the item by clicking. also the checkbox-checked happens before the selection, even if you were to set focusable to true, so selected index would still be -1.
you can find your label simply like this:
public Label FindLabel(CheckBox checkBox)
{
var listView = VisualTreeHelper.GetParent(checkBox);
while (listView.GetType() != typeof(ListView))
{
listView = VisualTreeHelper.GetParent(listView);
}
return (listView as FrameworkElement).FindName("vLabel") as Label;
}
but i suggest you tell us what you want to achieve, because this doesnt seem like a clean solution.
can you perhaps do this on your StackPanel:
<StackPanel CheckBox.Checked="CheckBox_Click" Orientation="Vertical">
and then access your two desired properties as following:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
var outerItem = (sender as FrameworkElement).DataContext;
var innerItem = (e.OriginalSource as FrameworkElement).DataContext;
}
and then do whatever you want to do?
Thank you for all your guidance. I did get hint from Milan's code to achieve solution for my issue. Here, I'm trying to get reference parent of listviewItem(i.e stackpanel) and then access its child. In my case, stack panels child at index 0 is Label and at index 1 is ListView. So then I go through visualtreehelper to get reference to its child at index 0 which is what i need access to. So here is the code snippet.
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox checkBox = (CheckBox)sender;
//to access parent of the checkbox
ListViewItem listViewItem =
GetVisualAncestor<ListViewItem>((DependencyObject)sender);
//to access parent of the listViewItem(which is parent of checkbox)
StackPanel stackPanel =
GetVisualAncestor<StackPanel>((DependencyObject)listViewItem);
int childCount = VisualTreeHelper.GetChildrenCount(stackPanel);
//to access child of stackpanel to access the current vLabel
var vValue = VisualTreeHelper.GetChild(stackPanel, 0) as Label;
}
private static T GetVisualAncestor<T>(DependencyObject o)where T : DependecyObject
{
...
}

WPF - Remove a "User Control" Child from a StackPanel

I'm trying to make a WPF UI where the user can edit a query to search the database. The query is created according to what the consumer chooses from the comboboxes Like This and he can create as much filters as he wants as long as he clicks the Add new Condition button.
I created the comboboxes template as a User Control like this :
User control XAML:
<StackPanel Orientation="Horizontal" >
<Button
Name="DeleteFilter"
HorizontalAlignment="Left"
Margin="5"
Content="-"
Click="DeleteFilter_OnClick">
</Button>
<ComboBox
Text="Property"
x:Name="Property"
Width="100"
DataContext="{StaticResource SomeViewModel}"
ItemsSource="{Binding Properties}"
DisplayMemberPath="Name"
SelectionChanged="Property_OnSelectionChanged"/>
<ComboBox
Text="PropertyOperator"
x:Name="Operator"
ItemsSource="{Binding Operators}"
DisplayMemberPath="Name"
SelectionChanged="Operator_OnSelectionChanged">
</ComboBox>
<TextBox
x:Name="Value"
Text="Value"
TextAlignment="Center"
Width="100"
Margin="5"/>
</StackPanel>
Whenever the user clicks the Add new Condition button, I call this event:
private void AddFilterButton_OnClick(object sender, RoutedEventArgs e)
{
var conditionUserControl = new ConditionUserControl();
StackPanel.Children.Add(conditionUserControl);
}
Everything works correctly.
My Question:
How can I delete the User Control child from clicking the DeleteFilter button that exists in the User Control template.
I tried this:
StackPanel.Children.Remove(..);
to remove the child from my MainWindow but how to know which child the user clicked.
Try this:
private void DeleteFilter_OnClick(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
var conditionUserControl = FindParent<ConditionUserControl>(btn);
if (conditionUserControl != null)
{
var sp = FindParent<StackPanel>(conditionUserControl);
if (sp != null)
sp.Children.Remove(conditionUserControl);
}
}
private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
{
var parent = VisualTreeHelper.GetParent(dependencyObject);
if (parent == null) return null;
var parentT = parent as T;
return parentT ?? FindParent<T>(parent);
}
Another answer to #mm8 answer is :
Update the AddFilterButton_OnClick:
I did this and the functionality works:
private void AddAndFilterButton_OnClick(object sender, RoutedEventArgs e)
{
var conditionUserControl = new ConditionUserControl();
StackPanel.Children.Add(conditionUserControl);
conditionUserControl.DeleteFilter.Click += (o, args) => StackPanel.Children.Remove(conditionUserControl);
}

c# - how to handle with null selectedItem?

i have an issue with selectedItem of a listbox. When I select an item of the listbox, a popup would be displayed where you click the add button to select an image (it contains a value of selectedItem) which is working fine. But after clicking the add button to select the image, then you realise the image is wrong, so you click the add button again to select another image, it started problem because selectedItem is null. How to handle it? How to stay the value of selectedItem? Your given code much appreciated.
if (lstDinner.SelectedItem != null)
{
output = _imageInserter.InsertImage(imageName, lstDinner.SelectedItem.ToString());
PopupToysImage.IsOpen = true;
strDinner.DinnersDetails = lstDinner.SelectedItem.ToString()
}
else
{
// strDinner.DinnersDetails = null that cause a problem.
output = _imageInserter.InsertImage(imageName, strDinner.DinnersDetails);
PopupDinnerImage.IsOpen = true;
}
UPDATE HERE:
WPF:
<ListBox Style="{DynamicResource ListBoxStyle1}" DisplayMemberPath="Dinner" BorderBrush="#FFF0F0F0" x:Name="lstDinner" FontSize="20" HorizontalAlignment="Left" Margin="0,110,0,72.667" Width="436" SelectionMode="Extended" PreviewMouseLeftButtonDown="MouseDownHandler" ScrollViewer.CanContentScroll="True" UseLayoutRounding="False" KeyDown="lstDinner_KeyDown" MouseDoubleClick="lstDinner_MouseDoubleClick" >
events in C#:
private void MouseDownHandler(object sender, MouseButtonEventArgs e)
{
var parent = (ListBox)sender;
_dragSource = parent;
var data = GetObjectDataFromPoint(parent, e.GetPosition(parent));
if (e.ChangedButton == MouseButton.Left && e.ClickCount == 1)
{
if (data != null)
DragDrop.DoDragDrop(parent, data, DragDropEffects.Move);
}
}
private void lstDinner_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete)
{
RemoveItemsFromDatabase();
}
}
private void lstDinner_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
_dinnerImage = new DinnerImageExtractor();
BitmapImage getImage = new BitmapImage();
if (lstDinner.SelectedItem != null)
{
getImage = _dinnerImage.GetDinnerImages(lstDinner.SelectedItem.ToString());
if (getImage != null)
{
DinnerImagePopup.Source = getImage;
}
else
{
DinnerImagePopup.Source = new BitmapImage(new Uri("/DinnerApplicationWPF;component/Menu/Images/noImage-icon-pink.png", UriKind.Relative));
}
PopupDinnerImage.IsOpen = true;
// PopupInstrcution.IsOpen = false;
}
}
I would suggest something like this
if ( lstDinner.SelectedItem == null)
{
output = _imageInserter.InsertImage(imageName, lstToys.SelectedItem.ToString());
PopupToysImage.IsOpen = true;
lstDinner.Databind();
}
Note: This may not work as I dont have your actual code. I have added DataBind() in the if statement, if the selected item was null. It should refresh the list.
Best thing is to use two different Listbox item templates for selected and unselected items. So without displaying popup, you can add button into the selected item template.
Are you disabling the ListBox while you select the image?
If so I believe by simply disabling the ListBox the SelectedItem will be set to null.
EDIT:
I imagine you want your event handlers (like the mouse double click) to happen when an item in your list is double clicked, not when the ListBox is double clicked. You need to change your XAML to this:
<ListBox Style="{DynamicResource ListBoxStyle1}" DisplayMemberPath="Dinner" BorderBrush="#FFF0F0F0" x:Name="lstDinner" FontSize="20" HorizontalAlignment="Left" Margin="0,110,0,72.667" Width="436" SelectionMode="Extended" PreviewMouseLeftButtonDown="MouseDownHandler" ScrollViewer.CanContentScroll="True" UseLayoutRounding="False" KeyDown="lstDinner_KeyDown">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<EventSetter Event="MouseDoubleClick" Handler="lstDinner_MouseDoubleClick" />
</Style>
</ListBox.Resources>
</ListBox>
My selected item does not come up null when I run this code.

Give focus to a component inside an expander

I have this requirement where I need to focus the first element inside the expander when the user press tab.
Currently (default behavior) the focus goes to the expander, I've tried to focus the first element of the expander by creating a focus event handler in the expander like this:
private void ExpanderGotFocus(object sender, RoutedEventArgs e)
{
var expander = (Expander) sender;
if (!expander.IsExpanded)
{
expander.IsExpanded = true;
this._someText.Focus();
}
}
Which doesn't work.
I've also tried to give the focus the the next element:
var tRequest = new TraversalRequest(FocusNavigationDirection.Next);
var keyboardFocus = Keyboard.FocusedElement as UIElement;
keyboardFocus.MoveFocus(tRequest);
But only works the second time ( when the expander has been at least opened once )
I've tried to put this in a thread and some other crazy ideas.
How can I give focus to the first element inside an expander? ( the first time the expander is closed )
I tried several ways and none of them worked, basically the problem is the TextBox is still rendering when the expander is expanding ( to early ).
So instead what I've found is to add the IsVisibleChanged event to the textbox so when the expander finished the textbox become visible and request the focus
XAML
<Expander GotFocus="ExpanderGotFocus">
<Expander.Header>
<TextBlock Text="{x:Static Client:Strings.XYZ}" />
</Expander.Header>
<Expander.Content>
<StackPanel>
<TextBox IsVisibleChanged="ControlIsVisibleChanged" Name="txtBox" />
</StackPanel>
</Expander.Content>
</Expander>
Code behind
private void ExpanderGotFocus(object sender, RoutedEventArgs e)
{
var expander = (Expander) sender;
if (!expander.IsExpanded )
{
expander.IsExpanded = true;
}
}
private void ControlIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
Keyboard.Focus((IInputElement)sender);
}
Check with the following,
XAML code:
<StackPanel>
<Expander Header="Expander"
Name="expander"
Collapsed="OnCollapsed"
IsExpanded="True" >
<StackPanel>
<TextBox Text="Text1" Name="textBox1" />
<TextBox Text="Text2" Name="textBox2" />
<TextBox Text="Text3" Name="textBox3" />
</StackPanel>
</Expander>
<TextBox Text="Text4" Name="textBox4" />
</StackPanel>
in the code behind:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.Loaded += delegate
{
textBox2.Focus();
};
}
private void OnCollapsed(object sender, RoutedEventArgs e)
{
var element = Keyboard.FocusedElement;
if (element != null)
{
//now is the ToggleButton inside the Expander get keyboard focus
MessageBox.Show(element.GetType().ToString());
}
//move focus
Keyboard.Focus(textBox4);
}
}

WPF - How do determine the index of the current item in a listbox from button handler

i have a listbox with a data template that contains a button.
When the button is clicked I want to get in the button
click handler the index of the listbox item that was current??
How do I do this please?
Malcolm
More appropriate answer,
private void Button_Click(object sender, RoutedEventArgs e)
{
DependencyObject dep = (DependencyObject)e.OriginalSource;
while ((dep != null) && !(dep is ListViewItem))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep == null)
return;
int index = lstBox.ItemContainerGenerator.IndexFromContainer(dep);
}
Hope the bellow code will help you.
private void Button_Click(object sender, RoutedEventArgs e)
{
var b = (Button)sender;
var grid = (Grid)b.TemplatedParent
var lstItem = (ListBoxItem)grid.TemplatedParent;
int index = lstBox.ItemContainerGenerator.IndexFromContainer(lstItem);
// rest of your code here...
}
And the XAML for the above assumed to be a DataTemplate on a ListBox named lstBox:
<DataTemplate x:Key="template">
<Grid>
<Button Click="Button_Click" Content="Press"/>
</Grid>
</DataTemplate>
Have you checked the "SelectedIndex" property of the listbox? It might be set by clicking on the button.
Probably way to late but using "IndexOf" on the listbox "Items" will give you the index #
Regards
myListbox.Items.CurrentItem seems be what you are looking for.
Hi you can use ContentPresenter.Content to get current item , instead of current index:
<DataTemplate DataType="{x:Type MyModel}">
<StackPanel Orientation="Horizontal" Margin="0 5">
<TextBlock Text="{Binding Title}" />
<Button Content="Active" Click="Button_Click" />
</StackPanel>
</DataTemplate>
and in code:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = e.Source as Button;
var contentPresenter = button.TemplatedParent as ContentPresenter;
var myModel = (MyModel)contentPresenter.Content;
}

Categories