Xamarin Forms Switch Toggled 事件未与视图模型绑定
Posted
技术标签:
【中文标题】Xamarin Forms Switch Toggled 事件未与视图模型绑定【英文标题】:Xamarin Forms Switch Toggled event doesn't bind with viewmodel 【发布时间】:2017-04-25 12:48:54 【问题描述】:我有一个表单 XAML 页面,其中有一个列表视图,每个元素都有一个 Switch(xamarin 默认)。我可以将项目中的数据绑定到列表视图,但我不能订阅 Switch 事件“Toggled”,因为它会导致项目不显示。我也尝试使用 ICommand 和 Command,因为它被指示使用按钮,但结果是一样的,没有显示。如何处理来自我的视图模型的开关切换?
查看
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TouristicWallet.Views.WalletManagementPage"
xmlns:vm="clr-namespace:TouristicWallet.ViewModels"
xmlns:converters="clr-namespace:TouristicWallet.Converters"
>
<ContentPage.BindingContext>
<vm:WalletManagementViewModel x:Name="ViewModel"/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converters:CurrencyIdToCodeConverter x:Key="idToCodeConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="MyCurrencies" ItemsSource="Binding Currencies, Mode=OneWay">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="Binding Currency.Initials, Mode=OneWay" />
<Switch IsToggled="Binding IsOwned, Mode=TwoWay"
Toggled="Binding Toggled"
/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
视图模型
public class WalletManagementViewModel : ViewModelBase
private readonly List<OwnedCurrencyWrapper> _currencies = new List<OwnedCurrencyWrapper>();
public List<OwnedCurrencyWrapper> Currencies get return _currencies;
public WalletManagementViewModel()
CurrencyDataAccess cda = new CurrencyDataAccess();
foreach (var item in cda.GetCurrencies())
Currencies.Add(new OwnedCurrencyWrapper(item));
OnPropertyChanged(nameof(Currencies));
public class OwnedCurrencyWrapper
public Currency Currency get; private set;
public Boolean IsOwned get; set;
public ICommand Toggled get; set;
public OwnedCurrencyWrapper(Currency currency)
Currency = currency;
WalletDataAccess wda = WalletDataAccess.Instance;
IsOwned = wda.IsOwned(Currency.Id);
Toggled = new Command(() => Update());
public void Update()
WalletDataAccess wda = WalletDataAccess.Instance;
if (IsOwned) wda.RemoveOwnedCurrency(Currency.Id);
else wda.OwnCurrency(Currency.Id);
public void Toggled_handler(object sender, ToggledEventArgs e)
Update();
我没有使用任何 mvvm 框架
【问题讨论】:
【参考方案1】:首先,Switch 无法绑定到Command
。看:
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/#Commanding_with_ViewModels
从上面可以看出,可以绑定到ICommand
的 Forms 控件有:
您只需执行以下操作即可在 View 的代码隐藏文件中运行代码,请在 XAML 中执行此操作:
<Switch IsToggled="Binding IsOwned, Mode=TwoWay"
Toggled="Handle_Toggled" />
然后在代码隐藏文件中:
void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
// Do stuff
另外,由于您正在绑定,您可以在实际的 OwnedCurrencyWrapper
类中运行代码(这似乎是您想要的),只需将代码添加到 IsOwned
的设置器即可。在这种情况下,不要为你的开关的 Toggled 属性分配任何东西::
<Switch IsToggled="Binding IsOwned, Mode=TwoWay" />
然后在你的OwnedCurrencyWrapper
类中:
bool _isOwned;
public bool IsOwned
get
return _isOwned;
set
_isOwned = value;
// Do any other stuff you want here
也就是说,您的绑定不完整,因为您的视图模型没有实现INotifyPropertyChanged
,因此直接对视图模型所做的更改不会反映在 UI 中。有关与 Forms MVVM 绑定的更多信息,请参阅:
https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/
更新:我不知道 Xamarin 表单中的行为。看: https://github.com/xamarin/xamarin-forms-samples/tree/master/Behaviors/EventToCommandBehavior
在命令的上下文中,行为是将控件连接到命令的有用方法。此外,它们还可用于将命令与未设计用于与命令交互的控件相关联。此示例演示了在事件触发时使用行为来调用命令。
所以这应该允许您将 Toggled 事件绑定到命令。
【讨论】:
我正在实现 INotifyPropertyChanged,它在我的自定义 ViewModelBase 类中,我的所有 ViewModel 都在扩展。你的答案(两者,我现在在我的代码中保留第二种方式)实际上是我解决问题的方式,但这不是很像“MVVM”。 这是另一个选项,行为:github.com/xamarin/xamarin-forms-samples/tree/master/Behaviors/…“行为是将控件连接到命令的有用方法。此外,它们还可用于将命令与并非旨在与命令交互。此示例演示了在事件触发时使用行为来调用命令。抱歉,我之前不知道行为。 只需将 IsToggled 绑定到模型中的属性并在 Getter/Setter 中实现您的逻辑。【参考方案2】:如果您遵循 Prism 框架,您可以轻松地将事件连接到命令。您的 xaml 将如下例所示。
<?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:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:b="clr-namespace:Prism.Behaviors;assembly=Prism.Forms"
x:Class="TouristicWallet.Views.WalletManagementPage">
<ContentPage.Content>
<StackLayout VerticalOptions="CenterAndExpand" Padding="20">
<Switch IsToggled="Binding IsOwned" x:Name="IsOwnedSwitch">
<Switch.Behaviors>
<b:EventToCommandBehavior EventName="Toggled" Command="Binding ToggleIsOwnedCommand"/>
</Switch.Behaviors>
</Switch>
</StackLayout>
</ContentPage.Content>
</ContentPage>
【讨论】:
【参考方案3】:正如其他人所提到的,您应该将 Toggled 事件绑定到将转发命令的 eventHandler 行为。可以使用下面的代码。
<Switch IsToggled="Binding SwitchEnabled" x:Name="MySwitch">
<Switch.Behaviors>
<!-- behaviors namespace comes from "Xamarin.Forms Behaviors" nuget -->
<behaviors:EventHandlerBehavior EventName="Toggled">
<behaviors:InvokeCommandAction Command="Binding ToggleSwitchCommand" />
</behaviors:EventHandlerBehavior>
</Switch.Behaviors>
</Switch>
【讨论】:
这对你有用吗?因为我已经设法让事件命令行为适用于其他控件,但无法让它与此一起使用 是的,它对我有用。它可能是您缺少的一些小东西。如果你愿意,我可以给你另一双眼睛。我在 Xamarin 论坛上使用相同的用户名,名字和姓氏之间没有空格。给我留言,如果你愿意,我会看看。 非常感谢,明天我会回到办公室 我无法添加行为我收到此错误:错误:“行为”未声明 @lyndonhughey 谢谢我已经下载了github.com/nuitsjp/Xamarin.Forms.BehaviorsPack,它运行良好。【参考方案4】:解决方案:在做了一些研发后,我找到了这个问题的根本原因,
第一篇文章中的错误代码:
<Switch IsToggled="Binding IsOwned, Mode=TwoWay"
Toggled="Binding Toggled"
/>
只需执行两个步骤。
-
在 ContentPage 类中声明事件侦听器函数 OnToggled 并且不在您需要绑定的 ViewModel 类中
在您的 ContentPage 类中
void OnToggled(object sender, ToggledEventArgs e)
将 Toggled="Binding Toggled" == 更改为 ==> Toggled="OnToggled"
它将解决问题,不知道为什么它不适用于在 ViweModel 类中声明的事件侦听器函数。
--我希望它会起作用。
【讨论】:
【参考方案5】:我遇到了同样的问题,并以非常简单的方式解决了它。
=> 目标:在列表视图中获取带有开关控件的项目以响应命令。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TouristicWallet.Views.WalletManagementPage"
xmlns:vm="clr-namespace:TouristicWallet.ViewModels"
x:Name="pageName"
xmlns:converters="clr-namespace:TouristicWallet.Converters"
>
<ContentPage.BindingContext>
<vm:WalletManagementViewModel x:Name="ViewModel"/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<converters:CurrencyIdToCodeConverter x:Key="idToCodeConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<ListView x:Name="MyCurrencies" ItemsSource="Binding Currencies, Mode=OneWay">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="Binding Currency.Initials, Mode=OneWay" />
<Switch IsToggled="Binding Selected" HorizontalOptions="Start">
<Switch.Behaviors>
<b:EventToCommandBehavior
EventName="Toggled" Command="
Binding
Path=BindingContext.SendCommand,
Source=x:Reference
Name=pageName" />
</Switch.Behaviors>
</Switch>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
在视图模型中 定义你的命令 /ICommand
public ICommand SendCommand get; set;
SendCommand = new Command(() => //do something.....);
请特别注意粗体部分。
【讨论】:
以上是关于Xamarin Forms Switch Toggled 事件未与视图模型绑定的主要内容,如果未能解决你的问题,请参考以下文章
Xamarin.Forms:Forms.Context 已过时
Xamarin.Forms 和 Xamarin Native 有啥区别? [关闭]
如何使用 Xamarin.Forms.Maps(无 Xamarin.Forms.GoogleMaps)在地图中应用样式或更改颜色
Xamarin Forms Prism:prism ResourceDictionary 中已存在具有键“Xamarin.Forms.NavigationPage”的资源
Xamarin.Forms.Forms.Init(e) Onlaunched 中的 FileNotFoundExeception