WinUi3 how to get Elements inside dataTemplate - c#

This is my xaml code, a NavigationView contains a NavigationView.HeaderTemplate.
<NavigationView.HeaderTemplate>
<DataTemplate
x:Name="HeaderDataTemplate">
<TextBlock
Name="HeaderText"
Text="I am a TextBlock"
Margin="0,0,0,10"/>
</DataTemplate>
</NavigationView.HeaderTemplate>
I want to know how to get the Texkblock through c# code.
Here is my c# code bu it doesn't work.
private void nvSample_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
var navView = sender as NavigationView;
NavigationViewItem item = args.SelectedItemContainer as NavigationViewItem;
if(item.Tag.ToString() == "SatrtPage")
{
DataTemplate dataTemplate = sender.HeaderTemplate;
DependencyObject dio = dataTemplate.LoadContent();
var rectangle= FindVisualChild<TextBlock>(dio);
if (rectangle != null)
{
rectangle.Text = "LLLLLLL";
}
contentFrame.Navigate(typeof(StartPage));
}
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
{
return (childItem)child;
}
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}

Try this:
private void nvSample_SelectionChanged(NavigationView sender, NavigationViewSelectionChangedEventArgs args)
{
var navView = sender as NavigationView;
if (FindVisualChild<SplitView>(navView) is SplitView splitView
&& splitView.Content is Panel panel
&& panel.Children.OfType<ContentControl>().FirstOrDefault() is ContentControl cc)
{
var textBlock = FindVisualChild<TextBlock>(cc);
if (textBlock != null)
textBlock.Text = "changed text...";
}
}

Related

Create a childnode in TreeView from right click

This is the code I have set up for binding the TreeView from a Tree data structure in my code:
public class ExtendedTreeView : TreeView
{
public ExtendedTreeView()
: base()
{
this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(___ICH);
}
void ___ICH(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (SelectedItem != null)
{
SetValue(SelectedItem_Property, SelectedItem);
}
}
public object SelectedItem_
{
get { return (object)GetValue(SelectedItem_Property); }
set { SetValue(SelectedItem_Property, value); }
}
public static readonly DependencyProperty SelectedItem_Property = DependencyProperty.Register("SelectedItem_", typeof(object), typeof(ExtendedTreeView), new UIPropertyMetadata(null));
}
With this in the xaml:
<local:ExtendedTreeView ItemsSource="{Binding Items}" SelectedItem_="{Binding Item, Mode=TwoWay}">
.....
<xn:ExtendedTreeView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add New"/>
</ContextMenu>
</xn:ExtendedTreeView.ContextMenu>
</local:ExtendedTreeView>
This works for getting the left clicked item, but I how do I get the right clicked item so that I can show a context menu and allow user to add/modify a child node at that level in the tree?
Refer the below code which gives the RightClickedItem.
public class ExtendedTreeView : TreeView
{
public ExtendedTreeView()
: base()
{
this.SelectedItemChanged += new RoutedPropertyChangedEventHandler<object>(___ICH);
this.PreviewMouseRightButtonDown += ExtendedTreeView_PreviewMouseRightButtonDown;
}
void ___ICH(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (SelectedItem != null)
{
SetValue(SelectedItem_Property, SelectedItem);
}
}
void ExtendedTreeView_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeViewItem treeViewItem =
VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject);
if (treeViewItem != null)
{
SetValue(RightClickedItem_Property, treeViewItem.DataContext);
e.Handled = true;
}
}
static T VisualUpwardSearch<T>(DependencyObject source) where T : DependencyObject
{
DependencyObject returnVal = source;
while (returnVal != null && !(returnVal is T))
{
DependencyObject tempReturnVal = null;
if (returnVal is Visual || returnVal is Visual3D)
{
tempReturnVal = VisualTreeHelper.GetParent(returnVal);
}
if (tempReturnVal == null)
{
returnVal = LogicalTreeHelper.GetParent(returnVal);
}
else returnVal = tempReturnVal;
}
return returnVal as T;
}
public object RightClickedItem_
{
get { return (object)GetValue(RightClickedItem_Property); }
set { SetValue(RightClickedItem_Property, value); }
}
public static readonly DependencyProperty RightClickedItem_Property =
DependencyProperty.Register("RightClickedItem_", typeof(object), typeof(ExtendedTreeView), new PropertyMetadata(null));
public object SelectedItem_
{
get { return (object)GetValue(SelectedItem_Property); }
set { SetValue(SelectedItem_Property, value); }
}
public static readonly DependencyProperty SelectedItem_Property = DependencyProperty.Register("SelectedItem_", typeof(object), typeof(ExtendedTreeView), new UIPropertyMetadata(null));
}
Reference:Select TreeView Node on right click before displaying ContextMenu

FindVisualChild reference issue

