e.OriginalSource is null - c#

I have a code where i get some text of textblock. I do this in a Hold Event using this code txt = (e.OriginalSource as TextBlock).Text; but sometimes it returns me this error "An exception of type 'System.NullReferenceException' occurred in Barcode_QRCode.WindowsPhone.exe but was not handled in user code" and sometimes works just fine. Does anyone could help me here?
my code:
private void ListViewItem_Holding(object sender, HoldingRoutedEventArgs e)
{
txt = (e.OriginalSource as TextBlock).Text;
MenuFlyout menu = new MenuFlyout();
MenuFlyoutItem item1 = new MenuFlyoutItem();
MenuFlyoutItem item2 = new MenuFlyoutItem();
MenuFlyoutItem item3 = new MenuFlyoutItem();
item1.Text = "Copiar";
item2.Text = "Deletar";
item3.Text = "Compartilhar";
item1.Click += MenuFlyout_Copiar;
item2.Click += MenuFlyout_Deletar;
item3.Click += MenuFlyout_Compartilhar;
menu.Items.Add(item1);
menu.Items.Add(item2);
menu.Items.Add(item3);
menu.ShowAt((FrameworkElement)sender);
}

Check if e.OriginalSource is null before attempting to cast and assign the value:
Private void ListViewItem_Holding(object sender, HoldingRoutedEventArgs e)
{
txt = (e.OriginalSource != null ? (e.OriginalSource as TextBlock).Text : "");
MenuFlyout menu = new MenuFlyout();
MenuFlyoutItem item1 = new MenuFlyoutItem();
MenuFlyoutItem item2 = new MenuFlyoutItem();
MenuFlyoutItem item3 = new MenuFlyoutItem();
item1.Text = "Copiar";
item2.Text = "Deletar";
item3.Text = "Compartilhar";
item1.Click += MenuFlyout_Copiar;
item2.Click += MenuFlyout_Deletar;
item3.Click += MenuFlyout_Compartilhar;
menu.Items.Add(item1);
menu.Items.Add(item2);
menu.Items.Add(item3);
menu.ShowAt((FrameworkElement)sender);
}

Maybe sometimes the OriginalSource you receive is not a TextBlock, which will cause you cast to return null. You should check the type of your OriginalSource before trying to use it like so :
var textBlock = e.OriginalSource as TextBlock;
if(textBlock != null)
{
....
}

Related

How to retrieve the name of a control created programmatically

in an app where it is possible to create a serie of buttons programmatically, how can I retrieve the name of one of these buttons once I click its context menu?
This is the piece of code:
private void addButton_Click(object sender, System.EventArgs e)
{
int y = (buttonIndex * 80) + 5;
btn.Name = "btn" + buttonIndex.ToString();
btn.Content = "button " + buttonIndex.ToString();
btn.Width = 440;
btn.Height = 100;
Thickness margin = new Thickness(0, y, 0, 0);
btn.Margin = margin;
// .. all other properties..
pivot1Grid.Children.Add(btn);
buttonIndex++;
AddContextMenuItems(btn);
}
private void AddContextMenuWithMenuItems(Button btn)
{
ContextMenu contextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem() { Header = "Edit", Tag = "Edit" };
MenuItem menuItem2 = new MenuItem() { Header = "Remove", Tag = "Remove" };
menuItem1.Click += new RoutedEventHandler(menuItem1_Click);
menuItem2.Click += new RoutedEventHandler(menuItem2_Click);
contextMenu.Items.Add(menuItem1);
contextMenu.Items.Add(menuItem2);
ContextMenuService.SetContextMenu(btn, contextMenu);
}
Now in the click event I should be able to get the name of the button clicked (it works in case the context menu is created directly in XAML):
void menuItem1_Click(object sender, RoutedEventArgs e)
{
string btnName = ((sender as MenuItem).Parent as ContextMenu).Name;
..
}
but it gives always an empty string.
Could you please tell me where is the mistake?
Thanks
In your code, you're casting sender.Parent to ContextMenu. So you know you are manipulating the ContextMenu object. Then why are you expecting to magically get the name of the button by querying the name of the context menu?
The easiest way in your case is to store your information in the Tag property of the context menu:
private void AddContextMenuWithMenuItems(Button btn)
{
ContextMenu contextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem() { Header = "Edit", Tag = "Edit" };
MenuItem menuItem2 = new MenuItem() { Header = "Remove", Tag = "Remove" };
menuItem1.Click += new RoutedEventHandler(menuItem1_Click);
menuItem2.Click += new RoutedEventHandler(menuItem2_Click);
contextMenu.Items.Add(menuItem1);
contextMenu.Items.Add(menuItem2);
// Store the name of the button in the Tag property of the context menu
contextMenu.Tag = btn.Name;
ContextMenuService.SetContextMenu(btn, contextMenu);
}
Then, in the event handler, you just have to retrieve the value you've set before:
void menuItem1_Click(object sender, RoutedEventArgs e)
{
var contextMenu = (ContextMenu)((MenuItem)sender).Parent;
string btnName = (string)contextMenu.Tag;
..
}

