Can't find element that should exist? - c#

I am adding tabs to my tab control through code:
TabItem tab = new TabItem();
var stack = new StackPanel() { Orientation = Orientation.Horizontal };
stack.Children.Add(new TextBlock() { Text = header });
stack.Children.Add(new TextBlock() { Name = "extra" });
tab.Header = stack;
tabControl.Items.Add(tab);
As you can see, it creates the header of the tabItem with a stack panel. It adds two text blocks; one of which is empty, but I've assigned the name "extra". What I would like to do is, later in the code, edit the textBlock named "extra" and add some new text to it.
How would I find and edit this element? I have tried the following code, but its producing an error saying the element can not be found:
object test = Application.Current.FindResource("extra");

FindName is what you are looking for but your TextBlock is not in the correct WPF Namescope.
MSDN states:
If you add an object to an object tree at a point in time after the XAML that produced that tree was parsed, a Name or x:Name value on the new object does not automatically update the information in a XAML namescope. To add a name for an object into a WPF XAML namescope after XAML is loaded, must call the appropriate implementation of RegisterName on the object that defines the XAML namescope.
For example:
var textBlock = new TextBlock() { Name = "extra" };
stack.Children.Add(textBlock );
RegisterName(textBlock);
...
TextBlock textBlock = FindName("extra") as TextBlock;
Finally, Application.Current.FindResource("extra") is returning null because the element does not exist when project resources are created. More on FindResource.

Just use FrameworkElement.FindName method:
var control = tab.FindName("extra");
if(control is TextBlock){
// your logic here
}
You don't need Application.Current.Resource dictionary here because it's different collection. If you want to use it then you should put user controls within Resource dictionary beforehand.

Because you are trying to find resource with the key "extra". It's wrong.
Try this:
TabItem tab = new TabItem();
var stack = new StackPanel() { Orientation = Orientation.Horizontal };
var textBlock = new TextBlock() { Name = "extra" }
stack.Children.Add(new TextBlock() { Text = header });
stack.Children.Add(textBlock);
tab.Header = stack;
tabControl.Items.Add(tab);
Now you can reach it with textBlock instance.

Here's some VB WPF code for what you need
Dim test As TextBlock
test = DirectCast(FindName("extra"), TextBlock)
I have no idea if it will work like that in C# WPF although if that doesn't work try looking up CType

Related

Xamarin Forms ListView ItemsSource issue