I have found and modified following code in order to export my dataGrid to a pdf document using iTextSharp class.
private void ExportToPdf(DataGrid grid)
{
PdfPTable table = new PdfPTable(grid.Columns.Count);
using (Document doc = new Document(iTextSharp.text.PageSize.A4))
{
using (PdfWriter writer = PdfWriter.GetInstance(doc, new System.IO.FileStream("Test.pdf", FileMode.Create)))
{
doc.Open();
for (int j = 0; j < grid.Columns.Count; j++)
{
table.AddCell(new Phrase(grid.Columns[j].Header.ToString()));
}
table.HeaderRows = 1;
IEnumerable itemsSource = grid.ItemsSource as IEnumerable;
if (itemsSource != null)
{
foreach (var item in itemsSource)
{
DataGridRow row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (row != null)
{
DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
for (int i = 0; i < grid.Columns.Count; ++i)
{
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock txt = cell.Content as TextBlock;
if (txt != null)
{
table.AddCell(new Phrase(txt.Text));
}
}
}
}
doc.Add(table);
doc.Close();
}
}
}
}
The problem occurs in the following line:
DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
Visual Studio returns following error 'The name 'FindVisualChild' does not exist in the current context'. How do I add this parameter ?.
FindVisualChild method is not provided by WPF framework, you have to add them. May be you want this:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj)
where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
public static childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
foreach (childItem child in FindVisualChildren<childItem>(obj))
{
return child;
}
return null;
}
Add these methods in some utility class so they can be reuse.
Also a common practice is to use these methods (posted by Rohit Vats) as extension methods, like this:
static class Utils
{
public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj)
where T : DependencyObject
{
...
}
public static childItem FindVisualChild<childItem>(this DependencyObject obj)
where childItem : DependencyObject
{
...
}
}
And then in your code:
using Utils;
class MyCode
{
public static DataGridCellsPresenter GetPresenter(DataGridRow row)
{
return row.FindVisualChild<DataGridCellsPresenter>();
}
}

Reorder ItemsControl with Drag and Drop using MVVM

I recently asked a question on how to reorder an ItemsControl using Drag and Drop (ItemsControl Drag and Drop). The answer worked great for the time being (code below) but now I am trying to implement MVVM and the current solution requires access to items in the view. Any ideas how to change this to work with MVVM? I plan to make attached properties to bind to commands but I don't know how to get rid of lines such as: int index = (int)(e.GetPosition(DimsContainer).X / width);
Current drag and drop code:
private void DimsContainer_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_isDown = true;
_startPoint = e.GetPosition(this.DimsContainer);
}
private void DimsContainer_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_isDown = false;
_isDragging = false;
if (_realDragSource != null)
{
_realDragSource.ReleaseMouseCapture();
}
}
private void DimsContainer_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (_isDown)
{
if ((_isDragging == false) &&
((Math.Abs(e.GetPosition(this.DimsContainer).X - _startPoint.X) >
SystemParameters.MinimumHorizontalDragDistance) ||
(Math.Abs(e.GetPosition(this.DimsContainer).Y - _startPoint.Y) >
SystemParameters.MinimumVerticalDragDistance)))
{
_isDragging = true;
_realDragSource = e.Source as UIElement;
_realDragSource.CaptureMouse();
double width = ((FrameworkElement)(this.DimsContainer.ItemContainerGenerator.ContainerFromIndex(0))).ActualWidth;
int index = (int)(e.GetPosition(DimsContainer).X / width);
DragDrop.DoDragDrop(_realDragSource, new DataObject("UIElement", index, true), DragDropEffects.Move);
}
}
}
private void DimsContainer_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("UIElement"))
{
e.Effects = DragDropEffects.Move;
}
}
private void DimsContainer_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent("UIElement"))
{
int sourceIndex = (int)e.Data.GetData("UIElement");
int removedObject = this.indices[sourceIndex];
this.indices.RemoveAt(sourceIndex);
UIElement droptarget = e.Source as UIElement;
// If a drag/drop is happening, there is definitely
// one child in the DimsContainer
double width = ((FrameworkElement)(this.DimsContainer.ItemContainerGenerator.ContainerFromIndex(0))).ActualWidth;
int index = (int)(e.GetPosition(DimsContainer).X / width);
try
{
this.indices.Insert(index, removedObject);
}
catch (InvalidOperationException)
{
// ignore
}
_isDown = false;
_isDragging = false;
_realDragSource.ReleaseMouseCapture();
}
}
public static int RemoveItemFromItemsControl(ItemsControl itemsControl, object itemToRemove)
{
int indexToBeRemoved = -1;
if (itemToRemove != null)
{
indexToBeRemoved = itemsControl.Items.IndexOf(itemToRemove);
if (indexToBeRemoved != -1)
{
IEnumerable itemsSource = itemsControl.ItemsSource;
if (itemsSource == null)
{
itemsControl.Items.RemoveAt(indexToBeRemoved);
}
// Is the ItemsSource IList or IList<T>? If so, remove the item from the list.
else if (itemsSource is IList)
{
((IList)itemsSource).RemoveAt(indexToBeRemoved);
}
else
{
Type type = itemsSource.GetType();
Type genericIListType = type.GetInterface("IList`1");
if (genericIListType != null)
{
type.GetMethod("RemoveAt").Invoke(itemsSource, new object[] { indexToBeRemoved });
}
}
}
}
return indexToBeRemoved;
}
public static void InsertItemInItemsControl(ItemsControl itemsControl, object itemToInsert, int insertionIndex)
{
if (itemToInsert != null)
{
IEnumerable itemsSource = itemsControl.ItemsSource;
if (itemsSource == null)
{
itemsControl.Items.Insert(insertionIndex, itemToInsert);
}
// Is the ItemsSource IList or IList<T>? If so, insert the dragged item in the list.
else if (itemsSource is IList)
{
((IList)itemsSource).Insert(insertionIndex, itemToInsert);
}
else
{
Type type = itemsSource.GetType();
Type genericIListType = type.GetInterface("IList`1");
if (genericIListType != null)
{
type.GetMethod("Insert").Invoke(itemsSource, new object[] { insertionIndex, itemToInsert });
}
}
}
}
use drag and drop behavior. e.g. http://www.codeproject.com/KB/WPF/gong-wpf-dragdrop-ii.aspx

