XAML button content changing based on VB variable - vb.net

Beginner here. I want to create a button in XAML which has text based on a variable in VB. I have the variable set in VB with
Dim ButtonName1 = "Test"
What will I need to do to make the button content display ButtonName1?

It is really quite easy. Your Button has a Name Property that you can use to reference it in your code behind, note in this example it is Button1 you just need to assign your string to the Button's Content Property
Xaml
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />
xaml.vb
Dim ButtonName1 = "Test"
Button1.Content = ButtonName1

Related

Cannot bind to button events using x:Bind in DataTemplates - generates XAML error

With the {x:Bind} markup syntax you can bind to events provided the method meets the following requirements:
Match the signature of the event.
OR have no parameters.
OR have the same number of parameters of types that are assignable from the types of the event parameters.
This works perfectly fine outside of a DataTemplate. Once the binding happens inside the DataTemplate the compiler generates the following error:
Xaml Internal Error error WMC9999: Object reference not set to an
instance of an object.
What is the fix for binding to events inside DataTemplates?
Full example code here.
Snippet of the example code below - note the first button (line 2) is fine and the second button (line 6) is also fine. If you comment out line 6 and and comment in line 7, the error occurs.
<StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Tapped="{x:Bind Click}" Content="WORKING"/>
<ListView ItemsSource="{x:Bind Names}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Customer">
<Button Content="{x:Bind Title}"/>
<!--<Button Tapped="{x:Bind Clicky}" Content="{x:Bind Title}"/>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
I was able to get it to work with the following code:
<DataTemplate x:DataType="local:Customer">
<StackPanel Orientation="Vertical">
<Button Tapped="{x:Bind Clicky}" Content="{x:Bind Title}" />
</StackPanel>
</DataTemplate>
It seems as though you need to have it inside a container for it work. I have no idea why I am guessing magic.
The parser cannot find Clicky from the datacontext of the button while in the template. Because the object that is being handed to the button in the template (from the Names on the ItemSource of the parent) is not the same as outside the template which has a Clicky. You will need to bind Clicky to the page's datacontext to get it to work.
Otherwise turn off any design time operations by setting Tapped="{x:Bind Clicky, IsDesignTimeCreatable=False}.

Using x:Bind inside the GridView's ItemTemplate layout User Control in UWP

In the Universal Windows Platform API, how do I use x:Bind inside of a User Control (intended to be the layout for a GridView's ItemTemplate) to bind to instance properties of a GridView's ItemSource?
Background
I'm trying to re-create the layout found in Windows 10 stock apps like Sports, News, Money, etc.
I'm using a two GridViews for the main area of the app; one for "featured articles" (2 large photos w/ headlines) and one for all the other articles (smaller photos w/ headlines).
I'm able to bind to a data source that I supply in the code behind (a List where NewsItem is a POCO with a Image and Headline property) Here's the pertinent parts of the MainPage.xaml:
<Page ...
xmlns:data="using:NewsApp.Models" />
....
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
....
The Image and Headline bind just fine (even though they've not been styled correctly). However, instead I think I need to bind to a User Control to get the styling options I want, control over resizing esp. when using Visual State Triggers and to simplify the XAML in general (at least, this was the technique suggested to me.)
So, I added a new User Control to the project (FeaturedItemControl.xaml), and copied in the DataTemplate's child Grid:
<UserControl ... >
<Grid Name="mainPanel" HorizontalAlignment="Stretch" Width="500" >
<Image Source="{x:Bind Image}" HorizontalAlignment="Stretch" />
<TextBlock Text="{x:Bind Headline}" />
</Grid>
</UserControl>
And then back in the MainPage.xaml, I change the DataTemplate to reference the new FeaturedItemControl:
<GridView Name="FeaturedItems" Grid.Row="0">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:NewsItem">
<local:FeaturedItemControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
However, I get the error message for both Image and Headline properties: Invalid binding path 'Headline': Property 'Headline' can't be found on type 'FeaturedItemControl'.
I've tried a few things but am flailing just throwing code at the problem without understanding what I'm doing. Any help would be greatly appreciated.
Thank you for your kind attention.
Using Depechie's answer, I formulated this little cheat cheat for posterity:
Do note that you MUST use this technique to utilize the VisualStateManager with items inside your data bound controls' (GridView, ListView) data templates.
1) Create a User Control.
2) Cut the content of the DataTemplate in your page and paste it into the User Control replacing the template's Grid.
3) Reference the User Control from inside the Data Template:
4) Modify the contents of the User Control changing x:Bind statements to utilize object.property notation:
<UserControl>
<StackPanel>
<Image Source="{x:Bind NewsItem.LeadPhoto}" />
<TextBlock Text="{x:Bind NewsItem.Headline}" />
<TextBlock Text="{x:Bind NewsItem.Subhead}" />
</StackPanel>
</UserControl>
5) Add this in the User Control's Code Behind:
public Models.NewsItem NewsItem { get { return this.DataContext as Models.NewsItem; } }
public ContactTemplate()
{
this.InitializeComponent();
this.DataContextChanged += (s, e) => Bindings.Update();
}
Well it's possible to use x:Bind in user controls, but you'll need to add some extra code behind.
I encountered the same problem in my project, you can see the result here : https://github.com/AppCreativity/Kliva/tree/master/src/Kliva/Controls
So what you need to do is, create a property in the code behind of your user control that points to the correct DataContext.
If you do that, you can use properties of that DataContext in the xaml of your control: for example:
Do note that in the constructor of your control you do need to add: DataContextChanged += (sender, args) => this.Bindings.Update(); because the datacontext will change depending on the page where your control is used!
Then on the page where you are placing this control, you'll also need to do the same to enable the x:bind to work.
You'll see this in my example on the MainPage.DeviceFamily-Mobile.xaml and MainPage.xaml.cs files.
Hope this helps.
x:Bind isn't really hierarchical like Binding/DataContext is. Additionally when you're not directly inside a DataTemplate (such as inside your user control) the object that x:Bind tries to use is 'this' rather than 'this.DataContext'. My current line of thinking on how to solve this sort of issue is to try not to use UserControls anywhere. Instead preferring DataTemplates contained within a ResourceDictionary. There are some pretty strong caveats to this approach though, you will for example crash the xaml compiler if you use x:Bind inside a data template that was created from the ResourceDictionary item template (add new item). you can find a pretty complete example here https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/XamlBind its important to note in the sample where they show the ResourceDictionary being used that its not actually just a ResourceDictionary.xaml its also a ResourceDictionary.xaml.cs (this is where the generated code from x:Bind ends up)
Another option is to add Headline and Image as properties on your user control and x:Bind them from the template, then inside the user control x:Bind as you are currently doing, but now the x:Bind generated path 'this.Headline' will exist. Unfortunately the order things are actually bound means that the x:Bind's you have inside your user control will have to be OneWay rather than the default OneTime. this is because x:Bind OneTime does the bind inside the InitializeComponent call, and any set of properties/DataContext stuff doesn't get done until after that has already run.
So to sum this up, you have two options, use data templates everywhere, or bind to properties that are directly on the user control.