Unhide Datagrid column in WPF

I am developing a WPF application.There is a datagrid in my Application i have created a context menu to hide and unhide column header of the datagrid while assigning the itemsource of datagrid to an IEnumerable collection.
this.dataGrid1.ItemsSource = objref.Result;
grid_data = objref.Result;
cxMenu = new ContextMenu();
foreach (Microsoft.Windows.Controls.DataGridColumn item in dataGrid1.Columns)
{
menuItem = new MenuItem();
menuItem.Header = item.Header;
menuItem.IsChecked = true;
cxMenu.Items.Add(menuItem);
menuItem.Click += new RoutedEventHandler(menuItem_Click);
menuItem.Checked += new RoutedEventHandler(menuItem_Checked);
menuItem.Unchecked += new RoutedEventHandler(menuItem_Unchecked);
}
Everythjing working fine. when i uncheck the columns are successfully remobved but when i again check the MenuItem of my ContextMenu it is not added.
Handler of my check event is as follows.
void menuItem_Checked(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
dataGrid1.ItemsSource = null;
dataGrid1.ItemsSource = objref.Result;// Again assgining the whole set to itemssource
List<string> menuList = new List<string>();
menuList.Clear();
foreach (MenuItem menuItem in cxMenu.Items)
{
if (menuItem.IsChecked == false)
{
menuList.Add(menuItem.Header.ToString());
}
}
Functionsclass objref = new Functionsclass();
foreach (string menuItem in menuList)
{
foreach (Microsoft.Windows.Controls.DataGridColumn column in dataGrid1.Columns)
{
if (column.Header.ToString() == menuItem)
{
dataGrid1.Columns.Remove(column);
break;
}
}
}
}
But my column is not added when i check again. Please help me on this.
Update 2:
void menuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
if (item.IsChecked)
{
item.IsChecked = false;
}
else
{
item.IsChecked = true;
}
}
void menuItem_Unchecked(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
foreach (Microsoft.Windows.Controls.DataGridColumn column in dataGrid1.Columns)
{
if (column.Header.ToString().Contains(item.Header.ToString()))
{
dataGrid1.Columns.Remove(column);
break;
}
}
}
Uncheck handler.
If you just want to hide/show columns, I don't think Removing/Adding columns is the right approach. I suggest you make use of the Visibility property of the column. set it to Visibility.Collapsed to hide it, then Visibility.Visible to make it visible again.
column.Visibility = Visibility.Collapsed; // Column is hidden
column.Visibility = Visibility.Visible; //Column is Visible
I have just changed my checked and Unchecked event handlers like below. Now its working fine..:)
//Unchecked handler
void menuItem_Unchecked(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
foreach (Microsoft.Windows.Controls.DataGridColumn column in dataGrid1.Columns)
{
if (column.Header.ToString().Contains(item.Header.ToString()))
{
column.Visibility = Visibility.Collapsed;
break;
}
}
}
// Checked handler
void menuItem_Checked(object sender, RoutedEventArgs e)
{
MenuItem item = sender as MenuItem;
List<string> menuList = new List<string>();
menuList.Clear();
foreach (Microsoft.Windows.Controls.DataGridColumn column in dataGrid1.Columns)
{
if (column.Header.ToString().Contains(item.Header.ToString()))
{
column.Visibility = Visibility.Visible;
break;
}
}
}

WP7 listbox binds to second observable collection autoselection error

