问题
I have a Model that contains some data, and a field that can have one of three (enum) values.
Socket,
Tcp,
Udp
And a View that shows some details.
The details that I want shown in the view differ according to the value of this property in the model.
I have read all about ItemTemplates for Lists and Pickers, and I want to do something similar but just with a single view bound to a single property.
If Socket
=> Show this view
else => Show this other view.
Both views have the same viewmodel.
View
<ContentView.Resources>
<local:SocketServerSocketView x:Key="ServerSocket" />
<local:SocketServerTcpUdpView x:Key="ServerTcpUdp" />
</ContentView.Resources>
...
<ContentView Grid.Column="2" Margin="12" >
<ContentView.Content>
<local:SocketServerTcpUdpView />
</ContentView.Content>
<ContentView.Style>
<Style TargetType="ContentView">
<Style.Triggers>
<DataTrigger TargetType="{x:Type ContentView}" Binding="{Binding Mode}" Value="{Binding models:NetworkMode.Socket}">
<Setter Property="Content" Value="{StaticResource ServerSocket}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentView.Style>
</ContentView>
So I start (by default) displaying the TCP version, and want to dynamically switch it out for the socket template when the value of the enum changes. What am I doing wrong?
回答1:
We can refer to Data Triggers documents to know how to achieve that .
Create a sample ViewModel model only contains Model
property inside it .
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int model;
public int Model
{
set
{
if (model != value)
{
model = value;
OnPropertyChanged("Model");
}
}
get
{
return model;
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Then we can create two sample ContentView
to replace SocketServerSocketView
and SocketServerTcpUdpView
as follow :
SocketServerTcpUdpView:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="AppTriggerType.SocketServerTcpUdpView">
<ContentView.Content>
<StackLayout BackgroundColor="Azure">
<Label Text="SocketServer TcpUdpView!"
VerticalOptions="Center" />
</StackLayout>
</ContentView.Content>
</ContentView>
SocketServerSocketView:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="AppTriggerType.SocketServerSocketView">
<ContentView.Content>
<StackLayout BackgroundColor="Beige" >
<Label Text="SocketServer SocketView!" />
</StackLayout>
</ContentView.Content>
</ContentView>
Now in Xaml of ContentPage
,we can defined as follow :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AppTriggerType"
mc:Ignorable="d"
x:Class="AppTriggerType.MainPage">
<ContentPage.Resources>
<local:SocketServerSocketView x:Key="ServerSocket" />
<local:SocketServerTcpUdpView x:Key="ServerTcpUdp" />
</ContentPage.Resources>
<StackLayout>
<!-- Place new controls here -->
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="Start" />
<Button Text="ServerSocket"
Clicked="Button_Clicked_ServerSocket"/>
<Button Text="ServerTcpUdp"
Clicked="Button_Clicked_ServerTcpUdp"/>
<ContentView x:Name="MyContentView"
Margin="12"
VerticalOptions="FillAndExpand">
<ContentView.Content>
<ContentView />
</ContentView.Content>
<ContentView.Triggers>
<DataTrigger TargetType="{x:Type ContentView}"
Binding="{Binding Source={x:Reference MyContentView}, Path=BindingContext.Model}"
Value="1">
<Setter Property="Content"
Value="{StaticResource ServerSocket}" />
</DataTrigger>
<DataTrigger TargetType="{x:Type ContentView}"
Binding="{Binding Source={x:Reference MyContentView}, Path=BindingContext.Model}"
Value="2">
<Setter Property="Content"
Value="{StaticResource ServerTcpUdp}" />
</DataTrigger>
</ContentView.Triggers>
</ContentView>
</StackLayout>
</ContentPage>
Last bind data for MyContentView
in ContentPage.xaml.cs :
public partial class MainPage : ContentPage
{
ViewModel viewModel = new ViewModel();
public MainPage()
{
InitializeComponent();
viewModel.Model = 1;
MyContentView.BindingContext = viewModel;
}
private void Button_Clicked_ServerSocket(object sender, EventArgs e)
{
viewModel.Model = 1;
}
private void Button_Clicked_ServerTcpUdp(object sender, EventArgs e)
{
viewModel.Model = 2;
}
}
Now we will see the effect as follow :
Here is the sample.
来源:https://stackoverflow.com/questions/63058029/switch-templates-in-xamarin-based-of-bound-property-not-itemtemplate