App crashing when assigning button-name through binding

I have buttons in a listbox and for each of them, I want
to provide a different name. This is how I setup the binding in XAML:
<Button Content="{Binding count}"
x:Name="{Binding buttonName}"
Width="55"
Height="55"
BorderThickness="3"
FontSize="18.667"
Padding="-1,-2,0,0"
Margin="-400,0,0,0"
FontWeight="Bold"
Click="servingButtonClicked" />
buttonName is a string, which is stored in an object in a LinkedList<string> as an itemSource for this listBox.
Why won't this work?
Error:
Object reference not set to an instance of an object.
x:Name must not bet via DataBinding - this is a name for the instance of the object, not something dynamic.

Silverlight Find Control in Data Template

I have the following xaml code:
<dxb:BarButtonItem Name="btnPrev" Cursor="Hand" ItemClick="btnPrev_ItemClick">
<dxb:BarButtonItem.ContentTemplate>
<DataTemplate>
<Image x:Name="imgSkipLeft" Source="/ProjectTool;component/images/arrowleft.png" Height="16" Width="16">
<ToolTipService.ToolTip>
<TextBlock x:Name="txtBlockTip_Left"/>
</ToolTipService.ToolTip>
</Image>
</DataTemplate>
</dxb:BarButtonItem.ContentTemplate>
</dxb:BarButtonItem>
How can I find txtBlockTip_Left and modify the text
Rather that trying to find the TextBlock on the DataTemplate to change the text it would be better to set the text through a binding and then change the property that the Text property is bound to. The following resource has an example on how to use data binding within a DataTemplate: http://www.silverlight.net/learn/data-networking/binding/data-binding-to-controls-%28silverlight-quickstart%29
Using the VisualTreeHelperExtensions class and put a grid inside the data template and give it a name, in the example below the name is grdTemplate.
var bttn= btnPrev.ItemContainerGenerator.ContainerFromItem(btnPrev);
var dataTemplate = bttn.GetDescendantsOfType<Grid>().FirstOrDefault(g => g.Name == ("grdTemplate"));
var textBlocks= VisualTreeHelperExtensions.GetDescendantsOfType<TextBlock>(dataTemplate);
TextBlock txtBlockTip_left = textBlocks.ElementAt(0);

Referencing XAML Custom Control names and properties within VB Code Behind