I have a list box which is bound to a Service. It loads fine and allows me to select an item and moves through to second page.
The Second page loads a new observable collection from the same service and uses the selected Item from previous page to load a new listbox with a data filter.
This second listbox allows for a further selection to load a details page based on this selection. The error I have is that the second listbox loads and automatically selects the first item in the list. Upon pushing the back button it loads the second listbox with no selection made.
Can someone please tell me how to stop the automatic selection in my second listbox? Code details below.
First Listbox code including sender
void ServiceReference1Client_GetMensleaderListCompleted(object sender, GetMensLeaderListCompletedEventArgs e)
{
if (e.Error != null) { MensHeading.Text = "Connect to Data"; return; }
ObservableCollection<Mens_Leaders> mensLeaders = e.Result;
this.mensRankings.ItemsSource = mensLeaders;
}
private void mensRankings_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (mensRankings.SelectedItem != null)
{
Mens_Leaders SelectedPlayer = mensRankings.SelectedItem as Mens_Leaders;
_SelectedMensPlayer = (sender as ListBox).SelectedItem;
NavigationService.Navigate(new Uri("/Pages/PlayerProfile.xaml", UriKind.Relative));
FrameworkElement root2 = Application.Current.RootVisual as FrameworkElement;
root2.DataContext = _SelectedMensPlayer;
}
}
Page where second list loads
private void LoadPlayerList()
{
Service1Client ServiceReference1Client = new Service1Client();
ServiceReference1Client.GetTournamentListCompleted += new EventHandler<GetTournamentListCompletedEventArgs>(ServiceReference1Client_GetTournamentListCompleted);
ServiceReference1Client.GetTournamentListAsync();
FrameworkElement root2 = Application.Current.RootVisual as FrameworkElement;
var currentPlayer = root2.DataContext as ATP_Tennis_App.TennisService.Mens_Leaders;
_SelectedPlayer = currentPlayer;
_selectedPlayerTournamentsWon = currentPlayer.Name;
}
void ServiceReference1Client_GetTournamentListCompleted(object sender, GetTournamentListCompletedEventArgs e)
{
if (e.Error != null) { return; }
ObservableCollection<Tournaments> tournamentList = e.Result;
viewSource = new CollectionViewSource();
viewSource.Filter += TournamentWin_Filter;
viewSource.Source = tournamentList;
this.listBox1.ItemsSource = viewSource.View;
}
void TournamentWin_Filter(object sender, FilterEventArgs e)
{
if (e.Item != null)
e.Accepted = ((Tournaments)e.Item).Prev_Male_Winner.Contains(_selectedPlayerTournamentsWon);
}
private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (listBox1.SelectedItem != null)
{
Tournaments selectedTournament1 = listBox1.SelectedItem as Tournaments;
_SelectedItemTournament = (sender as ListBox).SelectedItem;
NavigationService.Navigate(new Uri("/Pages/TournamentDetailsPanorama.xaml", UriKind.Relative));
FrameworkElement root3 = Application.Current.RootVisual as FrameworkElement;
root3.DataContext = _SelectedItemTournament;
}
else
{
return;
}
}
On the listbox, set the IsSynchroziedWithCurrentItem to False. This fixed the issue.
I know this is a dirty solution, but you can set listBox1.SelectedIndex = -1

dynamically associate a MenuItem with an item in a List

I'm using C# and I have a list of objects, and I want to show all the objects in a context menu, each object is shown as a MenuItem.
When one MenuItem is clicked, I want to refer to the associated object in the MenuItem_Click() function.
List<MyObject> MyList = new List<MyObject>();
ContextMenu menu = new ContextMenu();
foreach(MyObject o in MyList)
{
MenuItem item = new MenuItem();
item.Header = o.Name;
item.Click += MenuItem_Click;
menu.Items.add(item);
}
menu.IsOpen=true;
void MenuItem_Click(object sender, RoutedEventArgs e){
// Assume the 5th MenuItem is clicked, I need to refer to the 5th object in MyList
// how to do it?
}
A quick dirty hack that fits the code you currently have: use the Tag property.
foreach(MyObject o in MyList)
{
MenuItem item = new MenuItem();
item.Header = o.Name;
item.Tag = o;
item.Click += MenuItem_Click;
menu.Items.add(item);
}
then you can refer to it this way:
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
var myObj = (MyObject)((MenuItem)sender).Tag;
}
You could access it by
MenuItem nItem = sender as MenuItem;
var clickedItem = e.OriginalSource as MenuItem;
MyObject myObj = MyList.Find(o => o.Name == clickedItem.Header);

Opening a ContextMenu from a ToolStripMenuItem

