How to use Xamarin to call an UI Element with a bound name - xaml

I'm trying to use a custom variable to name UI Elements in XAML in order to use them in my Xamarin code. How would I do that?
I know that I can use the tags
<Label x:Name="CallVariable" Text="This will appear"/>
and I can call the label from Xamarin using
Label foo = FindByName("CallVariable") as Label;
and mess with the text with the following
foo.Text == "This will appear"
which should return true.
I learned about binding, and so I tried to use this in my variables.
<Label x:Name={Binding Name}/>
Label bar = FindByName(emp.training[i] as Label);
Unfortunately, every time I run it, I'm receiving the error:
System.NullReferenceException: Object reference not set to an instance of an object.
I remembered to set the BindingContext. And in case it's important, this is all happening within a list view.
Is x:Name a bindable object? Or is there another method I should be using? Maybe a way to call an object based on its label, or something?
My current task is as follows:
I have a list of people's information. Name, Age, Gender, Email, Location, and a few other pieces of information. I'm trying to get someone to search for certain types of people, have it return a list of everyone in a ListView, and have the person be able to select as many as they want. I did this using a button that adds the person to a list (or removes them from the list if they're already on). If the user chooses to, they should be able to also click "Select All" to add everyone. I've got the individual adding down, I just need to somehow select all of them.

You can't access the label with a listView by x:Name in code behind. Instead of access the label in the listView, you can bind the property of label in code behind. For example:
<ListView x:Name="testListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Name}" />
<Label Text="{Binding Desc}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And in code behind, it should be:
public partial class MainPage : ContentPage
{
ObservableCollection<testViewModel> myModels = new ObservableCollection<testViewModel>();
testViewModel model;
public MainPage()
{
InitializeComponent();
testListView.ItemsSource = myModels;
myModels.Add(new testViewModel { Name = "age" });
myModels.Add(new testViewModel { Name = "gender" });
myModels.Add(new testViewModel { Name = "name" });
}
}
class testViewModel
{
public string Name { get; set; }
public string Desc { get; set; }
}
Next time you want to update the text of label:
public void test() {
//Get the model you want to change
model.Desc = "This will appear";
}
I've got the individual adding down, I just need to somehow select
all of them.
I don't know how you implement the individual adding down, share the code and maybe I can give you some suggestions.

Related

Localize strings in XAML UI in UWP

I have a resource entry named info_278 in the Resources.resw file on my UWP app. I have 3 scenarios where I need to use this resource but looks like I need to duplicate this to cater to different scenarios. Scenarios are as follows.
Error message content from code
var displayErrorOnPopup = ResourceHandler.Get("info_278");
TextBlock Text property from XAML (Looks like a new entry needed as info_278.Text)
<TextBlock x:Uid="info_278" Margin="10,0,0,0" />
Button Content property from XAML (Looks like a new entry needed as info_278.Content)
<Button x:Uid="info_278" Margin="10,0,0,0" />
How do I proceed without duplicating this resource in the .resw file?
The only way to avoid duplication is to set the string value in code-behind using ResourceLoader. Because you could direct access to the specific property of the target control. Like this:
var resourceLoader = Windows.ApplicationModel.Resources.ResourceLoader.GetForCurrentView();
this.TextBlock.Text = resourceLoader.GetString("info_278");
If you are not going to do it in the code behind, then I have to say there is no way to avoid the duplication of the resource string. You should add info_278.Text and info_278.Content for different XAML scenarios.
You could create a markup extension. I've used this in WinUI 3, but should work in UWP too.
using Microsoft.UI.Xaml.Markup;
using Windows.ApplicationModel.Resources;
namespace MyApp;
[MarkupExtensionReturnType(ReturnType = typeof(string))]
public class StringResourceExtension : MarkupExtension
{
private static readonly ResourceLoader _resourceLoader = new();
public StringResourceExtension() { }
public string Key { get; set; } = "";
protected override object ProvideValue()
{
return _resourceLoader.GetString(Key);
}
}
Then in the XAML:
...
local="using:MyApp"
...
<TextBlock Text="{local:StringResource Key=info_278}" />
<Button Content="{local:StringResource Key=info_278}" />
The Content of Button can be a TextBlock:
<Button>
<TextBlock x:Uid="MyTextId" Style="{StaticResource MyTextBlockStyle}" />
</Button>

Dynamically change DataTemplate for a ListView at Runtime

I have 2 DataTemplates for displaying the contents of ClassA or ClassB inside a single ListView; which template to select will be based on a RadioButton selection by the user.
Is it possible to change the ItemTemplate of a ListView (in XAML) based on user input dynamically at runtime?
An example snippet of code:
XAML Page:
<Page...>
<Page.Resources>
<DataTemplate x:Key="ClassAListViewItemTemplate" x:DataType="vm:ClassA" ... />
<DataTemplate x:Key="ClassBListViewItemTemplate" x:DataType="vm:ClassB" ... />
</Page.Resources>
<RelativePanel>
<RadioButton Content="ClassA" ... />
<RadioButton Content="ClassB" ... />
<ListView DataContext="{Binding Path=MainViewModel}"
ItemsSource="{Binding ListOfClassAOrB, Mode=TwoWay}"
ItemTemplate="{StaticResource ClassAListViewItemTemplate}"/>
</RelativePanel>
</Page>
I have stripped the code down somewhat to the essentials, but I would like to be able to change the following at runtime:
ItemTemplate="{StaticResource ClassAListViewItemTemplate}"
I have seen solutions for Classic WPF applications that use Style.Triggers, but these aren't applicable for UWP
Marco Minerva's blog on Adaptive Triggers, RelativePanel and DataTemplate in the Universal Windows Platform talks of using UserControls within DataTemplates to modify the visual state using Adaptive Triggers, but this doesn't take into account switching out of templates based on user input
The closest answer I have found to my problem is another blog he wrote "Dynamically choose DataTemplate in WinRT" where there is an element of code-behind involved - but it only appears to be an if statement - but its the cleanest solution I have come across thus far, and what I'd like to replicate in XAML
Thanks
you need to use overwrite SelectTemplateCore of Data template. Change your view model like this.
Below code will helps you.
public class SampleViewModel : DataTemplateSelector
{
public DataTemplate ClassAListViewItemTemplate{ get; set; }
public DataTemplate ClassBListViewItemTemplate{ get; set; }
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
{
var itemsData = item as SampleClass; // add your Data class
if (itemsData.IsAddButton == false) // define any property to select the datatemplate
{
return ClassAListViewItemTemplate;
}
else
{
return ClassBListViewItemTemplate;
}
}
}
Add your two datatemplates to one key, and give the key to ItemTemplateSelector property in gridview.
<viewModels:SampleViewModel x:Key="FeedbackTempateSelector"
ClassAListViewItemTemplate="{StaticResource ClassAListViewItemTemplate}"
ClassBListViewItemTemplate="{StaticResource ClassBListViewItemTemplate}">
</viewModels:SampleViewModel>

How to use template selector within a ContentPresenter in Windows 8.1

I have a Windows 8.1 application. I have a requirement of selecting different templates based on a certain value. For this purpose I'm using ContentPresenter in the xaml with a Static Resource TemplateSelector.
Here's my datatemplates and templateselector in xaml resources
<DataTemplate x:Key="template1">
<TextBox Text="Temp 1" />
</DataTemplate>
<DataTemplate x:Key="template2">
<TextBox Text="Temp 2" />
</DataTemplate>
<DataTemplate x:Key="template3">
<TextBox Text="Temp 3" />
</DataTemplate>
<template:BalanceTypesTemplateSelector x:Key="MySelector"
Template1="{StaticResource template1}"
Template2="{StaticResource template2}"
Template3="{StaticResource template3}" />
Here's my ContentPresenter XAML
<ContentPresenter ContentTemplateSelector="{StaticResource MySelector}"
Content="{Binding MyData}" />
Here's my Template Selector Code
public class BalanceTypesTemplateSelector : DataTemplateSelector
{
public DataTemplate Template1 { get; set; }
public DataTemplate Template2 { get; set; }
public DataTemplate Template3 { get; set; }
protected override DataTemplate SelectTemplateCore(object item)
{
var type = item.ToString();
switch (type)
{
case "t1":
return Template1;
case "t2":
return Template1;
case "t3":
return Template3;
default:
throw new NotSupportedException();
}
}
return null;
}
}
But it's not hitting the templateselector code at all. The string that is bound is directly displayed on the display when I run the app.
I would be glad if some one point me in the right direction. Thanks in Advance.
Basically, you're only overriding one of the SelectTemplateCore overloads.
From the DataTemplateSelector docs:
To define an effective DataTemplateSelector subclass, provide implementations for SelectTemplateCore(Object) and SelectTemplateCore(Object, DependencyObject)
Once you provide an implementation for SelectTemplateCore(Object, DependencyObject), it will get invoked.
I tried to do it, but there was another problem I encountered - the object is always null (and not the Content/DataContext of the ContentPresenter).
I asked Google why is that and found this discussion. From it:
The ContentControl and ContentPresenter appear to be broken in Windows RT when used with a ContentTemplateSelector property bound to a view model. The 'object' parameter to the template selector is always null.
There's also a workaround for this problem at the end of that discussion.
Hope this helps. :)
Using ContentControl instead of ContentPresenter is working for me. Thanks #KaiBrummund for his comment on my question.

