How to check if a UIElement is visible in Silverlight? - c#

How can I check if any given UIElement is currently visible on the UI?
There is the UIElement.Visibility property, but this is set by the progammer to indicate that the element should be hidden or visible.
I already check if the element is in the VisualTree.
All this does not help if there is another element on top that overlaps it.
WPF has a property UIElement.IsVisible that seems to do the job, but this is missing in Silverlight.
Any ideas?
Thanks

You can do some code to test the Visiblity and the HitTestVisible property of an element.
EDIT:
Try to do something like mentioned here,
Silverlight - Determine if a UIElement is visible on screen

There is a way to check the "render visibility" (although it cannot check for overlapping elements):
Elements do have the Unloaded event.
It is raised whenever changes to the VisualTree happen that result in the Element being part of a VisualTree branch that is not currently rendered. But luckily you don't have to listen for those events because only loaded elements do have decendants or a parent in the VisualTree.
And with the help of a nice little ExtensionMethod you can check whether an element is loaded or not at any given point in time:
public static class FrameworkElementExtensions
{
public static bool IsLoaded(this FrameworkElement element)
{
return element.GetVisualChildren().Any();
//I'm not sure if this alternative is better:
//return System.Windows.Media.VisualTreeHelper.GetParent(element)!= null;
//or
//return element.GetVisualParent() != null;
}
}

Related

Why do CausesValidation does not propagate from Containers to child controls?

I am using c#.
Why does the CausesValidation property does not propagate from containers to child controls?
I have a TabControl and i need to perform validation of user input on all tabs.
But each tab is independent. I found out that if i have a container like a TableLayoutPanel and i set CausesValidation to false, the child componentes still perform validation.
So this code would not work:
Foreach(Control c in Container.Controls)
{
c.CausesValidation = False;
}
If you do some DEBUG output you will see that the only found control is the TableLayoutPanel or any other container like a GroupBox that will be found and set to False. But containers are not propagating that value to the child level.
A lot of people asked how we could solve the problem. I found a lot of methods, but i have created a static class that allows me to select wich tab on the TabControl that i want to perform validation, and it will set CausesValidation to False on ALL controls of that TabControl, including child controls with a deepness of 10 layers. If you want that library just ask for it!
My real question is, should not a container propagate that property to its child controls, and that child controls to any child controls?!
It would save us a lot of work from creating a very crazy code that is very specific for something that should work from scratch? Why is this not implied?
This just isn't a constructive way to deal with your requirement. The feature just wasn't implemented the way you like it to work and that's never going to change. It isn't a problem, you can easily add it yourself with a wee bit of code:
public static void SetCausesValidation(Control.ControlCollection ctls, bool enable) {
foreach (Control ctl in ctls) {
ctl.CausesValidation = enable;
SetCausesValidation(ctl.Controls, enable);
}
}
And use it in your form constructor, something like:
public Form1() {
InitializeComponent();
SetCausesValidation(panel1.Controls, false);
}
Note the use of recursion in the method to set the property through the entire tree of controls inside the container.

How can I get the parent of a FrameworkElement in Windows Store app

I am writing a C# XAML Windows Store app. I have a grid on my page. I add a child element to that grid and I immediately try to get the parent of this child. The parent is null. There does not seem to be a way to get the parent grid from the child element. Here's some code to show what I'm doing. It's not all that complicated:
This is the code that adds the child element and tries to get the parent element:
FrameworkElement FieldView = Field.getView( true );
ContentPanel.Children.Add( FieldView );
Panel theParent = VisualTreeHelper.GetParent(FieldView) as Panel;
FrameworkElement theotherparent = (FrameworkElement)FieldView.Parent;
ContentPanel is a Grid on the page. FieldView is a UserControl. The page displays just fine and there are no exceptions in any of the code. The only thing that is wrong is that I cannot get the parent of FieldView. It is null.
Before posting this, I did a quick test to make sure that UserControl was not the issue. using a TextBlock shows the same problem:
TextBlock Derf = new TextBlock();
PageGroup.ContentPanel.Children.Add(Derf);
Panel theParent2 = VisualTreeHelper.GetParent(Derf) as Panel;
FrameworkElement theotherparent2 = (FrameworkElement)Derf.Parent;
Does the parent property never get set in a Windows Store app? This code worked fine on Window Phone 8.
Thanks for any help.
Dave
As Nate suggested, adding child elements to a Grid works as expected when it is done within the "Loaded" event handler. It only fails within the "OnNavigatedTo" handler. Changing the place in the code where I add the children lets me get a non-null parent.
I would like to point out that this is a bit strange (like a bug). The Grid object exists, so it doesn't make sense that it cannot be set as the parent of the child object. Additionally, even if the parent property is set to null, the code somehow knows that there is a parent object/container because it throws an exception if I try to add the child to more than one Grid.

Change TreeListNode Index (Position) in DevExpree TreeList Control

I'm using DevExpree XtraTreeList Control, I want to randomly Set one of the first levels nodes to be the first node in the Tree, nothing helpful shown in the TreeList Control's Methods nor in the TreeListNode Methods,
Please Advice.
Edit: My Code
private void btnSetMaster_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
{
//Load reprot
if (treeLstRprtDS.FocusedNode != null)
{
treeLstRprtDS.SetNodeIndex(treeLstRprtDS.FocusedNode,0);
//Get selected underlying object
ReportDataSource rprtDataSourceSelected =
(ReportDataSource)treeLstRprtDS.GetDataRecordByNode(treeLstRprtDS.FocusedNode);
theReport.SetReportDataSourceAsMaster(rprtDataSourceSelected);
}
}
Edit:
Note: working on bound mode
Solution:
I implemented the CompareNodeValues Event for the XtrTreeList Control
Read here...
and then forced the tree to do sorting using Column.SortIndex Read here...
Do you wish to scroll the TreeList so that a certain node to be the top one? If so, use the TreeList's TopVisibleNodeIndex property. If you need a certain node to be the first one, you should sort the TreeList within its CompareNodeValues event handler.
It sounds like you're looking for the SetNodeIndex method.

