PreviewMouseDownEvent of Listbox blocking Command from Button - c#

In my main view I have a Listbox for which I set (among others) the PreviewMouseLeftButtonDownEvent that I use to support drag and drop re-ordering.
var style = ListBox.ItemContainerStyle;
style.Setters.Add(new Setter(AllowDropProperty, true));
style.Setters.Add(new EventSetter(PreviewMouseLeftButtonDownEvent,
new MouseButtonEventHandler(Input_Down)));
private void Input_Down(object sender, EventArgs e)
{
if (!(sender is ListBoxItem))
return;
var draggedItem = sender as ListBoxItem;
isDragging = true;
StartDrag(draggedItem);
}
private void StartDrag(ListBoxItem draggedItem)
{
draggedItem.IsSelected = true;
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
}
In the ListBox.ItemTemplate there is a button with an Update command:
<Button Command="{Binding Path=UpdateCommand}" Content="Button"/>
However, the command is never triggered when I set the PreviewMouseLeftButtonDownEvent. If I remove the PreviewMouseLeftButtonDownEvent setter, the command works fine. Any ideas on why this is and how I can use both?

The DragDrop.doDragDrop() operation seems to block all underlying events, meaning that the commands from the buttons that are clicked are not fired.
Since I did not find any clean way of doing this, I decided to go for a hack. In the event handler of the ListBox.ItemContainerStyle I check if the original source in the RoutedEventArgs is a Button with an ICommand attached to it. If so, I abort the DragDrop.doDragDrop() procedure:
style.Setters.Add(new EventSetter(PreviewMouseLeftButtonDownEvent,
new MouseButtonEventHandler(Input_Down)));
private void Input_Down(object sender, RoutedEventArgs e)
{
if (EventTriggeredByButtonWithCommand(e))
return;
var draggedItem = sender as FrameworkElement;
if(draggedItem !=null)
StartDrag(draggedItem);
}
bool EventTriggeredByButtonWithCommand(RoutedEventArgs e)
{
var frameWorkElement = e.OriginalSource as FrameworkElement;
if (frameWorkElement == null)
return false;
var button = frameWorkElement.TemplatedParent as Button;
if (button == null)
return false;
return button.Command != null;
}

Related

WPF Raise DoubleClick Event

I have a class derived from WindowsFormsHost that listens to WinForms mouse events. It works fine for single clicks but is there any way to trigger double client events? ClickCount is read-only so I can't set it, and raising Control.MouseDoubleClickEvent doesn't propagate it. Any other idea?
private void OnMouseDown(object sender, System.Windows.Forms.MouseEventArgs e) {
MouseButton? wpfButton = ConvertToWpf(e.Button);
if (!wpfButton.HasValue)
return;
RaiseEvent(new MouseButtonEventArgs(Mouse.PrimaryDevice, 0, wpfButton.Value) {
RoutedEvent = Mouse.MouseDownEvent,
Source = this
//ClickCount = 2 // read-only
});
//RaiseEvent(new RoutedEventArgs() { // won't propagate
// RoutedEvent = System.Windows.Controls.Control.MouseDoubleClickEvent,
// Source = this
//});
}
Here is you would raise a MouseDoubleClickEvent programmatically in WPF:
MouseButtonEventArgs doubleClickEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, (int)DateTime.Now.Ticks, MouseButton.Left);
doubleClickEvent.RoutedEvent = Control.MouseDoubleClickEvent;
doubleClickEvent.Source = this;
RaiseEvent(doubleClickEvent);

Indirect reference to a button

