Using TargetName reference in VisualStates in MAUI in C# (NOT Xaml)
I am posting it here at the recommendation of a Microsoft developer following my initial post on MAUI community support forum (https://learn.microsoft.com/en-us/answers/questions/1183810/using-targetname-reference-in-visualstates-in-maui)
Per Microsoft, it is possible to do MAUI development using C# only (no XAML). However, there appears to be no working C# equivalent to setting VisualStates which reference TargetName.
Here's an example. I need to make a label visible when a CollectionView item is selected, and invisible otherwise. This is easily accomplishable in XAML as follows:
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="sharedModels:Showuser">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter TargetName="LabelCheckMark" Property="IsVisible" Value="False"/>
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter TargetName="LabelCheckMark" Property="IsVisible" Value="True"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<HorizontalStackLayout>
<Label x:Name="LabelCheckMark" Text="X" />
<Label Text="{Binding Username}" />
</HorizontalStackLayout>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
I am replicating this functionality in C# as follows. I create a helper grid class:
public class pickerGrid : Grid
{
public pickerGrid() {
var vsg = new VisualStateGroup() { Name = "vsg" };
var vs_nor = new VisualState { Name = "Normal" };
var vs_sel = new VisualState { Name = "Selected" };
var LabelCheckMark = new Label {
Text = "X",
};
var LabelName = new Label();
LabelName.SetBinding(Label.TextProperty, "Name", BindingMode.Default, null, "{0}");
vs_nor.Setters.Add(new Setter { TargetName = "LabelCheckMark", Property = IsVisibleProperty, Value = false });
vs_sel.Setters.Add(new Setter { TargetName = "LabelCheckMark", Property = IsVisibleProperty, Value = true });
var sl = new HorizontalStackLayout() {
Children = {
LabelCheckMark,
LabelName,
}
};
this.Add(sl);
vsg.States.Add(vs_nor);
vsg.States.Add(vs_sel);
VisualStateManager.GetVisualStateGroups(this).Add(vsg);
}
}
which I can then use for my CollectionView:
CollectionView _makeCollectionView() {
var cV = new CollectionView();
cV.SetBinding(ItemsView.ItemsSourceProperty, "ViewModel_Contacts");
cV.SelectionMode = SelectionMode.Multiple;
cV.SelectionChanged += OnSelectionChanged;
cV.ItemsLayout = new GridItemsLayout(ItemsLayoutOrientation.Vertical) {
VerticalItemSpacing = 6
};
cV.ItemTemplate = new DataTemplate(typeof(pickerGrid));
return cV;
}
and finally I use the created collection view in my window:
Content = new VerticalStackLayout {
Children = {
_makeCollectionView()
}
};
However, the TargetName reference fails, because the "x:Name" property is not available in C#. The exception thrown is System.InvalidOperationException Message this element is not in a namescope.
Hi @quibenefacit. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md
This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
Could you write a sample program of how you're trying to do this? If "The TargetName reference fails" I assume that means the VisualStateManager is throwing an exception? Or are you unable to write out the code?
Hi, I have updated my initial post with the C# code and other information you have requested.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
@quibenefacit if you look at the code here you'll see a demo of how-to setup your own namescopes.
@quibenefacit if you look at the code here you'll see a demo of how-to setup your own namescopes.
Thank you, this works! I suggest converting this issue from needing implementation to needing documentation.
In case anyone else will need it, the link changed to this
if you look at the code here you'll see a demo of how-to setup your own namescopes.
In case anyone else will need it, the link changed to this
@PureWeen @pr0skilled
I have this issue as well, though i dont understand how what is linked resolves the issue, and certainly dont see a "demo" Please advise
Verified this issue with Visual Studio Enterprise 17.9.0 Preview 1.0. Can repro this issue.
I run on a very similar issue just now, i could make it work. You need to set the namescope and then register the names, like this.
using Microsoft.Maui.Controls.Internals;
...
var label = new Label {
Text = "X",
};
INameScope nameScope = new NameScope();
NameScope.SetNameScope(/*yout root view*/, nameScope);
//nameScope.RegisterName("Root", /*yout root view*/); //not necesary, but if u need it
nameScope.RegisterName("NameHere", label);
...
afther that you can use TargetName = "NameHere" on setters. You can also use .FindeByName("NameHere") method on the created view.