Check if an element is added on a Grid - c#

I have a UserControl contained in a class When some conditions are met I initialize the UserControl and I add it in a Grid, setting row and column property depending on the position of the class in a list. When I change that position, I need to update the position of the element on the Grid, but since not every class has its UserControl initialised and added, I need to check when I order the elements in the Grid.
To check if the UserControl is initialised I check if it is null
classElement.userControl == null
How do I check if the UserControl has been added to the Grid?

Perhaps the easiest way to achieve your requirements would be for you to simply iterate through the children of the Grid using the Children property, checking each one in turn. You could do something like this:
<Grid Name="YourGrid">
...
</Grid>
...
foreach (UIElement uiElement in YourGrid.Children)
{
if (uiElement.GetType() == typeof(UserControl))
{
if (uiElement != null)
{
// Do something with your control here
}
}
}
UPDATE >>>
I don't understand your comment... you said I need a way to know if the usercontrol is in the grid or not... that is exactly what I have provided you with. If you are adding the UserControl to the Grid, then you must have a reference to the Grid. If you have a reference to the Grid, then you can iterate the controls that have been added to that Grid just as I have shown you. If you are adding the UserControl from the UserControl code behind, then you can do this:
foreach (UIElement uiElement in YourGrid.Children)
{
if (uiElement.GetType() == typeof(UserControl))
{
if (uiElement != null)
{
if (uiElement == this)
{
// this UserControl is in the Grid
}
}
}
}
If this does not solve you problem, then please take the time to provide a decent description of your problem that would enable me to suggest a fix for it. From what I understand presently, this is your fix.

Related

How to get UIElement out of templated data in ListView?