I'm having this code:
private void b9_Click(object sender, EventArgs e)
{
b9.Enabled = false;
color = 8;
}
The problem is that i'm having a lot of buttons for disabling. Is there a chance i can use something like:
this.Enabled=false;
Probably that is what you want
private void OnClick(object sender, EventArgs e)
{
if( sender is Button )
{
Button button = (Button)sender;
button.Enabled = false;
}
}
Use this routine for every button you need to disable on click.
It is known as single event handler for multiple controls. Just put following event handler for your buttons as many as you like.
public void Button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
button.IsEnable = false;
// If you want to access text in the button
... = button.Content as object;
}
private void OnClick(object sender, EventArgs e)
{
Button btn = sender as Button; // if sender is not a Button, btn will be null
if (btn != null)
{
btn.Enabled = false;
}
}
If you want to apply the same behaviour to any clickable control, you can use Control class instead of Button. Button inherits from Control and the property Enabled is defined in Control class.
private void OnClick(object sender, EventArgs e)
{
Control ctrl = sender as Control; // if sender is not a Control, ctrl will be null
if (ctrl != null)
{
ctrl .Enabled = false;
}
}
Also, if you want to go one step further, you can create a method that disables the clicked control. Something like this:
private void DisableControl(object sender)
{
Control ctrl = sender as Control;
if (ctrl != null)
{
ctrl.Enabled = false;
}
}
Then, you can call this method from the Click even handler like this:
private void OnClick(object sender, EventArgs e)
{
DisableControl(sender);
}

ButtonClick to get an Object on SelectionChanged event

I have a SelectionChanged event and works perfectly, but I want to figure out how to "catch" this selected item at the click of a button they need to pass it as parameter to another page and edit this Item. Here's the current code and button SelectionChanged I still implemented because this is what I need.
private void listCarros_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ListBox listBox = sender as ListBox;
if (listBox != null && listBox.SelectedItem != null)
{
//pega o Carro que foi selecionado
Carro sCar = (Carro)listBox.SelectedItem;
btnEditCar.IsEnabled = true;
btnDeleteCar.IsEnabled = true;
}
else
{
btnEditCar.IsEnabled = false;
btnDeleteCar.IsEnabled = false;
}
}
I need to edit the selectedItem on this button:
private void btnEditCar_Click(object sender, EventArgs e)
{
//Here I need access to the selectedItem on SelectionChanged event.
}
If you could also tell me how to pass the object as parameter would be perfect.
You can do this with binding also
1.Bind ListBoxItem(Carro Object) to the tag of "btnEditCar" in xaml.
Xaml should be like this
<Button Name="btnEditCar" OnClick="btnEditCar_Click" Tag="{Binding}"/>
and now in
private void btnEditCar_Click(object sender, EventArgs e)
{
Carro sCar=(Carro)((sender as FrameworkElement).Tag)
}
This is the good practice,creating a class variable only for temporary purpose is hack
To give a better idea on my comments. Creating a class level variable is like this:
Notice that sCar is declared outside the method, but within the class.
Carro sCar = new Carro();
private void listCarros_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ListBox listBox = sender as ListBox;
if (listBox != null && listBox.SelectedItem != null)
{
sCar = (Carro)listBox.SelectedItem;
...
private void btnEditCar_Click(object sender, EventArgs e)
{
sCar.ProperyYouWantToChange = "Stuff I want to change"
}

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

How to return the selected tab item's control in the container

I had a old windows form WebBrowser and I had:
public WebBrowser getCurrentWebBrowser()
{
return (WebBrowser)TabControl.SelectedTab.Controls[0];
}
I want to know how to do the same thing in WPF.
Thanks for any help.
You can hook the TabContols' SelectionChanged event and then have code like this in the callback...
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
HeaderedContentControl hcc = e.AddedItems[0] as HeaderedContentControl;
if (hcc != null)
{
WebBrowser webBrowser = hcc.Content as WebBrowser;
if (webBrowser != null)
{
// do something...
}
}
}
If you have a WebBrowser in more than one tab, you can name the TabItems and adapt your callback thusly...
<TabItem Header="Browser" Name="MyBrowserTabItem">
<WebBrowser/>
</TabItem>
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
HeaderedContentControl hcc = e.AddedItems[0] as HeaderedContentControl;
if (hcc != null && hcc.Name == "MyBrowserTabItem")
{
WebBrowser webBrowser = hcc.Content as WebBrowser;
if (webBrowser != null)
{
// do something...
}
}
}
The 'AddedItems' property of the SelectionChangedEventArgs is a list of objects that have been selected since the last time the event was fired. For a TabControl, AddedItems should normally have a length of 1, and the single element should be an instance of HeaderedContentControl (i.e., the TabItem).

Categories

Resources