I am new with WPF, so I'm not sure if the title of the question is correct or makes any sense, please edit if it can get more relevant. I am using Kinect.Toolbox MouseControl in my application. For using the magnetic controls I have a problem. I know that I can define them in XAML by adding:
<Page ...
xmlns:local ="clr-namespace:Kinect.Toolbox;assembly=Kinect.Toolbox">
...
<Button local:MagneticPropertyHolder.IsMagnetic="True" ... />
....
But I need to do it in the code. Is there anyway to set the magnetic controls in the code? I can get all the controlls in the page like 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;
}
}
}
}
foreach (Button tb in FindVisualChildren<Button>(this))
{
//Set the buttons to be magnetic
}
However I cannot understand how to set them progmatically.
This looks like an attached property.
To set it, you'd do something like
tb.SetValue(MagneticPropertyHolder.IsMagneticProperty, true);
or possibly
MagneticPropertyHolder.SetIsMagnetic(tb, true);
A quick glance at the Kinect Toolbox source code suggests that either would work. The second is more type safe.
See How to I access an attached property in code behind? for more information.
Related
I'm struggling using XAML variables in a loop, my problem is detailed below :
I've a foreach() loop, I've 4 images in XAML called let's say image1, image2, image3, image4 now I would like to associate a image that I've got its path in my foreach loop to each image variable.
An obvious solution would be :
foreach() {
//my stuff
image1.Source = bitmapSource;
image2.Source = bitmapSource;
image3.Source = bitmapSource;
image4.Source = bitmapSource;
}
But this solution is not flexible, I thought about putting my image variables in an array but I don't think that is possible (at least I haven't found anything that goes in this way).
What's the best / cleanest way to do it ? Thanks
Use LINQ and Enumerable.OfType<TResult> Method:
Grid1.Children.OfType<Image>().ToList().ForEach(c => c.Source = bitmapSource);
I've presumed the images are inside the Grid container with name Grid1. Change accordingly if they are inside another container.
EDIT:
If your images are inside different containers as you pointed out in your last comment you can do 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 is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
And then:
FindVisualChildren<Image>(MainGrid).ToList().ForEach(c => c.Source = bitmapSource);
Again I've presumed your different containers are inside a main Grid with name MainGrid.
In WPF, I have a structure like this
<Button>
<Grid>
<!--definitions for 1 row and 2 columns-->
<TextBlock x:Name="t1" Grid.Column="0"/>
<TextBlock x:Name="t2" Grid.Column="1"/>
</Grid>
</Button>
Supposed a Button b with this structure is generated dynamically. How to access t1 from Button b?
Edit for clarification: Since t1 resides within Button b, is it possible to change the content of t1 if one only have access to b? something along the line of b.childGridElement.childTextBlock_t1.Text = "newString"?
This should work for the use case you've provided:
((TextBlock)b.FindName("t1")).Text = "newString";
You need to use Visual Tree Helper for this.
Define Handler Extension Method
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject parent) where T : DependencyObject
{
if (parent != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the available child is not null and is of required Type<T> then return with this child else continue this loop
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
now in your xaml
IEnumerable<TextBlock> textblockes=FindVisualChildren<TextBlock>(b);
foreach (var textblock in textblockes)
{
if (textblock!= null && textblock.Name="t1")
{
//write code for t1 here;
}
if (textblock!= null && textblock.Name="t2")
{
//write code for t2 here;
}
}
In above method whatever is your tree structure , it will find all the textblock of your Button b and then on the basis of Name property you can do appropriate operations.
I'm exploring logical and visual trees from the same application without success going deeper through the levels.
My code uses a generic explorer:
private static void ProcessGenericTree(object current, List<FrameworkElement> leaves, Type treeType)
{
if (current is FrameworkElement)
{
if (!leaves.Contains(current as FrameworkElement))
leaves.Add(current as FrameworkElement);
}
DependencyObject dependencyObject = current as DependencyObject;
if (dependencyObject != null)
{
if (treeType.Equals(typeof(VisualTreeHelper)))
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
ProcessVisualTree(VisualTreeHelper.GetChild(dependencyObject, i), leaves);
}
}
else
{
foreach (object child in LogicalTreeHelper.GetChildren(dependencyObject))
{
ProcessLogicalTree(child, leaves);
}
}
}
}
ProcessLogicalTree and ProcessVisualTree simply iterate (doing something before the ProcessGenericTree re-call).
The result looks complete, but when I'm trying to retrieve a TextBlock into a GridViewColumn Header it looks like the item doesn't exist neither in the Logical nor in the Visual leaves list of FrameworkElement.
It seems to be a Visual Element into a Logical Element. In fact adding a watch this TextBlock appears in the Visual Children of my GridView (retrieved as logical, it stands in a Tab Item not selected), but my code isn't unable to get it.
My call is pretty simple:
ProcessVisualTree(root, _visualElements);
ProcessLogicalTree(root, _logicalElements);
where root is the MainWindow.
So, how can I explore my tree at its deepest level? Maybe re-iterating through the retrieved FrameworkElement list? I think my ProcessGeneric code already does it.
Update: the WPF Visualizer shows a structure of this kind:
ListView > ScrollViewer > Grid > DockPanel > Grid > ScrollContentPresenter > GridViewHeaderRowPresenter > GridViewColumnHeader > HeaderBorder
The GridViewColumnHeader level contains my TextBlock but the visual tree doesn't.
Update 2: using the recursion starting from the main window with my element visible I'm not able to Find the object with a specified name with this code:
public static T FindVisualChild<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 = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}
I'm pretty sure the VisualTreeHelper is not able to retrieve elements inside Header property but the WPF Inspector works correctly.
I wonder if it uses a different approach to traverse the tree (maybe inspecting the Properties like Header too). Suggestions?
I have a Canvas being populated from a XAML load from a file using:
SBWindowContainerCanvas.Children.Clear();
StreamReader stringreader = new StreamReader("C:\\xaml\\xmltest.xaml");
XmlReader xmlreader = XmlReader.Create(stringreader);
var mainborder = XamlReader.Load(xmlreader);
SBWindowContainerCanvas.Children.Add((Blacklight.Controls.ClippingBorder)mainborder);
The border contains many child elements including some user controls.
partial snippet of XAML file:
<av:ContentControl Name="VisScoreCC" Width="417" Height="228" IsHitTestVisible="True" av:Canvas.Left="855" av:Canvas.Top="8" av:Selector.IsSelected="False">
<fsp:Scores3DigitControl Name="Vis3DigitScoreControl" VisitorControl="True" OperatorControl="True" NumericValue="4" UseGradientMainBG="False" UseGradientNumberBG="False" UseGradientLogoBG="False" UseGradientTeamNameBG="False" UseRadialMainBG="False" UseRadialNumberBG="False" UseRadialLogoBG="False" UseRadialTeamNameBG="False" UseImageStringMainBG="False|none|False|Tile|Top Left|1" SolidColorMainBG="#FFD4D2D2" SolidColorNumberBG="#FF000000" SolidColorBannerBG="#FF000000" FGColorNumbers="#FFFF0000" FGColorTeamName="#FFFFFFFF" FGColorBanner="#FFFFA500" SolidColorImageLogoBG="#FF000000" SolidColorTeamNameBG="#FF000000" GradientMainBG="#FF000000|#FF808080|#FFFFFFFF" GradientNumberBG="#FF000000|#FF808080|#FFFFFFFF" GradientLogoBG="#FF000000|#FF808080|#FFFFFFFF" GradientTeamNameBG="#FF000000|#FF808080|#FFFFFFFF" GradientOffsetsMainBG="0|0.5|1" GradientOffsetsNumbersBG="0|0.5|1" GradientOffsetsLogoBG="0|0.5|1" GradientOffsetsTeamNameBG="0|0.5|1" LinearAngleMainBG="180" LinearAngleNumberBG="180" LinearAngleLogoBG="180" LinearAngleTeamNameBG="180" OffSegmentOpacity="0.1" RoundRadiusNumbers="0" RoundRadiusLogo="0" RoundRadiusTeamName="0" PosSizeStringNumbers="180|8|200|150" PosSizeStringLogo="20|10|150|150" PosSizeStringTeamName="25|165|360|60" TeamNameFontString="Arial|40|True" UseRightSideBanner="True" Style="{av:DynamicResource Scores3DigitControlTemplate}" Height="Auto" Margin="0,0,0,0" IsHitTestVisible="True" />
</av:ContentControl>
<av:ContentControl Name="HomeScoreCC" Width="417" Height="228" IsHitTestVisible="True" av:Canvas.Left="11" av:Canvas.Top="8" av:Selector.IsSelected="False">
<fsp:Scores3DigitControl Name="Home3DigitScoreControl" VisitorControl="False" OperatorControl="True" NumericValue="4" UseGradientMainBG="False" UseGradientNumberBG="False" UseGradientLogoBG="False" UseGradientTeamNameBG="False" UseRadialMainBG="False" UseRadialNumberBG="False" UseRadialLogoBG="False" UseRadialTeamNameBG="False" UseImageStringMainBG="False|none|False|Tile|Top Left|1" TargetElementIndex="0" SolidColorMainBG="#FFD4D2D2" SolidColorNumberBG="#FF000000" SolidColorBannerBG="#FF000000" FGColorNumbers="#FFFF0000" FGColorTeamName="#FFFFFFFF" FGColorBanner="#FFFFA500" SolidColorImageLogoBG="#FF000000" SolidColorTeamNameBG="#FF000000" GradientMainBG="#FF000000|#FF808080|#FFFFFFFF" GradientNumberBG="#FF000000|#FF808080|#FFFFFFFF" GradientLogoBG="#FF000000|#FF808080|#FFFFFFFF" GradientTeamNameBG="#FF000000|#FF808080|#FFFFFFFF" GradientOffsetsMainBG="0|0.5|1" GradientOffsetsNumbersBG="0|0.5|1" GradientOffsetsLogoBG="0|0.5|1" GradientOffsetsTeamNameBG="0|0.5|1" LinearAngleMainBG="180" LinearAngleNumberBG="180" LinearAngleLogoBG="180" LinearAngleTeamNameBG="180" OffSegmentOpacity="0.1" RoundRadiusNumbers="0" RoundRadiusLogo="0" RoundRadiusTeamName="0" PosSizeStringNumbers="35|8|200|150" PosSizeStringLogo="250|10|150|150" PosSizeStringTeamName="25|165|360|60" TeamNameFontString="Arial|40|True" UseRightSideBanner="False" Style="{av:DynamicResource Scores3DigitControlTemplate}" OverridesDefaultStyle="False" Name="Home3DigitScoreControl" Height="Auto" IsHitTestVisible="True" />
</av:ContentControl>
When I want to get access to my controls in code-behind, I am not able to actually re-hook to the elements using:
Scores3DigitControl Vis3DigitScoreControlC = (Scores3DigitControl)SBWindowContainerCanvas.FindName("Vis3DigitScoreControl");
if (Vis3DigitScoreControlC == null)
{
MessageBox.Show("Couldn't Find Vis");
}
else
{
Vis3DigitScoreControlC.Visibility = Visibility.Hidden;
}
The UI Elements show up fine on the screen but I always get a "Couldn't Find Vis" message. From everything I read so far, using the FindName should work as long as my element is a child somewhere in the canvas, right? What am I missing?
Thank you
FindName is generally used for getting elements from a template. In your case your probably best to use the LogicalTreeHelper
LogicalTreeHelper.FindLogicalNode(SBWindowContainerCanvas,
"Vis3DigitScoreControl");
Try to use that method:
public 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;
}
}
}
}
It should return to you all object which you need. And after you will be able choose one in foreach loop.
Try using x:Name instead of Name and checking after that element has loaded.
LogicalTreeHelper.FindLogicalNode(...) works here, because it goes across NameScope boundries.
Whereas FindName(...) works in same NameScope.
Dynamically adding controls require good understanding of NameScopes.
sorry about not making myself clear enough and not putting enough effort (wont happen again :)). i'm building a form App where users have to fill out the form. i have a TabControl with 3 TabItem one of the TabItem has TextBoxes the second has TextBoxes and RadioButton and third has only CheckBoxes. i have written a code to dictect error by on clicking submit using ValidationRule/ValidationResult and and using GroupBinding (got it from msdn samples). now the problem am having is code to search through the tabs, compare the controls (e.g. controlA,controlB) to know wich one comes before the other and return the tabindex. one of the use i want with this is letting the user jump to the uncompleted TextBox,RadioButton or CheckBoxes in order like starting from the first Tabitem in the TabControl
with this code i could work the tree to locate the controls(code from Philipp Sumi blog but i modified it a little)
private void Button_Click(
object sender,
RoutedEventArgs e)
{
IEnumerator enumerator = FindLogicalChildren(_parentStackPanel).GetEnumerator();
while (enumerator.MoveNext())
MessageBox.Show(enumerator.Current.ToString());
}
private IEnumerable FindLogicalChildren(
DependencyObject depObj)
{
if (depObj != null)
{
foreach (object childObj in LogicalTreeHelper.GetChildren(depObj))
{
DependencyObject child = childObj as DependencyObject;
if (child != null && child is Control)
{
yield return (Control)child;
}
foreach (Control childOfChild in FindLogicalChildren(child))
{
yield return childOfChild;
}
}
}
}
but i dodnt know how continue to get the tabindex of each control in order form as i work down the tree. can any one please help me on this? Thanks
im using this method:
private int Compare(
Control controlA,
Control controlB)
{
DependencyObject commonAncestor = controlA.FindCommonVisualAncestor(controlB);
for (int index = 0; index < VisualTreeHelper.GetChildrenCount(commonAncestor); index++)
{
Visual childVisual = (Visual)VisualTreeHelper.GetChild(commonAncestor, index);
Control control = (Control)childVisual;
control.TabIndex = index;
}
return controlA.TabIndex.CompareTo(controlB.TabIndex);
}
that returns 1,-1 or 0 to compare two controls to find out which one comes before the other. the question is, can anyone tell me a better way of doing this.