I have 3 TextBox objects as children of a Canvas object, I then have that Canvas object as a child of a larger Canvas.
The TextBox objects are set as children of the child Canvas so that I can drag them around as 1 object (the child Canvas) and interact with mouse events.
How do I get the text from the TextBox objects out of the child Canvas object?
I have tried
Dim newTextbox As TextBox = childCanvas.Children(0)
but I cannot cast from a Canvas to a TextBox.
I was able to get the text from the canvas like this
Dim text As String = childCanvas.Children(0).GetValue(TextBox.TextProperty)
Related
I have a Button on a UserControl that adds an item to a ListBox on that UserControl. Let's call that control Parent. The ListBoxItems contain another UserControl. Let's call that Child. The button adds an item to the ItemSource of the listbox (MVVM style).
I can scroll that into view without a problem. I can set the focus to the ListBoxItem, but what I want is the focus to be set on the first TextBox of the child UserControlof the content of the ListBoxItem. I can't seem to figure that out. The code below sets the focus to the ListBoxItem, not the UserControl child of it or any control on it.
Private Sub bnAdd(sender As Object, e As RoutedEventArgs)
VM.AddDetail()
MyList.ScrollIntoView(MyList.Items(MyList.Items.Count - 1))
Dim ListBoxItem As ListBoxItem = MyList.ItemContainerGenerator.ContainerFromItem(MyList.SelectedItem)
ListBoxItem.Focus()
End Sub
On my child UserControl I used this in XAML:
FocusManager.FocusedElement="{Binding ElementName=txtMyBox}"
There is a related question here and most of the approaches use hooking into focus events to achieve the focus change. I want to propose another solution that is based on traversing the visual tree. Unfortunately, I can only provide you C# code, but you can use the concept to apply it in your Visual Basic code.
As far as I can see, you are using code-behind to scroll your items into view. I will build on that. Your list box has list box items and I guess you use a data template to display UserControls as child items. Within these user controls there is a TextBox that you have assigned a name in XAML via x:Name or in code-behind via the Name property. Now, you need a helper method to traverse the visual tree and search for text boxes.
private IEnumerable<TextBox> FindTextBox(DependencyObject dependencyObject)
{
// No other child controls, break
if (dependencyObject == null)
yield break;
// Search children of the current control
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
// Check if the current item is a text box
if (child is TextBox textBox)
yield return textBox;
// If we did not find a text box, search the children of this child recursively
foreach (var childOfChild in FindTextBox(child))
yield return childOfChild;
}
}
Then we add a method that filters the enumerable of text boxes for a given name using Linq.
private TextBox FindTextBox(DependencyObject dependencyObject, string name)
{
// Filter the list of text boxes for the right one with the specified name
return FindTextBox(dependencyObject).SingleOrDefault(child => child.Name.Equals(name));
}
In your bnAdd handler you can take your ListBoxItem, search for the text box child and focus it.
var textBox = FindTextBox(listBoxItem, "MyTextBox");
textBox.Focus();
wpf
I have a control A, (an inkcanvas), within a Grid within a ScrollViewer. Conrol A is taller then the physical window, so the ScrollViewer correctly adds a vertical scroll bar and the entire control can be viewed by scrolling down. When attaching an Adorner with a control B, (another inkcanvas), to control A, scrolling downward shows the Adorner to be cut off at the bottom of the screen. That is, the Adorner is not completely covering the adorned element and/or is not extended downward when scrolling.
How do I get the Adorner (the control) to completely cover the adorned element and respect the ScrollViewer. (I need a one-to-one match between the pixels of the Adorner control and the adorned element within the ScrollViewer).
TIA
Edit#1: The key line in the Adorner that sets the background of the InkCanvas is
_inkcanvas.Background = CreateGrid();
public InkCanvasTextAdorner(InkCanvas element)
: base(element)
{
_element = element;
_visuals = new VisualCollection(this);
_inkcanvas = new InkCanvas();
_inkcanvas.Background = CreateGrid();
_visuals.Add(_inkcanvas);
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
adornerLayer.Add(this);
}
If an InkCanvas is used (as the above) the Adorner's background is clipped at the bottom. The adorner control, however, does continue to the bottom of the adorned element.
However, if a Canvas is used instead of the InkCanvas, the Adorner's background does extend to the bottom of the adorned element.
What's wrong?
I'm guessing that the difference in the Background property expanding past the physical screen with the Canvas and not the InkCanvas may be because the Canvas inherits from Panel whereas the InkCanvas does not. Based on the finding that the Canvas background does do what I need, I find the below code does accomplish what I want--the canvas allows images from layers beneath it to be seen yet posts a grid of lines overwhich the InkCanvas will accept strokes. All is well :)
public InkCanvasTextAdorner(InkCanvas element)
: base(element)
{
_element = element;
// The VisualCollection has only one visual parent. I.e. InkCanvasTextAdorner is the parent to the VisualCollection.
// By overriding default rendering behavior of the VisualCollection, any kind of control and its children can be placed in the Adorner.
_visuals = new VisualCollection(this);
_inkcanvas = new InkCanvas();
_inkcanvas.Background = Brushes.Transparent;
_canvas = new Canvas();
_canvas.Background = CreateGrid();
_grid = new Grid();
_grid.Children.Add(_canvas);
_grid.Children.Add(_inkcanvas);
// The _grid is a logical child of the VisualCollection of the Adorner. The ArrangeOverride and MeasureOverride will set up the Grid control.
_visuals.Add(_grid); // Adding a single control for display.
// AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(element);
adornerLayer.Add(this);
}
Which looks like:
I have two displays. One resides inside a UserControl and the other one is a Rectangle. I am passing the Rectangle as a parameter to a UserControl method. Now inside my ViewModel Method, I want to combine this Rectangle with the UserControl display. How can I achieve this combined display?
ViewModel Code -
private UserControl CreateCombination(Rectangle rect)
{
//This UserControl contains one its display (basically a combination of few controls)
CombinedUC combination = new CombinedUC();
// I want to write some code here so that I can place combination object just above my rectangle (rect).
return combination;
}
Hi I have contentControl in my user control. I am applying style to this contentControl which consist of TextBlock and ListBox. I am binding text of the textBlock to CategoryName(from Tag of the control). I want to bind category's child items to listBox. I have set ContentControl's dataContext property to child items[]. Now how to bind these child items to listbox which is in resource.
In loaded event of the user control
Panel pnl = sender as Panel;
Category category = panel.Tag as Category;
Items[] items = GetChildItemsByCategoryId(category.CategoryID);
mainContent.DataContext = items;
If the control is in the visual tree of mainContent, simply set in code or XAML
ItemsSource={Binding}
Hi i would like to add Tool Tip to ViewPort3D child elements when i put my mouse over on it, Only viewPort3D has a tooltip property but not for their childs. Any way to work around it?
I was able to get a partial solution by adding a canvas with a textblock inside to hold my text. Like this...
<Grid>
<Canvas>
<TextBlock Name="txtblkTip" TextAlignment="Center" Padding="2" />
</Canvas>
<Viewport3d ...
...
</Viewport3d>
</Grid>
Then as the user moves the mouse over an object in viewport3d I use the following mouse event handler to redraw the tooltip at the required location, based on the HitTest method.
Private Sub viewport_PreviewMouseMove(ByVal sender As Object, ByVal e As System.Windows.Input.MouseEventArgs) Handles viewport.PreviewMouseMove
Dim ptMouse As Point = e.GetPosition(viewport)
Dim result As HitTestResult = VisualTreeHelper.HitTest(viewport, ptMouse)
If TypeOf result Is RayMeshGeometry3DHitTestResult Then
Dim result3d As RayMeshGeometry3DHitTestResult = CType(result, RayMeshGeometry3DHitTestResult)
If TypeOf result3d.VisualHit Is Sphere Then
If CType(result3d.VisualHit, Sphere).Name <> "" Then
'Position the Canvas near the mouse pointer
Canvas.SetLeft(txtblkTip, ptMouse.X + 12)
Canvas.SetTop(txtblkTip, ptMouse.Y + 12)
txtblkTip.Text = CType(result3d.VisualHit, Sphere).Name
End If
End If
End If
End Sub
One thing I have not been able to get is an event when the mouse moves off all objects in the Viewport, to remove the tooltip, but I suspect this could be done with a storyboard.
Hope this helps you along the way.
XamTrix's answer works with the addition of a MouseLeave event handler that sets the visibility of the textblock to Visibility.Collapsed (the visibility of the textblock
must also be reset to Visible in the PreviewMouseMove event handler).
Also, if the Canvas is placed after the Viewport3d instead of before it, the textblock
will appear above the Viewport3d elements. In this case the Canvas.SetLeft statement
should be changed to: ptMouse.X + 12 - viewport3d.actualWidth.