WPF Button event not firing while Grid have PreviewMouseMove set - c#

I have button on the Grid that does not detects PreviewMouseLeftDown click event.
After some testing I figured that the problem is in <Grid PreviewMouseMove="onMouseMove" >
If I remove PreviewMouseMove="onMouseMove" part, then MouseDown event is detected, but i need that line of code, since I also have to detect mouse position inside that grid only.
XAML:
<Grid PreviewMouseMove="onMouseMove" Background="Transparent">
<ItemsControl Name="btnTableImageList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Content}"
Height="{Binding Height}"
Width="{Binding Width}"
Tag="{Binding Tag}"
Margin="{Binding Margin}"
Background="{Binding Background}"
HorizontalAlignment="Center"
PreviewMouseLeftButtonDown ="tblButton_MouseDown"
PreviewMouseLeftButtonUp ="tblButton_MouseUp"
Click="ClickHandlerTableBtn"
TextBlock.TextAlignment="Center" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Any idea is welcomed. Thanks!

I totally agree with themightylc, but also understand you... WPF and MVVM are not so "easy" to get used to, I do it for a year more or less, and still have a lot to learn.
In that kind of situation I only could advise you to read some tutorials about WPF, DataBinding and ObservableCollection and ViewModel (these are the keywords you need to know).
1) Create a ViewModel where you can define a ObservableCollection, ObservableCollection is kind of list, but using it you can update your View (almost) automaticaly.so when you launch your application, you will read the list of buttons you need to display, then add them to the ObservableCollection
for your tests will be something like that :
Button button1=new Button();
Button button2=new Button();
//define all dimensions/parameters of your button
MyObservableCollection.Add(button1);
MyObservableCollection.Add(button2);
Then in XAML you just need to specify the ItemsSource of ItemsControls(MyObservableCollection). doing like that you don't need anymore all description of buttons inside.
Then when you click to add a button(in your case), you just need to make in code behind something like
Button newButton=new Button();
newButton.Height=defaultHeight...//width, background etc...
MyObservableCollection.Add(newButton);
again, just for advise if WPF/MVVM is new to you, I would advise to begin with easier samples, make a small listview with simple objects inside, or a listbox.
Could also advise you these websites :
wpf-tutorial.com
www.wpftutorial.net

At the end this is actually working properly.
For test I have set up a label, and in MouseMove event i am sending Mouse Position to that label,lblCoord.Content = Mouse.GetPosition(Application.Current.MainWindow);
In case of MouseClick I am sending lblCoord.Content="MouseClick";
And in case of MouseDown I am sending lblCoord.Content="MouseDown";.
I can see mouse coordinates in lblCoord, I can see MouseClick, but it never displayed MouseDown.
However, if i call MessageBox inside MouseDown event, everything works. So i guess that XAML <Grid> PreviewMouseMove="onMouseMove" works even when I am not moving mouse so it is sending coords to a Label all the time and overwrites lblCoord.Content="MouseDown"; faster than I am able to see it.
The answer to this question is: Don't work with WPF and expect WinForms results...
Thanks to everybody for their time and effort!

Related

Pointer events not triggered on UI Elements in custom control

I am creating an application with a UserControl containing multiple UI Elements. The UserControl is rendered into a StackPanel using ItemsControl since the number of UserControls to be rendered depends on user's input.
The basic XAML in the UserControl is as follows.
<Grid x:Name="Viewport" VerticalAlignment="Top" HorizontalAlignment="Center">
<Border x:Name="ViewportBorder" Background="White" BorderThickness="2, 2, 2, 2" BorderBrush="#FF353334" />
<Image x:Name="Image" Margin="0" UseLayoutRounding="True" ManipulationMode="Scale"/>
<InkCanvas x:Name="InkCanvas" />
<Canvas x:Name="SelectionCanvas" CompositeMode="SourceOver" />
</Grid>
I want to change the cursor icon when user is hovering over the SelectionCanvas (based on a condition check in my case as you might see in the source). It seemed pretty straight forward so I tried to use PointerEntered & PointerExited events to capture & release the pointer from the SelectionCanvas. And PointerMoved to change the cursor icon. But it seems that none of the events were triggering.
I tried binding to the Viewport grid element as well but no luck in that too.
I'm not sure what I missed here. Could someone please help me on this? Any help is much appreciated. Please find the complete source code here.
Please note that a sample PDF is included into the startup project /Resources which you'll have to open from the app.
The PointerEntered and PointerExited events are raised provided that the area that is supposed to raise them is painted so try to set the Background property of the Canvas to some brush like for example Transparent:
<Canvas x:Name="SelectionCanvas" CompositeMode="SourceOver"
Background="Transparent"
PointerEntered="SelectionCanvas_PointerEntered"
...