I have a ListView and its ItemsSource.
ListView IList = new ListView();
IList.ItemsSource = _routine_names;
In order to customize the Data Template for each item I'm doing:
IList.ItemTemplate = new DataTemplate(()=>
{
Label Routine_Name = new Label(); // should be_routine_names
return new ViewCell
{
View = new StackLayout{
Children = {Routine_Name}
}
};
});
When I run this my ListView is displayed and the list items are indeed there (they have onclick handlers that work) but there is no text, which should be whatever is in _routine_names.
My question how do I get the Label in the DataTemplate to be items in _routine_names?
The reason I'm adding a DataTemplate is so I can add swipe to delete.
You can just use the built in TextCell for what you're trying to do. It has a bindable TextProperty and an optional DetailProperty if you want a smaller text line below the main one.
IList.ItempTemplate = new DataTemplate(()=>
{
var textCell = new TextCell();
textCell.ContextActions.Add(yourAction);
textCell.SetBinding(TextCell.TextProperty, ".");
return textCell;
}
IList.ItemsSource = _routine_names;
yourAction is of type MenuItem as seen here
Also, please notice that IList is a name of a class in System.Collection namespace so I'd use something else there.

How to Set Parent Panel Alignment of The Control Programmatically?

Background:
I have created a helper method to set properties of each TextBlockas per its adjacent TextBox for some scenarios in my application. In this method I already have the TextBlock object, the TextBox object and the parent object (it's always RelativePanel in my case).
The RelativePanel in my views always contain only TextBox & TextBlock.
// Helper Method
public static void SetPropertiesOfEachTextBlock(IList<TextBox> boxes)
{
foreach (TextBox textBox in boxes)
{
var parent = VisualTreeHelper.GetParent(textBox) as RelativePanel;
foreach(var element in parent.Children)
{
if(element is TextBlock)
{
TextBlock textBlock = (TextBlock)element;
textBlock.FontSize = textBox.FontSize;
textBlock.Margin = textBox.Margin;
textBlock.FontWeight = textBox.FontWeight;
textBlock.Foreground = new SolidColorBrush(Colors.Gray);
// Here I need to set alignment to the adjacent TextBox by the RelativePanel
}
}
}
}
Relative Panel Sample:
<RelativePanel>
<TextBox Name="UserName"/>
<TextBlock RelativePanel.AlignLeftWith="UserName" />
</RelativePanel>
Question:
How can I set the following property of TextBlock programmatically:
RelativePanel.AlignLeftWith="UserName"
AlignLeft is an Attached Property and can be found on RelativePanel itself. You set them like this:
RelativePanel.SetAlignLeftWith(element, UserName);
You can read the docs on the property here:
Edit: fixed syntax error based on comment

WPF read Checkbox.Content

I have a couple of CheckBoxes with a TextBlock as content.
Now I want to read out the TextBlock.Text from each Checkbox.
If I read out the content like checkBox.Content.ToString(); I only get System.Windows.Controls.TextBlock which kinda makes sense.
I also tried to create a new TextBlock and give it the content but it didn't work.
TextBlock _tempTBL = new TextBlock();
_tempTBL = checkBox.Content;
Any help is much appreciated.
var _tempTBL = (TextBlock) checkBox.Content; //Get handle to TextBlock
var text = _tempTBL.Text; //Read TextBlock's text
Edit:
On a side note, you can directly set desired text as CheckBox's content.
checkBox.Content = "Hello World";
And when you want to access the text, no type cast is needed
string text = checkBox.Content;
You have to cast the type to a TextBlock:
// no need to 'new' it up if you're assigning an existing instance...
TextBlock _tempTBL = (TextBlock) checkBox.Content;

how to add EntryCell to Xamarin.Forms Content

I am new on Xamarin.Forms and I am trying to use EntryCell
AccountId = new EntryCell {Label="Account Id", Text = CustomersPage.staticCustomer.AccountId};
When I am trying to add EntryCell to content page:
Content = new StackLayout {
Children = {
AccountId
}
};
I get the following error:
The best overloaded Add method
'System.Collections.Generic.ICollection.Add(Xamarin.Forms.View)'
for the collection initializer has some invalid arguments
Why can't I add EntryCell directly just like Entry?
EntryCell doesn't derive from View, therefore you cannot add it as a child to StackLayout children collection.
EntryCell is intented to use with ListView (also with TableView) control, generally due to performance reasons. EntryCell derives from Cell which provides description of a visual element rather than is a visual element.
On the other side Entry derives from View, thus you can add it to StackLayout.
Actullay I was searching away to use Label And Text on the same time So
As #Arkadiusz said
I used TableView like that :
TableView tb = new TableView();
tb.Root = new TableRoot() { new TableSection("Info") { AccountId }};
Content = new StackLayout { Children={ tb, ProcessToCheckOut } }
or
I need to user Entry && Label instead of EntryCell And Change stackLayout orientation To Horizontal

Add Children to element of type Page created in code behind Windows Phone 8.1

I can create a new element of type Page in code behind, but I want to add children elements of type UIElement as I would to a Grid like: myGrid.Children.Add(myUIElement);
I don't have the Children property and setting the Content property does not work.How can I achieve this?
UPDATE:
This is what I have so far, but does not work:
Page myNewPage = new Page();
Grid myGrid = new Grid();
TextBlock myText = new TextBlock();
myText.Text = "I am a TextBlock!";
myGrid.Children.Add(myText);
myNewPage.Content = myGrid;
Frame.Navigate(myNewPage.GetType());
A Page can host a single UIElement in its Content property. To add several children, you have to do it like you would do it in XAML: add a panel that can contain and layout several children and add your elements to that panel.
In your question you talk about a grid called myGrid. You could add and layout your items in myGrid and then set myGrid as yourPage.Content.
Your code correctly builds the page. The problem with your code is that your Frame is navigating to a new instance of Page that is not the one that you created. Frame creates a new instance of the type that you pass as a parameter.
If you want to create a page fully in code, you can simply create class that extends Page and build the page in its constructor:
public class MyPage : Page
{
public MyPage()
{
this.BuildPage();
}
private void BuildPage()
{
var panel = new StackPanel();
panel.Children.Add(new TextBlock { Text = "Hello" });
panel.Children.Add(new TextBlock { Text = "World" });
this.Content = panel;
}
}
That's, after all, what the InitializeComponent method does in pages created in XAML.

Categories