I am trying to mimic the behavior of, for example, Windows Explorer and how the Favorites items can launch a context menu.
I currently am using:
contextMenu.Show((sender as ToolStripMenuItem).GetCurrentParent().PointToScreen(e.Location));
This occurs in the MouseDown event of the ToolStripMenuItem. The problem is that the menu closes immediately after right-click, and I don't know any way to suspend it while the context menu is open.
I've tried deriving from ToolStripMenuItem and overriding the MouseDown/MouseUp but I can't figure out how to keep it open on click.
Is there a good way of doing this?
This is what I've had luck with, it's a bit more direct:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
void MenuItemContext(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) return;
ToolStripMenuItem mID = (ToolStripMenuItem)sender;
ContextMenu tsmiContext = new ContextMenu();
MenuItem Item1 = new MenuItem();
MenuItem Item2 = new MenuItem();
Item1.Text = "Item1";
Item2.Text = "Item2";
tsmiContext.MenuItems.Add(Item1);
tsmiContext.MenuItems.Add(Item2);
Item1.Click += new EventHandler(Item1_Click);
Item2.Click += new EventHandler(Item2_Click);
hndPass = mID.Text;
tsmiContext.Show(menuStrip1, menuStrip1.PointToClient(new Point(Cursor.Position.X, Cursor.Position.Y)));
}
private String hndPass;
void Item1_Click(object sender, EventArgs e)
{
MenuItem mID = (MenuItem)sender;
MessageBox.Show("You clicked " + mID.Text + " in the context menu of " + hndPass);
}
void Item2_Click(object sender, EventArgs e)
{
MenuItem mID = (MenuItem)sender;
MessageBox.Show("You clicked " + mID.Text + " in the context menu of " + hndPass); ;
}
}
One way that you could accomplish this is by using the ToolStripDropDown control to host a ListBox inside of the ToolStripDropDown.
This may require some tweaking regarding the AutoClose behavior, but it should get you started:
First in your main form, add the following line to your ToolStripDropDropDown item
toolStripDropDownButton1.DropDown = new CustomListDropDown();
Then create a custom drop down class as follows:
public class CustomListDropDown : ToolStripDropDown
{
private ContextMenuStrip contextMenuStrip1;
private ToolStripMenuItem toolStripMenuItem1;
private ToolStripMenuItem toolStripMenuItem2;
private ToolStripMenuItem toolStripMenuItem3;
private System.ComponentModel.IContainer components;
public ListBox ListBox { get; private set; }
public CustomListDropDown()
{
InitializeComponent();
this.ListBox = new ListBox() { Width = 200, Height = 600 };
this.Items.Add(new ToolStripControlHost(this.ListBox));
this.ListBox.ContextMenuStrip = contextMenuStrip1;
this.ListBox.MouseDown += new MouseEventHandler(ListBox_MouseDown);
contextMenuStrip1.Closing += new ToolStripDropDownClosingEventHandler(contextMenuStrip1_Closing);
//add sample items
this.ListBox.Items.Add("Item1");
this.ListBox.Items.Add("Item2");
this.ListBox.Items.Add("Item3");
this.ListBox.Items.Add("Item4");
}
void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
this.Close();
this.AutoClose = true;
}
void ListBox_MouseDown(object sender, MouseEventArgs e)
{
this.AutoClose = false;
this.ListBox.SelectedIndex = this.ListBox.IndexFromPoint(e.Location);
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.contextMenuStrip1 = new System.Windows.Forms.ContextMenuStrip(this.components);
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripMenuItem();
this.toolStripMenuItem3 = new System.Windows.Forms.ToolStripMenuItem();
this.contextMenuStrip1.SuspendLayout();
this.SuspendLayout();
//
// contextMenuStrip1
//
this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.toolStripMenuItem1,
this.toolStripMenuItem2,
this.toolStripMenuItem3});
this.contextMenuStrip1.Name = "contextMenuStrip1";
//
// contextMenuStrip1.ContextMenuStrip
//
this.contextMenuStrip1.Size = new System.Drawing.Size(181, 48);
//
// toolStripMenuItem1
//
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
this.toolStripMenuItem1.Size = new System.Drawing.Size(180, 22);
this.toolStripMenuItem1.Text = "toolStripMenuItem1";
//
// toolStripMenuItem2
//
this.toolStripMenuItem2.Name = "toolStripMenuItem2";
this.toolStripMenuItem2.Size = new System.Drawing.Size(180, 22);
this.toolStripMenuItem2.Text = "toolStripMenuItem2";
//
// toolStripMenuItem3
//
this.toolStripMenuItem3.Name = "toolStripMenuItem3";
this.toolStripMenuItem3.Size = new System.Drawing.Size(180, 22);
this.toolStripMenuItem3.Text = "toolStripMenuItem3";
//
// CustomListDropDown
//
this.Size = new System.Drawing.Size(2, 4);
this.contextMenuStrip1.ResumeLayout(false);
this.ResumeLayout(false);
}
}
In my tests this worked reasonably well. Let me know how it goes.
As ContextMenuStrip is derived from ToolStripDropDown, you could do this:
private ContextMenuStrip CopyToContextMenu(ToolStripMenuItem mnuItemSource)
{
var mnuContextDestination = new ContextMenuStrip();
//Move itens from ToolStripMenuItem to ContextMenuStrip
while (mnuItemSource.DropDown.Items.Count > 0)
{
mnuContextDestination.Items.Add(mnuItemSource.DropDown.Items[0]);
}
//Put ContextMenuStrip in ToolStripMenuItem using DropDown property
mnuItemSource.DropDown = mnuContextDestination;
return mnuContextDestination;
}

Categories

Resources