WPF TextBlock.IsHitTestVisible doesn't seem to work - c#

Maybe I'm misunderstanding how this is supposed to work, but from everything I've read it's my understanding that setting the IsHitTestVisible property to false should essentially make that element "invisible" to mouse events, and MSDN states that this property "declares whether this element can possibly be returned as a hit test result".
I have a procedurally generated Grid, each cell contains a Border, and each Border's child is a TextBlock.
This is how I'm creating the cell:
var cellBorder = new Border { BorderBrush = Brushes.LightGray, Background = Brushes.WhiteSmoke, BorderThickness = thickness };
var label = new TextBlock { Text = time.ToShortTimeString(), Foreground = Brushes.Tomato, IsHitTestVisible = false };
cellBorder.Child = label;
_grid.Children.Add(cellBorder);
Grid.SetColumn(cellBorder, j);
Grid.SetRow(cellBorder, i);
In an DragMove event handler, I want to change background color of the current cell. This was working fine before I added the TextBlock to the border. It looks something like this:
void _grid_DragOver(object sender, DragEventArgs e)
{
var pos = e.GetPosition(_grid);
var result = VisualTreeHelper.HitTest(_grid, pos);
if (result != null)
{
var border = result.VisualHit as Border;
if (border != null)
border.Background = Brushes.LightYellow;
else if (result.VisualHit is TextBlock)
Console.WriteLine("Textblock hit"); // Why is this happening?
}
}
The TextBlock is getting returned from the hit test. Why?

The VisualTreeHelper does not take IsHitTestVisible into account.
If you want to omit the TextBlock from the hit test for VisualTreeHelper then you should pass filter callbacks to HitTest()

Related

Location of panel not correct when using different anchor style

this is for Winforms / C# btw.
So I am making my own ComboBox, just playing around.
The item List is basically a Panel, which is located under or above the ComboBox control, depending on its height and location.
This works as intended, as long as I use AnchorStyle Top / Left for my usercontrol.
As soon as I switch to Top / Right Style, the location of my listpanel breaks. Okay, makes sense, the location point of my usercontrol changes with the different anchorstyle, so how about I adjust my panel to a new location using my usercontrol.LocationChanged event? Doesen't work. Maybe because of the order of the events? Or does the origin of locations change depending on the given AnchorStyles?
Anyway, I am a bit lost. Unfortunately I couldn't find a similar case here, therefore this question.
Here's my DropDownPanel (effectively my "list"):
private Panel DropDownPanel()
{
Panel DropDownPanel = new Panel() {
Width = this.Width,
Height = 200,
BackColor = _skin.TextBoxBackColor,
BorderStyle = BorderStyle.FixedSingle,
ForeColor = _skin.TextBoxForeColor,
Visible = false,
AutoScroll = false
};
DropDownPanel.HorizontalScroll.Enabled = false;
DropDownPanel.HorizontalScroll.Visible = false;
DropDownPanel.HorizontalScroll.Maximum = 0;
DropDownPanel.AutoScroll = true;
DropDownPanel.Leave += DropDownPanel_Leave;
return DropDownPanel;
}
Here's my userControl Load Event:
private void GbComboBox_Load(object sender, EventArgs e)
{
_dropDownPanel = DropDownPanel();
this.Parent.Parent.Controls.Add(_dropDownPanel);
RelocateDropDownPanel();
_dropDownPanel.BringToFront();
ApplyItems(_items);
}
And my calculation for the location:
private void RelocateDropDownPanel()
{
if (_dropDownPanel != null)
{
int initLocY = this.Parent.Location.Y + this.Location.Y + this.Height + _dropDownPanel.Height;
int fullHeight = this.FindForm().Height;
Point p = new Point();
if (initLocY < fullHeight)
{
p = new Point(this.Parent.Location.X + this.Location.X, initLocY - _dropDownPanel.Height);
}
else
{
p = new Point(this.Parent.Location.X + this.Location.X, initLocY - _dropDownPanel.Height - this.Height);
}
_dropDownPanel.Location = p;
}
}
So I figured out a "solution".
I simply inherited the Anchor of my Panel from the Usercontrol it was associated to.
But I wanna mention, that still, this whole thing is kind of a crappy way of dealing with custom combobox desings. As #Jimi stated in his first comment, the correct way of doing this would be to ownerdraw the combobox. I haven't done this because of specific reasons, which didn't let me do this.
A little example on how this could be made:
Change ComboBox Border Color in Windows Forms

UWP Canvas inside Scrollviewer handle pen input like mouse input

I have a Canvas (not InkCanvas) inside a Scrollviewer. Both are not created in XAML but in code behind. I want to draw lines on my Canvas with Pen and Mouse input, everything works just fine but now I tested the whole thing with a pen as input device and the Scrollviewer seems to recognize it as touch input because the whole thing starts scrolling.
My question is: Is it possible to tell the Scrollviewer to ignore all inputs from a device type? Because it also seems like the Scrollviewer is 'eating' the events which should be fired from the Canvas.
Here my Scrollviewer init:
private void SetUpScrollViewer()
{
scroll = new ScrollViewer();
scroll.VerticalScrollMode = ScrollMode.Auto;
scroll.HorizontalScrollMode = ScrollMode.Auto;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
scroll.ZoomMode = ZoomMode.Enabled;
scroll.ManipulationMode = ManipulationModes.System;
scroll.HorizontalAlignment = HorizontalAlignment.Left;
scroll.VerticalAlignment = VerticalAlignment.Top;
scroll.IsZoomInertiaEnabled = false;
scroll.MinZoomFactor = 1;
scroll.MaxZoomFactor = 5;
}
Those are the events I use in my Canvas:
public void EnableDrawingOnCanvas(Canvas canvas)
{
//Adding the needed event handler.
canvas.PointerPressed += Canvas_PointerPressed;
canvas.PointerMoved += Canvas_PointerMoved;
canvas.PointerReleased += Canvas_PointerReleased;
canvas.PointerExited += Canvas_PointerExited;
}
And those events all check if the input device is everything but touch like this
if (e.Pointer.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Touch){...}
But with those Events I can only check the input device for my Canvas and if I add a Event to the Scrollviewer it won't get passed to the Canvas afaik.
You can bind a PointerPressed event to your ScrollViewer and check if the e.Pointer.PointerDeviceType equals PointerDeviceType.Pen. Then you can disable the VerticalScrollMode the HorizontalScrollMode and the ZoomMode like in the code below.
If you want to reactivate the ScrollViewer you can bind a PointerExited event to your ScrollViewer and reenable everything.
private void Scroll_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == PointerDeviceType.Pen)
{
scroll.VerticalScrollMode = ScrollMode.Disabled;
scroll.HorizontalScrollMode = ScrollMode.Disabled;
scroll.ZoomMode = ZoomMode.Disabled;
}
}