Okay, i feel slightly dumb for askin this but, I have a listview with a templated class MyClass or whatever, whenever i "myListView.Add(new MyClass())" the winrt platform adds a new UIElement there and binds the proper properties into their proper uielements properly, now, I want to be able to iterate through these logical items (myListView.Items or myListView.SelectedItems) and get their corresponding UIElement for animation, is that possible?
like for example
class PhoneBookEntry {
public String Name { get;set }
public String Phone { get;set }
public PhoneBookEntry(String name, String phone) {
Name = name; Phone = phone;
}
};
myListView.Add(new PhoneBookEntry("Schwarzeneger", "123412341234");
myListView.Add(new PhoneBookEntry("Stallone", "432143214321");
myListView.Add(new PhoneBookEntry("Statham", "567856785678");
myListView.Add(new PhoneBookEntry("Norris", "666666666666");
And in XAML (just an example so i can explain what I mean)
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Phone}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
So, my point and objective here is to
foreach(PhoneBookEntry pbe in myListView.Items) // or SelectedItems
{
UIElement el; // How can I get the UIElement associated to this PhoneBookEntry pbe?
if(el.Projection == null)
el.Projection = new PlaneProjection;
PlaneProjection pp = el.Projection as PlaneProjection;
// Animation code goes here.
if(myListView.SelectedItems.Contains(pbe)
//something for selected
else
//something for not selected
}
I just need a way to get an UIElement which is being used to represent this logical data class PhoneBookEntry in the templated listview.
Also, this necessity comes with a very big problem I'm having where, selected items doesn't differ visually on Windows Phone -_- any ideas?
You can also use the ListView.ContainerFromItem or ListView.ContainerFromIndex methods which will return the container UI element for a given item in the list view (of course, only if the container is generated)
Ok I may look like a fool answering my own question but i've figured a way out.
First things first: ListViews only create UIElements for determinate items in the list (the ones cached and the ones being shown). So if you do add 2000 items to myListView.Items, the effective ammount of UIElements representing these items will be 56 or close number.
Because, the ItemListView simulates the UIElements even if they're not there, just to give size and position to the scrollbar (hence why scrolling down on very large lists cause some lag, WinRT is unloading UIElements and loading new ones)
From that, I figured out I could simply iterate through the current list of loaded UIElements through
// For each of the cached elements
foreach(LIstViewItem lvi in myListView.ItemsPanelRoot.Children)
{
// Inside here I can get the base object used to fill the data template using:
PhoneBookEntry pbe = lvi.Content as PhoneBookEntry;
if(pbe.Name == "Norris")
BeAfraid();
// Or check if this ListViewItem is or not selected:
bool isLviSelected = lvi.IsSelected;
// Or, like I wanted to, get an UIElement to animate projection
UIElement el = lvi as UIElement;
if(el.Projection == null)
el.Projection = new PlaneProjection();
PlaneProjection pp = el.Projection as PlaneProjection;
// Now I can use pp to rotate, move and whatever with this UIElement.
}
So, this is it. Right beneath my nose...

Different-sized Tiles in Windows App

I know that I can use the ListView and GridView to create "Tiles"/Items whatever size I want, but how can I create different-sized Tiles for use within my app? This will need to work with a ListView or GridView.
I have tried so many things but I just have absolutely no idea how to do this. Any help will be much appreciated.
In case I haven't described what I am trying to achieve properly, here is a pic:
A simple way is to create a new class inheriting from GridView and override the PrepareContainerForItemOverride method. In which you can set the Column Span and RowSpan to Child item based on the model data. Consider your model class contains the Spanning information.
public class VariableGrid : GridView
{
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
ITileItem tile = item as ITileItem;
if (tile != null)
{
GridViewItem griditem = element as GridViewItem;
if (griditem != null)
{
VariableSizedWrapGrid.SetColumnSpan(griditem, tile.ColumnSpan);
VariableSizedWrapGrid.SetRowSpan(griditem, tile.RowSpan);
}
}
base.PrepareContainerForItemOverride(element, item);
}
}
More information : http://wpfplayground.blogspot.in/2013/03/different-sized-tile-items-in-winrt.html
You need to set ItemsPanel/ItemsPanelTemplate of your list to VariableSizedWrapGrid and set Grid.RowSpan/ColumnSpan of your list items to the values you want. I believe you can do that in ItemContainerStyle of the list control, which is best extracted by right-clicking the control in VS XAML design view or in Blend and selecting "Edit Additional Templates"/"Edit Generated Item Container".

WPF Listbox Virtualization creates DisconnectedItems

I'm attempting to create a Graph control using a WPF ListBox. I created my own Canvas which derives from a VirtualizingPanel and I handle the realization and virtualization of items myself.
The listbox' item panel is then set to be my custom virtualized canvas.
The problem I am encountering occurs in the following scenario:
ListBox Item A is created first.
ListBox Item B is created to the right of Item A on the canvas.
ListBox Item A is virtualized first (by panning it out of view).
ListBox Item B is virtualized second (again by panning it out of view).
Bring ListBox Item A and B in view (i.e: realize them)
Using Snoop, I detect that the ListBox has now 3 items, one of them being a "DisconnectedItem" located directly underneath ListBox Item B.
What causes the creation of this "DisconnectedItem" ? If I were to virtualize B first, followed by A, this item would not be created. My theory is that virtualizing items that precedes other items in a ListBox causes children to be disconnected.
The problem is even more apparent using a graph with hundreds of nodes, as I end up with hundreds of disconnected items as I pan around.
Here is a portion of the code for the canvas:
/// <summary>
/// Arranges and virtualizes child element positionned explicitly.
/// </summary>
public class VirtualizingCanvas : VirtualizingPanel
{
(...)
protected override Size MeasureOverride(Size constraint)
{
ItemsControl itemsOwner = ItemsControl.GetItemsOwner(this);
// For some reason you have to "touch" the children collection in
// order for the ItemContainerGenerator to initialize properly.
var necessaryChidrenTouch = Children;
IItemContainerGenerator generator = ItemContainerGenerator;
IDisposable generationAction = null;
int index = 0;
Rect visibilityRect = new Rect(
-HorizontalOffset / ZoomFactor,
-VerticalOffset / ZoomFactor,
ActualWidth / ZoomFactor,
ActualHeight / ZoomFactor);
// Loop thru the list of items and generate their container
// if they are included in the current visible view.
foreach (object item in itemsOwner.Items)
{
var virtualizedItem = item as IVirtualizingCanvasItem;
if (virtualizedItem == null ||
visibilityRect.IntersectsWith(GetBounds(virtualizedItem)))
{
if (generationAction == null)
{
GeneratorPosition startPosition =
generator.GeneratorPositionFromIndex(index);
generationAction = generator.StartAt(startPosition,
GeneratorDirection.Forward, true);
}
GenerateItem(index);
}
else
{
GeneratorPosition itemPosition =
generator.GeneratorPositionFromIndex(index);
if (itemPosition.Index != -1 && itemPosition.Offset == 0)
{
RemoveInternalChildRange(index, 1);
generator.Remove(itemPosition, 1);
}
// The generator needs to be "reseted" when we skip some items
// in the sequence...
if (generationAction != null)
{
generationAction.Dispose();
generationAction = null;
}
}
++index;
}
if (generationAction != null)
{
generationAction.Dispose();
}
return default(Size);
}
(...)
private void GenerateItem(int index)
{
bool newlyRealized;
var element =
ItemContainerGenerator.GenerateNext(out newlyRealized) as UIElement;
if (newlyRealized)
{
if (index >= InternalChildren.Count)
{
AddInternalChild(element);
}
else
{
InsertInternalChild(index, element);
}
ItemContainerGenerator.PrepareItemContainer(element);
element.RenderTransform = _scaleTransform;
}
element.Measure(new Size(double.PositiveInfinity,
double.PositiveInfinity));
}
I'm 6 years late, but the problem is still not fixed in WPF. Here is the solution (workaround).
Make a self-binding to the DataContext, eg.:
<Image DataContext="{Binding}" />
This worked for me, even for a very complex xaml.
It's used whenever a container is removed from the visual tree, either because the corresponding item was deleted, or the collection was refreshed, or the container was scrolled off the screen and re-virtualized.
This is a known bug in WPF 4
See this link for known bug, it also has a workaround you may be able to apply.
"You can make your solution a little more robust by saving a reference
to the sentinel object {DisconnectedItem} the first time you see it,
then comparing against the saved value after that.
We should have made a public way to test for {DisconnectedItem}, but
it slipped through the cracks. We'll fix that in a future release, but
for now you can count on the fact that there's a unique
{DisconnectedItem} object."

How can I make a specific TabItem gain focus on a TabControl without click event?

How can I tell my TabControl to set the focus to its first TabItem, something like this:
PSEUDO-CODE:
((TabItem)(MainTabControl.Children[0])).SetFocus();
How about this?
MainTabControl.SelectedIndex = 0;
this.tabControl1.SelectedTab = this.tabControl1.TabPages["tSummary"];
I've found it's usually a best practice to name your tabs and access it via the name so that if/when other people (or you) add to or subtact tabs as part of updating, you don't have to go through your code and find and fix all those "hard coded" indexes. hope this helps.
I realise this was answered a long time ago, however a better solution would be to bind your items to a collection in your model and expose a property that selected item is bound to.
XAML:
<!-- MyTemplateForItem represents your template -->
<TabControl ItemsSource="{Binding MyCollectionOfItems}"
SelectedItem="{Binding SelectedItem}"
ContentTemplate="{StaticResource MyTemplateForItem}">
</TabControl>
Code Behind:
public ObservableCollection<MyItem> MyCollectionOfItems {
get;
private set;
}
private MyItem selectedItem;
public MyItem SelectedItem{
get { return selectedItem; }
set {
if (!Object.Equals(selectedItem, value)) {
selectedItem = value;
// Ensure you implement System.ComponentModel.INotifyPropertyChanged
OnNotifyPropertyChanged("SelectedItem");
}
}
}
Now, all you have to do to set the item is:
MyItem = someItemToSelect;
You can use the same logic with the SelectedIndex property, further, you can use the two at the same time.
This approach allows you to separate your model correctly from the UI, which could allow you to replace the TabControl with something else down the line but not requiring you to change your underlying model.
Look at the properties for the tab control...
Expand the TabPages properties "collection"...
Make note of the names you gave the members.
ie. a tab control called tabMain with 2 tabs called tabHeader and tabDetail
Then to select either tab...You have to set it with the tabname
tabMain.SelectedTab = tabHeader;
tabControl1.SelectedTab = item;
item.Focus();
Basically all of the answers here deal with SELECTION, which does not answer the question.
Maybe that is what OP wanted, but the question very specifically asks for FOCUS.
TabItem item = (TabItem)MainTabControl.Items[0];
// OR
TabItem item = (TabItem)MainTabControl.SelectedItem;
// Then
item.Focus();
tabControl.SelectedItem = tabControl.Items[0];
If you have a Tabcontroller named tabControl you could set the selectedIndex from different methods, i use following methods mostly.
codebehind:
tabControl.SelectedIndex = 0; // Sets the focus to first tabpanel
clientside:
First, put the following javascript in your aspx/ascx file:
<script type="text/javascript">
function SetActiveTab(tabControl, activeTabIndex) {
var activeTab = tabControl.GetTab(activeTabIndex);
if(activeTab != null)
tabControl.SetActiveTab(activeTab);
}</script>
Then add following clientside event to prefered controller:
OnClientClick="function(s, e) { SetActiveTab(tabControl, 0);
it's better to use the following type of code to select the particular
item in the particular tab...
.
private void PutFocusOnControl(Control element)
{
if (element != null)
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Input,
(System.Threading.ThreadStart)delegate
{
element.Focus();
});
}
And in calling time... tabcontrol.isselected=true;
PutFocusOnControl(textbox1);
will works fine...
Private Sub TabControl1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles TabControl1.SelectedIndexChanged
'MsgBox(TabControl1.SelectedIndex)
If TabControl1.SelectedIndex = 0 Then
txt_apclntFrstName.Select()
Else
txtApplcnNo.Select()
End If
End Sub
It worked for me to set focus to the last tab just after I open it:
//this is my assignment of the collection to the tab control
DictTabControl.DataContext = appTabs.DictTabs;
//set the selected item to the last in the collection, i.e., the one I just added to the end.
DictTabControl.SelectedItem = DictTabControl.Items[(DictTabControl.Items.Count-1)];

How do I avoid .Parent.Parent.Parent. etc. when referencing control hierarchies?

I'm trying to fix this ugly code.
RadGrid gv = (RadGrid) (((Control) e.CommandSource).Parent.Parent.Parent.Parent.Parent);
I often need to find the first grid that is the parent of the parent of... etc of a object that just raised an event.
The above tends to break when the layout changes and the number of .Parents increase or decreases.
I don't necessarily have a control Id, so I can't use FindControl().
Is there a better way to find the 1st parent grid?
Control parent = Parent;
while (!(parent is RadGrid))
{
parent = parent.Parent;
}
If you really have to find the grid, then you might something like this:
Control ct = (Control)e.CommandSource;
while (!(ct is RadGrid)) ct = ct.Parent;
RadGrid gv = (RadGrid)ct;
But maybe you can explain why you need a reference to the grid? Maybe there is another/better solution for your problem.
I'm not familiar with the API that you are using, but can you do something like:
Control root = ((Control)e.CommandSource);
while(root.Parent != null)
{
// must start with the parent
root = root.Parent;
if (root is RadGrid)
{
// stop at the first grid parent
break;
}
}
// might throw exception if there was no parent that was a RadGrid
RadGrid gv = (RadGrid)root;
If you have control of the Parent's code, you could use simple recursion to do it, I'd think. Something like:
public Control GetAncestor(Control c)
{
Control parent;
if (parent = c.Parent) != null)
return GetAncestor(parent);
else
return c;
}
I make no claims as to how well that will work, but it should get the idea across. Navigate up the parent chain as far as it goes until there is no parent, then return that object back up the recursion chain. It's brute force, but it will find the first parent no matter how high it is.

Categories