ScrollViewer jumps to the top when TextBox child loses focus

I'm having a weird UI issue in my app, where a ScrollViewer jumps to the top as soon as a TextBox child loses focus. I've already tried to set BringIntoViewOnFocusChange="False" in the parent ScrollViewer, but that doesn't solve the issue unfortunately.
Here's a quick video that shows the problem I have:
As you can see, every time the top TextBox is focused, the ScrollViewer jumps back to the top as soon as it loses focus (ie. whenever I tap on an item in the ListViews below. This also happen if I click on one of those ComboBox controls: the ScrollViewer still jumps back immediately.
This is the general structure of the contents of the Popup your're seeing:
<UserControl>
<RelativePanel HorizontalAlignment="Stretch">
<!--Item name-->
<TextBlock Text="Name"/>
<customControls:TextBoxActionButton/>
<customControls:TextValidatorControl/>
<!--Section selector-->
<TextBlock Text="Section"/>
<customControls:ComboBoxWithResetButton/>
<!--Item GroupName-->
<TextBlock Text="Group"/>
<customControls:ComboBoxWithResetButton/>
<!--Template based on-->
<TextBlock Text="Based on"/>
<customControls:ComboBoxWithResetButton/>
<!--Icons list and description-->
<TextBlock Text="Icon"/>
<ListView ScrollViewer.VerticalScrollMode="Disabled"/>
<!--Select color text-->
<TextBlock Text="Select color"/>
<ListView ScrollViewer.VerticalScrollMode="Disabled"/>
</RelativePanel>
</UserControl>
I don't have any code that interacts with the parent ScrollViewer, which is in a completely different UserControl, along with the rest of the Popup UI (header, buttons at the bottom etc..).
I've also tried to subscribe to the LosingFocus event of the first TextBox, and to set e.Handled = true; from there, but that didn't work too.
Do you have any idea on why this is happening? And also, why doesn't the BringIntoViewOnFocusChange="False" property work in this situation?
Thanks!
I think the problem is the TextValidatorControl which causes the TextBox to regain focus, because this does not seem to happen when the control is not there.
Please verify what happens if you actually enter a valid name. If the behavior stops, I would suggest you to invetigate or post the source code of TextValidatorControl, because it looks like the source of the problems.

WPF C# Button Binding and TextBox to Button Binding

I am fairly new to WPF and have two questions?
Question #1:
From my XAML snip below, by button "btnRed" word's fine with my code behind. When the button is clicked, the proper view is display. However, how does one perform the same thing "programmatically"? Hence, my next question.
Question #2:
I am not sure how to make a "textbox" and "button" work together to perform the same action. What I'm trying to do is this. (1) I would like the textbox to be linked to the "DataContext" of the button, "btnDisplayView". (2) so when I type in, say, "RedView" into the textbox and click the button, the correct view is displayed.
My long term goal is to have a database, with a couple of tables. A table for "MenuItems" and a table for "Views". Instead of using buttons, I'll use the menu control. Then once a menu item is selected, it would display the correct view.
But for now, I'm startings small and trying to keep it simple:
--------- WPF - XAML START ---------------------------
<StackPanel Grid.Column="0" Orientation="Vertical">
<TextBox x:Name="txtDisplayView" Height="23" Margin="5" TextAlignment="Center"/>
<Button x:Name="btnDisplayView" Content="Display" Margin="5" Click="btnDisplay_Click"/>
<Button x:Name="btnRed" Content="Red" Margin="5" DataContext="RedView" Click="Red_Click"/>
</StackPanel>
<StackPanel Grid.Column="1" Orientation="Vertical">
<ContentControl Margin="5" Content="{Binding}"/>
</StackPanel>
-----------WPF - XAML END -------------------------
If someone could show me how to get this to work, it would help me move my project in the right direction and would be greatly appreciated.
What you need here is:
Create a property in your DataContext that represents the selected item
Bind that property to your TextBox element
Now, you have two options. One is "WPF Friendly" and the other is more Windows Forms-ish:
Create a command (take a look at this article) that reads a parameter, which will be binded to the property you created before
On the Click event, you can read the binded property value
I personally prefer the first solution. Why? Because when you change it to a Menu, for example, your work will be only to populate the menu with your list items (the MenuItem class also has a Command property, so the implementation is the same as with a Button). You will only need to change the source!

Nullpointer error on event listeners when using StaticResource and MouseDown handler

I have a very odd error case that sprung up the moment I used a StaticResource converter on a Rectangle for coloring its background and at the same time using a MouseDown handler on another component next to it within a DataTemplate. If I narrow the code down a bit, this is what is required to reproduce the error :
In the top I have these resources, one pointing to a converter that takes the boolean from the binding and converts it to a fill background color):
<Window.Resources>
<vm:DesktopViewModel x:Key="DesktopVM" />
<vm:BooleanToColorConverter x:Key="converter" />
</Window.Resources>
And later in the same xaml file I iterate over a list of Alarm objects using this (I have replaced a Grid layout with a StackPanel and removed some other components for shorter code sample, this code snippet below still fails):
<ItemsControl ItemsSource="{Binding Alarms}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Rectangle Height="20" Stroke="Black" Width="20" RadiusX="4" RadiusY="4" Fill="{Binding Alarm, Converter={StaticResource converter}}"/>
<Image Source="/MyNamespace;component/images/chart.png" Stretch="None" MouseDown="Image_MouseDown" Cursor="Hand"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If I remove the MouseDown handler on the image it runs just fine without the nullpointer error in the start. If I remove the Fill tag in the Rectangle the code works just fine WITH the MouseDown handler!!! (and the handler works just fine too). It seems like the StaticResource reference in Fill is messing up something that makes locating the mouse handler function fail?!?
Note that it fails when the window is created, not while running or clicking anything.
Edit: I had the same nullpointer issue if I replaced the converter with a style using a StaticResource with triggers to do the same as the converter. Its pretty clear that the StaticResource reference in an attribute is the culprit but I have no idea why it should affect the event listener.
Also the order of the compoents dont matter either. If I place the Image before the Rectangle the error is exactly the same.
My guess is that the problem is in your converter code, that it does not take into account that it can get a null value.
Why the effect of the mouseDown? Probably it causes the rendering of the image element at an earlier moment and to request the value of the Fill property at a moment that your ViewModel has not been created yet.
There is too little information to state it with certainty, but converters that do not handle null values properly can be a major pain in WPF development in my experience. A lot of design time instability has had root in converters that did not handle the null values properly.