Hide text in comboBox

I've got a WinForms comboBox with the datasouce set to a list of a custom class. I'm displaying these items as colors (based on a property in the class) and would like to only display the color (i.e. no text). I'm displaying the items as colors in the dropdown through the DrawItem event, but this doesn't work for the comboBox itself (the part other than the dropdown). I've tried changing the ForeGround Color to Transparent, but that didn't work either. What I'd really like is a comboBox.DisplayMember = "None"; or something similar.
What is the best way to accomplish this?
Edit: So after a bit of fiddling around, I've found one solution: adding a "None" property to the class like this:
public string None
{
get
{
return "";
}
}
then I can just do the comboBox.DisplayMember = "None"; like I mentioned before. But I think the question still stands: is there a better way?
You can make a ComboBox control as a color picker to display and select colors by using DrawItem event and also there is a property called DrawMode for the ComboBox control which determines whether the Operating System or the code will handle the drawing of the items in the list. This property must be set to OwnerDrawFixed using the Properties window in order for the DrawItem event implementation to be called.
private void ColorComboBox_DrawItem(object sender, DrawItemEventArgs e)
{
Graphics g = e.Graphics;
Rectangle rect = e.Bounds;
if (e.Index >= 0)
{
Color c = Color.FromName(n);
Brush b = new SolidBrush(c);
g.DrawString(n, f, Brushes.Black, rect.X, rect.Top);
g.FillRectangle(b, rect.X, rect.Y + 5, rect.Width -10, rect.Height - 10);
}
}
You can read more about CodeProject: Color Picker Combo Box
As my "pseudo-solution" seems to be the best solution here, I'll just copy it down here:
Since the items in my comboBox are of a custom class, I added another property to that class:
public string None
{
get
{
return "";
}
}
and I set the comboBox.DisplayMember = "None";. This achieves the result I was looking for

Cannot animate the color property because the object is sealed or frozen

Ive seen other similiar issues but they alwayse seem to be doing this in XAML, since this is in an event handler I need to figure out the answer in c#. basically I just need the sending menu item to blink red.
ColorAnimation ca = new ColorAnimation()
{
From = Color.FromRgb(0, 0, 0),
To = Color.FromRgb(255,0,0),
AutoReverse = true,
RepeatBehavior = new RepeatBehavior(3),
Duration=new Duration(TimeSpan.FromSeconds(.5))
};
(sender as MenuItem).Foreground.BeginAnimation(SolidColorBrush.ColorProperty, ca);
You would have to assign a mutable SolidColorBrush instance to the element's Foreground property before it can be animated, either in XAML or in code behind:
var item = (MenuItem)sender;
item.Foreground = new SolidColorBrush(Colors.Black);
item.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, ca);
If you animate from the current color value (e.g. Black here), you don't have to set the From property of the animation.
Note also that you shouldn't use the as operator without checking whether the result is null. Better use an explicit type cast instead of as, because in case sender is not a MenuItem, you would correctly get an InvalidCastException instead of a NullReferenceException.

Any idea why my usercontrol isn't centering in my tabcontrol?

I'm a little confused as to why this isn't working, since I had it working in a prototype and the only big difference I think is that I use a custom TabItem and UserControl instead of the default ones. I'm trying to get the usercontrol that appears to be centered in the tab window, but it seems to be aligned left.
You hand this method the usercontrol you want to use and it formats it and sticks it in the tabcontrol. In a test solution I did of this earlier, setting scroll's horizontal and vertical alignment to stretch fixed this, but it's not working in this case. Is there some other setting or something else somewhere that would override this?
public void CreateNewTab(UserControlGeneric new_user_control, string tab_header)
{
//TabItem tab = new TabItem();
TabItemIndexed tab = new TabItemIndexed();
//The scrollviewer is created/setup to make sure the usercontrol gets scroll bars if the window if ever made smaller than the usercontrol
ScrollViewer scroll = new ScrollViewer();
//How you programatically set a scrollviewer's height and width to be "Auto"
scroll.Height = Double.NaN;
scroll.Width = Double.NaN;
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
scroll.HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch;
scroll.VerticalAlignment = System.Windows.VerticalAlignment.Stretch;
scroll.Content = new_user_control;
tab.Content = scroll;
tab.Header = tab_header;
//If there aren't any tabs, then hide the "No Workspaces Open" notice (Since we're adding a tab)
if (!tabControl_main.HasItems) label_no_workspaces_open.Visibility = System.Windows.Visibility.Hidden;
tabControl_main.Items.Add(tab);
tabControl_main.SelectedItem = tab;
}

Categories