How to determine on which UIElement a tagged object is placed?

In my app I use tagged objects. Now I'd like to react differently not only on the object that is placed on the surface, but also on the element it is placed on. Is this possible somehow? I couldn't find any information about it.
You might do a HitTest. Basically you get the point relative to your window and look which element of the visual tree is being hit. No code sample at hand, but you'll find a lot using HitTest and WPF on google.
Yes, it is possible. Please show us your code so we can help you better.
What you are looking for is probably Reflection.
Did you know you can always check if an object is of a certain type with the is operator?
var tag = myDependencyObject.Tag;
if(myDependencyObject is CheckBox)
{
//...
}
else if(myDependencyObject is TextBox)
{
//...
}
To detect a change of the Tag-Property, listen to the DependencyPropertyChanged event like this:
DependencyPropertyDescriptor prop = DependencyPropertyDescriptor.FromProperty(
FrameworkElement.TagProperty,
typeof(FrameworkElement));
prop.AddValueChanged(aTaggedControl, this.YourEventHandlerMethod);

WPF - FindName Returns null when it should not

FindName is broken for me :(
The object I am looking for is there. I have proof.
Here is the scenario:
ToggleButton button = (ToggleButton)sender;
Popup popup = (Popup)button.FindName("popSelectIteration");
popup is null but not always. Just sometimes. But even when it is set to null the child I am looking for is there.
I put a break point in when it was null and grabbed these two screenshots.
The is where FindName is returning null for "popSelectIteration".
But if you dig into the watch, you see that the child is there.
So what am I missing? Why does FindName not find it? As you can see from the screen shot this is not a timing issue (the FindName watch is null but the direct path is fine).
Is there a better way to find a control?
Side Note: If you are intersted in the XAML for the toggle button in question it can be found in this question: WPF - FrameworkElement - Enumerate all decendents?.
Update: I did some digging to see why this fails some times and other times it works. I have an animation that calls NameScope.SetNameScope((DependencyObject)form, new NameScope()); (Full method code here). Right after that call the FindName starts to fail.
I don't really understand that call. I think I copied and pasted the code. Anyway, I commented it out. But I would love know why this is failing.
I would guess it has to do with the difference between the visual and logical tree. The control is in the logical tree but maybe the template for this control has not been applied yet and therefore FindName won't return anything useful.
You could try to call ApplyTemplate(); on the container first.
This would also explain why it returns something sometimes.
Try
LogicalTreeHelper.FindLogicalNode(button, "popSelectIteration");
Little late to the party (and not actually answer to OP question), but
when you add elements dynamically, they are not findable by FindName.
You need to register them by calling RegisterName.
Example:
string number = GenerateNumber();
Button myButton = new Button();
myButton.Content = number;
myButton.Name = "button_" + number;
RegisterName(myButton.Name, myButton);
Panel.Children.Add(myButton);
object o = Panel.FindName(myButton.Name);
Maybe someone might find this useful.
In my experience, this happens when you add items via code-behind. I've found that you can fool FindName() (or the animation framework) via name scopes. That is, when you create your control, you do
NameScope.GetNameScope(yourContainer).RegisterName("name of your control", yourControlInstance);
For this to work reliably, though, you must make sure that you unregister the name:
NameScope.GetNameScope(yourContainer).UnregisterName("name of your control");
Posting this for future reference.
I have meet the same question now, but I use the method like so:
#region Override - OnApplyTemplate
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this.PART_ListViewLeft = GetTemplateChild(cPART_ListViewLeft) as ListView;
this.PART_ListViewCenter = GetTemplateChild(cPART_ListViewCenter) as ListView;
this.PART_ListViewRight = GetTemplateChild(cPART_ListViewRight) as ListView;
this.PART_GridViewLeft = GetTemplateChild(cPART_GridViewLeft) as DsxGridView;
this.PART_GridViewCenter = GetTemplateChild(cPART_GridViewCenter) as DsxGridView;
this.PART_GridViewRight = GetTemplateChild(cPART_GridViewRight) as DsxGridView;
if(this.PART_ListViewLeft!=null)
this.PART_ListViewLeft .AlternationCount = this.AlternatingRowBrushes.Count;
if(this.PART_ListViewCenter!=null)
this.PART_ListViewCenter .AlternationCount = this.AlternatingRowBrushes.Count;
if(this.PART_ListViewRight!=null)
this.PART_ListViewRight .AlternationCount = this.AlternatingRowBrushes.Count;
// ApplyTempleted = true;
CreateColumnLayout();
}
#endregion
If the Control is dynamic create and of which or whose container the 'Visibility' is set to hide or Collapsed, then the code this.PART_ListViewLeft = GetTemplateChild(cPART_ListViewLeft) as ListView; will always return null, the reason is that the datatemplete has not yet been applied before OnApplyTemplate being called.
I would suggest to avoid using FindName function, based on my experience, expecially problematic when you try to find something in the DataTemplate applied to some control.
Instead , if it possible (based on your software architecture) declare Popup in XAML and
refer to it like resource or use Binding to set some Model property to it's reference.
Good luck.
Try to use button.FindResource("popSelectIteration")
ellipseStoryboard.Children.Add(myRectAnimation);
containerCanvas.Children.Add(myPath);
After you add register the controls like
RegisterName("TextBlock1", Var_TextBox);
or
RegisterName(myRectAnimation.Name,myRectAnimation);
RegisterName(myPath.Name,myPath);

Categories

Resources