PivotItem header changes during runtime

I ran into a weird problem working with the Windows Phone 8 pivot control.
Apparently, when the Pivot is bound to a list of models and the HeaderTemplate is used for binding to one of the model's properties, changing the property during runtime causes layout problem in the headers.
Here is the sample code.
Create a simple model class.
public class MyModel: INotifyPropertyChanged
{
private string _displayName;
public event PropertyChangedEventHandler PropertyChanged;
public string DisplayName
{
get
{
return _displayName;
}
set
{
_displayName = value;
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("DisplayName"));
}
}
}
}
Then initialize the model list (could occur in the ViewModel, or page's code)
Items = new List<MyModel>
{
new MyModel { DisplayName = "model 1" },
new MyModel { DisplayName = "model 2" },
}
Connecting the list of models to the pivot control
<phone:Pivot ItemsSource="{Binding Items}" DisplayMemberPath="DisplayName">
<phone:Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</phone:Pivot.HeaderTemplate>
</phone:Pivot>
So now we have 2 pivot items and the headers are displayed correctly. Now we change DisplayName property of the first item during app runtime (say following a button click) and assign a longer string value:
Items[0].DisplayName = "Some other header";
This causes the headers to overlap.
Any thoughts?
Elad
if you set displayName property to "Some other header" at first time, and then change the value to "model 2", normal display. So, in my opinion, this problem was caused by the pivot header width property(in your code,the textblock's width). When the pivot was loaded, every header had fixed width, and at this time, you changed the header display name to a longger value, the pivot will not be display correctly.

Change font colour inside combo box, data coming from SQL

Hard to put into words for title. I have a normal WPF combo box and the data (list of names) is getting pulled from SQL and I want to change the text colour and
Foreground ="Black"
only seems to be working when I actually select the user. Any suggestions how else I can change this?
EDIT: I haven't tried any other things as of yet as I know that way to actually change the text colour.
EDIT2:
<ComboBox x:Name="cmbDepartment" HorizontalAlignment="Left" Height="25" Margin="92,580,0,0" VerticalAlignment="Top" Width="400" Foreground="#FFA2A2A2" FontSize="13"/>
This is my XAML code for the combo box. I have figured out that my theme is making it blue but when I change the font colour on my theme everything then turns that colour in my application. Is there a piece of code that I can write in my XAML which will set the colour of everything in the combo box grey, without changing the colours in my application.
I assume that initially the ComboBox shows no selected value and once you click on it it shows the list of names with the proper color (being whatever color you assigned through the Foreground property).
If so, may it be the case that you haven't selected an item? Once you have set the items, you must select an item (e.g. SelectedIndex, SelectedValue) if you don't want the ComboBox selection to appear empty.
Excuse me if this is not the case, but the question was pretty vague..
Here is a example using MVVM
XAML
<Window x:Class="SelfBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox ItemsSource="{Binding MyItems}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Foreground="{Binding Name}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
codebehind
using System.Collections.Generic;
using System.Windows;
namespace SelfBinding
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
public class MyViewModel
{
public List<MyItem> MyItems { get; set; }
public MyViewModel()
{
MyItems = new List<MyItem>();
MyItems.Add(new MyItem { Name = "Black" });
MyItems.Add(new MyItem { Name = "Red" });
MyItems.Add(new MyItem { Name = "Orange" });
MyItems.Add(new MyItem { Name = "Green" });
}
}
public class MyItem
{
public string Name { get; set; }
}
}
to test it on your on create a new WPFproject an copy & past the code
Maybe you can override the theme colors in the combobox resources. This is an exaple for doing so.
I just don't know what exactly is the key that you need to override. I guess you can google that.
good luck.