Xamarin Forms Switch Toggled事件不与viewmodel绑定

时间:2016-12-09 23:52:13

标签: xamarin mvvm xamarin.forms

我有一个Forms XAML页面,在那里我有一个listview,每个元素都有一个Switch(默认为xamarin)。我可以将项目中的数据绑定到listview,但我无法订阅Switch事件“Toggled”,因为它会导致项目不显示。我也尝试使用ICommand和Command,因为它被指示用于按钮,但结果是相同的,没有显示。如何处理来自我的viewmodel的切换切换?

视图

    <?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框架

5 个答案:

答案 0 :(得分:12)

首先关闭Switch无法绑定到Command。看到: https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_bindings_to_mvvm/#Commanding_with_ViewModels

从上面可以看出,可绑定到ICommand的Forms控件是:

  • 按钮
  • MenuItem
  • ToolbarItem
  • SearchBar
  • TextCell(因此也是 ImageCell)
  • ListView
  • TapGestureRecognizer

您只需执行以下操作即可在View后面的代码中运行代码,在XAML中执行此操作:

<Switch IsToggled="{Binding IsOwned, Mode=TwoWay}"
        Toggled="Handle_Toggled" />

然后在Code后面的文件中:

void Handle_Toggled(object sender, Xamarin.Forms.ToggledEventArgs e)
{
    // Do stuff
}

或者,由于您是绑定的,只需在OwnedCurrencyWrapper的setter中添加代码,就可以在实际的IsOwned类中运行代码(这就是您想要的)。在这种情况下,不要为switch ::

的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事件绑定到Command。

答案 1 :(得分:5)

正如其他人所提到的,您应该将Toggled事件绑定到将转发命令的eventHandler行为。可以使用以下代码。

filename = open("output3.txt")
f = open("countoutput.txt", "w")
import collections
for line in filename: 
    for number in line.split(): 
        print(collections.Counter("f"))
        break

答案 2 :(得分:3)

如果您遵循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 :(得分:0)

解决方案:经过一些研发,我发现了此问题的根本原因,

第一篇文章中的错误代码:

<Switch IsToggled="{Binding IsOwned, Mode=TwoWay}"
                      Toggled="{Binding Toggled}"
                      />

只需执行两个步骤。

  1. ContentPage 类中声明事件监听器函数 OnToggled ,并且不进入需要绑定的ViewModel类

在您的 ContentPage 类中

void OnToggled(object sender, ToggledEventArgs e){

}
  1. Toggled =“ {Binding Toggled}” ==更改为==> Toggled =“ OnToggled”

它将解决此问题,不知道为什么它不适用于ViweModel类中声明的事件侦听器功能

-我希望它能起作用。

答案 4 :(得分:0)

我遇到了同样的问题,并以非常简单的方式解决了它。

=> 目标:在列表视图中使用开关控件获取项目以响应命令。

<?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.....);

请特别注意粗体部分。