Sorry for the basic questions, but I've been searching the web for a number of days and can't find the answer to these questions.
I've created a Custom Control, and I will be placing a large number of instances of that Custom Control on my xaml page. In working with that Custom Control in the VB Code Behind, how do I do the following?
How do I reference the name of the Custom Control (in my VB code) which was clicked with the MouseLeftButtonDown event? For example, if I have 10 instances of my Custom Control in xaml, each with a different x:name (say 1-10), when a particular instance is clicked, how can I see which one was clicked? I've tried a number of things including e.OriginalSource.Name (which returns the component within the control which was clicked and not the name of the instance of the control).
My Custom Control consists of numerous parts and pieces (Rectangles, Lines, Text, etc). Each of these items is a part of my layer. In VB code, once I can reference a particular Control, how can I hide or change certain parts of that control (such as hiding a Line, and changing the text). Also, I need to modify more than just the control which was clicked, so I need to be able to access properties of all of the controls, not just what was clicked. For example, if I click Control instance Test1, I also need to modify Test2, Test3, and Test5 in some way.
Here is some test code I through together as part of a Silverlight project using MS Blend 2. My control is much larger, and I need 200 - 250 instances/copies of that custom control, so I really need to know which control instance/copy was clicked.
My UserControl:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="MyControl1"
x:Name="UserControl"
d:DesignWidth="60" d:DesignHeight="59">
<Grid x:Name="LayoutRoot" MouseLeftButtonDown="OnMouseClick">
<Rectangle x:Name="Rectangle1" Fill="#FFFFFFFF" Stroke="#FF000000"/>
<TextBox Background="{x:Null}" x:Name="TextBox1" Text="Test" TextWrapping="Wrap"/>
<Ellipse x:Name="Circle1" Fill="{x:Null}" Stroke="#FF000000"/>
<Path Margin="1,29,0,29" x:Name="Line1" Fill="{x:Null}" Stretch="Fill" Stroke="#FF000000" Data="M74,80 L132,80"/>
<Path Margin="0,0,1,14" x:Name="Line2" VerticalAlignment="Bottom" Height="1" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" Data="M73,95 L131,95"/>
<Path Margin="0,0,0,4" x:Name="Line3" VerticalAlignment="Bottom" Height="1" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" Data="M73,105 L132,105"/>
</Grid>
</UserControl>
My xaml App using the Custom Control:
<Grid x:Name="LayoutRoot">
<Tester:MyControl1 HorizontalAlignment="Left" Margin="56,54,0,0" VerticalAlignment="Top" Width="60" Height="60" x:Name="Test1"/>
<Tester:MyControl1 HorizontalAlignment="Left" Margin="116,54,0,0" VerticalAlignment="Top" Width="60" Height="60" x:Name="Test2"/>
<Tester:MyControl1 HorizontalAlignment="Left" Margin="176,54,0,0" VerticalAlignment="Top" Width="60" Height="60" x:Name="Test3"/>
<Tester:MyControl1 HorizontalAlignment="Left" Margin="236,54,0,0" VerticalAlignment="Top" Width="60" Height="60" x:Name="Test4"/>
<Tester:MyControl1 HorizontalAlignment="Left" Margin="296,54,0,0" VerticalAlignment="Top" Width="60" Height="60" x:Name="Test5"/>
</Grid>
My Custom Control VB Code:
Partial Public Class MyControl1
Public Sub New()
MyBase.New()
Me.InitializeComponent()
' Insert code required on object creation below this point.
End Sub
Private Sub OnMouseClick(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
Dim int_Temp As Integer
Dim str_InstanceName As String
str_InstanceName = "1.What code here tells me the name of the instance which was checked? Test1, Test2, etc. for example."
int_Temp = MessageBox.Show(str_InstanceName, "Testing", MessageBoxButton.OK)
'2.What code here lets me manipulate parts of my control instances (and not just the instance which was clicked)?
'I want to hide Test1.Line1 and Test2.Line3 and Test3.Circle1 and change the background of Test5.Rectangle1 for example.
End Sub
End Class
Thanks in advance, and sorry to all the C# experts that I need this in VB.
It looks like you're talking about a User Control, not a Custom Control. There is a little bit of a difference when working with the two. You can read more about those differences here:
Custom Controls Vs. User Controls
In this case, you want to be looking at the 'sender' object in your event handler. You want to cast the sender as your User Control (this will be safe since you're only using that event handler on controls of your type).
Private Sub OnMouseClick(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
Dim senderAsControl As MyControl1 = sender As MyControl1
' Get the instance name from the sender
Dim instanceName As String = senderAsControl.Name
' You can also access your children from the sender once cast
senderAsControl.Rectangel1.IsVisible = False ' Hide the rectangle
End Sub
I can't compile the code to double check myself at the moment...but it should give you the idea.