WPF: Get next /prev visual object

I have a StackPanel containing a number ofTextBox. Is there a way to get the Next / Previous visual elements ?
The functionality I want is fairly analogous to jQuery's .next() function that get the next object.
You can try following method to enumerate the Visual Tree.
public static IEnumerable<T> FindVisualChildren<T>
(DependencyObject depObj, string childName) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
var frameworkElement = child as FrameworkElement;
if (child != null && frameworkElement.Name == childName)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child, childName))
{
yield return childOfChild;
}
}
}
}
Assuming that you named your textBoxes "tbInsideStackPanel", use it like:
foreach (var textBox in FindVisualChildren<TextBox>(this.stackPanel1,
"tbInsideStackPanel").ToList())
{
textBox.Background = Brushes.Blue;
}

WPF Listbox auto scroll while dragging

I have a WPF app that has a ListBox. The drag mechanism is already implemented, but when the list is too long and I want to move an item to a position not visible, I can't.
For example, the screen shows 10 items. And I have 20 items. If I want to drag the last item to the first position I must drag to the top and drop. Scroll up and drag again.
How can I make the ListBox auto scroll?
Got it. Used the event DragOver of the ListBox, used the function found here to get the scrollviewer of the listbox and after that its just a bit of juggling with the Position.
private void ItemsList_DragOver(object sender, System.Windows.DragEventArgs e)
{
ListBox li = sender as ListBox;
ScrollViewer sv = FindVisualChild<ScrollViewer>(ItemsList);
double tolerance = 10;
double verticalPos = e.GetPosition(li).Y;
double offset = 3;
if (verticalPos < tolerance) // Top of visible list?
{
sv.ScrollToVerticalOffset(sv.VerticalOffset - offset); //Scroll up.
}
else if (verticalPos > li.ActualHeight - tolerance) //Bottom of visible list?
{
sv.ScrollToVerticalOffset(sv.VerticalOffset + offset); //Scroll down.
}
}
public static childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
// Search immediate children first (breadth-first)
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Based on this I have created an Attached Behavior which can easily be used like this -
<ListView
xmlns:WpfExtensions="clr-namespace:WpfExtensions"
WpfExtensions:DragDropExtension.ScrollOnDragDrop="True"
Here is the code for attached behavior -
/// <summary>
/// Provides extended support for drag drop operation
/// </summary>
public static class DragDropExtension
{
public static readonly DependencyProperty ScrollOnDragDropProperty =
DependencyProperty.RegisterAttached("ScrollOnDragDrop",
typeof(bool),
typeof(DragDropExtension),
new PropertyMetadata(false, HandleScrollOnDragDropChanged));
public static bool GetScrollOnDragDrop(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool)element.GetValue(ScrollOnDragDropProperty);
}
public static void SetScrollOnDragDrop(DependencyObject element, bool value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(ScrollOnDragDropProperty, value);
}
private static void HandleScrollOnDragDropChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
FrameworkElement container = d as FrameworkElement;
if (d == null)
{
Debug.Fail("Invalid type!");
return;
}
Unsubscribe(container);
if (true.Equals(e.NewValue))
{
Subscribe(container);
}
}
private static void Subscribe(FrameworkElement container)
{
container.PreviewDragOver += OnContainerPreviewDragOver;
}
private static void OnContainerPreviewDragOver(object sender, DragEventArgs e)
{
FrameworkElement container = sender as FrameworkElement;
if (container == null)
{
return;
}
ScrollViewer scrollViewer = GetFirstVisualChild<ScrollViewer>(container);
if (scrollViewer == null)
{
return;
}
double tolerance = 60;
double verticalPos = e.GetPosition(container).Y;
double offset = 20;
if (verticalPos < tolerance) // Top of visible list?
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - offset); //Scroll up.
}
else if (verticalPos > container.ActualHeight - tolerance) //Bottom of visible list?
{
scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset); //Scroll down.
}
}
private static void Unsubscribe(FrameworkElement container)
{
container.PreviewDragOver -= OnContainerPreviewDragOver;
}
private static T GetFirstVisualChild<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = GetFirstVisualChild<T>(child);
if (childItem != null)
{
return childItem;
}
}
}
return null;
}
}

Categories

Resources