ContentControl With ScrollViewer, Focus

In my Windows 8 Metro project, I'm using a class derived from ContentControl (let's call it MyControl) to present my content. Inside MyControl I have a ScrollViewer. Because I want my control to handle keyboard events, I need to be able to set the focus to my control. However, I also want the option to let the scrollviewer handle keyevents, such as arrow keys and PageUp/Down. More precisely, I want this to be an option that another programmer can turn on or off. This means that sometimes, I want MyControl to be a tab-stop, and sometimes I want ScrollViewer to be a tab-stop, but never both.
The issue is that I don't want to expose the inner workings of MyControl to other programmers. That is, they ideally should be able to use MyControl.IsTabStop and leave the logic of placing the actual tab-stop with my Control (to put in MyControl or ScrollViewer).
Is there any good way to achieve this, or do I somehow have to work around it by providing a separate function to make my control a tab stop?
If you look at my test XAML you'll see I'm doing nothing, yet the up/down keys in the TextBox work to go between lines of text and they scroll the ScrollViewer when there is no line of text to go to. This is likely achieved by the KeyDown handlers setting the e.Handled value to true when they don't want the key event to bubble up (as when the TextBox already handled it) and leaving it false when the event is not handled, which lets the ScrollViewer handle it. The event will always trigger on the TextBox if it has focus, but it bubbles up the visual tree if it is not handled. It does not seem that you have to do anything more than just deciding whether you want to mark the key events as handled or not.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer
IsTabStop="True">
<Grid
Width="2000"
Height="2000">
<Button
Margin="149,342,0,311">
<Button>
<TextBox
AcceptsReturn="True"
Height="400"
Width="200"/></Button>
</Button>
</Grid>
</ScrollViewer>
</Grid>

Categories