简体   繁体   English

将值UserControl传递给视图页面的ViewModel

[英]Pass value UserControl to ViewModel of View Page

Here is the complete Sample code 这是完整的示例代码
Using MVVM pattern My requirement is to have a ListView where 使用MVVM模式我的要求是要有一个ListView

  1. If user Taps inside ListView on checkBox Storyboard Animation should play for True False and the ListView binded value should be updated in database. 如果用户在复选框“ 故事板”上的ListView内部点击,则True False播放,并且ListView绑定值应在数据库中更新。 For true the tick should pop up with animation for false the tick should become invisible with animation. 如果为true,则应使用动画弹出刻度线;如果为false,则应使用动画隐藏刻度线。
    Solved as per @Elvis Xia answer 解决按@Elvis夏答案
  2. If user taps on ListviewItem Navigate to new page with value 如果用户点击ListviewItem导航到具有值的新页面
  3. Blueprint 蓝图

Now I went with Usercontrol creation for the datatemplate. 现在,我为数据模板创建了用户控件。 Here I want to identify both events separately user clicking on checkbox or clicking on Item separately. 在这里,我想分别单击checkbox或单击Item来标识两个事件。
Using ICommand I am creating two Delegates that gets binded to two transparent button which relays tapped event. 使用ICommand我正在创建两个委托,它们被绑定到两个透明按钮上,以中继轻击事件。
Dependency of creating transparent buttons and creating delgates while binding them made me think surely there must a better way in which I can utilize MVVM for these events without any code behind . 创建透明按钮和绑定绑定时创建代理的依赖性使我确信,肯定有一种更好的方式可以将MVVM用于这些事件,而无需任何代码

UserControl XAML UserControl XAML

<Button Background="LightBlue" BorderBrush="White" BorderThickness="4" Command="{x:Bind sampleItem.itemTapped}" CommandParameter="{Binding}" HorizontalContentAlignment="Stretch">

    <Grid Margin="20">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <TextBlock Margin="20" HorizontalAlignment="Center" Text="{x:Bind sampleItem.sampleText}" FontSize="30"/>
        <Image Grid.Column="1" Height="60" Width="60" Source="ms-appx:///Assets/check_off.png" HorizontalAlignment="Right"/>
        <Image x:Name="image" Grid.Column="1" Height="60" Width="60" Source="ms-appx:///Assets/check_on.png" HorizontalAlignment="Right"  Visibility="Collapsed" RenderTransformOrigin="0.5,0.5">
            <Image.RenderTransform>
                <CompositeTransform/>
            </Image.RenderTransform>
        </Image>
        <Button x:Name="btnFav" Grid.Column="1"  Height="60" Width="60" HorizontalAlignment="Right" Background="Transparent" Command="{x:Bind sampleItem.favTapped}" CommandParameter="{Binding}">
            <Interactivity:Interaction.Behaviors>
                <!--<Core:EventTriggerBehavior EventName="Tapped">
                <Core:InvokeCommandAction Command="{Binding favTapped}" />
            </Core:EventTriggerBehavior>-->
                <Core:DataTriggerBehavior Binding="{Binding isFav}" Value="true">
                    <Media:ControlStoryboardAction Storyboard="{StaticResource StoryboardCheckOn}"/>
                </Core:DataTriggerBehavior>
                <Core:DataTriggerBehavior Binding="{Binding isFav}" Value="false">
                    <Media:ControlStoryboardAction Storyboard="{StaticResource StoryboardCheckOff}"/>
                </Core:DataTriggerBehavior>
            </Interactivity:Interaction.Behaviors>
        </Button>
    </Grid>
</Button>

UserControl XAML codeBehind UserControl XAML代码背后

MainPageModel sampleItem { get { return this.DataContext as MainPageModel; } }
        public MainPageUserControl()
        {
            this.InitializeComponent();
            this.DataContextChanged += (s, e) => this.Bindings.Update();
        }

Viewmodel Code 视图模型代码

public async Task GetData()
{
    for (int i = 0; i < 10; i++)
    {
        if (i == 3)
            sampleList.Add(new MainPageModel { sampleText = "Selected", isFav = true, favTapped= new DelegateCommand<MainPageModel>(this.OnFavTapped), itemTapped= new DelegateCommand<MainPageModel>(this.OnItemTapped)});
        else
            sampleList.Add(new MainPageModel { sampleText = "UnSelected"+i.ToString(), isFav = null, favTapped = new DelegateCommand<MainPageModel>(this.OnFavTapped), itemTapped = new DelegateCommand<MainPageModel>(this.OnItemTapped) });
}
}
private void OnFavTapped(MainPageModel arg)
{
    if (arg.isFav == null) arg.isFav = true;
    else
        arg.isFav = !arg.isFav;
}
private void OnItemTapped(MainPageModel arg)
{
    System.Diagnostics.Debug.WriteLine("Button Value: "+arg.sampleText);
    System.Diagnostics.Debug.WriteLine("Selected Item Value: "+selectedItem.sampleText);
}

MainPage Xaml 主页Xaml

 <Grid Grid.Row="1">
            <ListView  ItemsSource="{x:Bind ViewModel.sampleList}" IsItemClickEnabled="True" SelectedItem="{Binding ViewModel.selectedItem,Mode=TwoWay}">
                <ListView.ItemTemplate>
                    <DataTemplate>                       
                            <userControls:MainPageUserControl/>                       
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>

There must be a better way to achieve the desired result using code behind. 必须有一种更好的方法来使用后面的代码来获得所需的结果。

The DataContext of every item in your project is an instance of MainPageModel class. 项目中每个项目的DataContext是MainPageModel类的实例。 So the favTapped command should be added to MainPageModel class. 因此,应该将favTapped命令添加到MainPageModel类。 And it is a command, so favTapped should be an instance of a new class,which implements ICommand interface. 它是一条命令,因此favTapped应该是实现ICommand接口的新类的实例。

And if you don't want the animation to show at the page's first load, you can set isFav to bool? 而且,如果您不希望动画在页面首次加载时显示,则可以将isFav设置为bool? . And when the page first loads, set the value of isFav to null, thus it won't trigger the animation action. 并且,当页面首次加载时,请将isFav的值设置为null,这样就不会触发动画操作。

Below are the Codes snippets and Demo Link: 以下是代码段和演示链接:

ViewModelCommands.cs: ViewModelCommands.cs:

public class ViewModelCommands : ICommand
{
    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public void Execute(object parameter)
    {
        //if it's a tapped event
        if (parameter is TappedRoutedEventArgs)
        {
            var tappedEvent = (TappedRoutedEventArgs)parameter;
            var gridSource = (Grid)tappedEvent.OriginalSource;
            var dataContext = (MainPageModel)gridSource.DataContext;
            //if tick is true then set to false, or the opposite.
            if (dataContext.isFav == null)
            {
                dataContext.isFav = true;
            } else
            {
                dataContext.isFav = !dataContext.isFav;
            }
        }
    }
}

MainPageModel.cs: MainPageModel.cs:

 public class MainPageModel:BindableBase
{

    public MainPageModel() {
        favTapped = new ViewModelCommands();
    }
    public ViewModelCommands favTapped { get; set; }
    private string _sampleText;
    public string sampleText
    {
        get
        {
            return this._sampleText;
        }
        set
        {
            Set(ref _sampleText, value);
        }
    }
    private bool? _isFav;
    public bool? isFav
    {
        get
        {
            return this._isFav;
        }
        set
        {
            Set(ref _isFav, value);
        }
    }
}

Here is the complete Demo: Demo Project 这是完整的演示: 演示项目

Update: 更新:

When using DelegateCommand , you can add the command Property to MainPageModel.cs and since the DataContext of the items are MainPageModel instances. 使用DelegateCommand ,可以将命令属性添加到MainPageModel.cs,并且由于项目的DataContext是MainPageModel实例。 You can use this.isFav to change the clicked item's value of isFav . 您可以使用this.isFav更改单击项的isFav值。

Here are the codes of MainPageModel.cs: 以下是MainPageModel.cs的代码:

public class MainPageModel : BindableBase
{
    private DelegateCommand _favTapped;

    public DelegateCommand favTapped
    {
        get
        {
            if (_favTapped == null)
            {
                _favTapped = new DelegateCommand(() =>
                {
                    //Here implements the check on or off logic
                    this.CheckOnOff();
                }, () => true);
            }
            return _favTapped;
        }
        set { _favTapped = value; }
    }

    private void CheckOnOff()
    {
        if (this.isFav == null)
        {
            this.isFav = true;
        }
        else
        {
            this.isFav = !this.isFav;
        }
    }
    private string _sampleText;
    public string sampleText
    {
        get
        {
            return this._sampleText;
        }
        set
        {
            Set(ref _sampleText, value);
        }
    }
    private bool? _isFav;
    public bool? isFav
    {
        get
        {
            return this._isFav;
        }
        set
        {
            Set(ref _isFav, value);
        }
    }
}

For Listview item selected 对于选择的Listview项目

You can use ListView.ItemClick Event. 您可以使用ListView.ItemClick事件。 But you should also set IsItemClickEnabled="True",otherwise the event handler won't be fired. 但您还应该设置IsItemClickEnabled =“ True”,否则将不会触发事件处理程序。

For The subitem of Listview tapped 对于利用Listview的子项

You can use Tapped Event of userControl. 您可以使用userControl的Tapped Event。

Here are the Xaml codes, that shows how to register the above two events: 这是Xaml代码,显示了如何注册上述两个事件:

<Grid Grid.Row="1">
    <ListView IsItemClickEnabled="True" ItemClick="ListView_ItemClick_1" ItemsSource="{x:Bind ViewModel.sampleList}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <userControls:MainPageUserControl  Tapped="MainPageUserControl_Tapped"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>
public class ViewMOdel()
{ 
       public ViewModel()
    {
favTapped= new DelegateCommand<MainPageModel>(this.OnFavTapped)
 itemTapped= new DelegateCommand<MainPageModel>(this.OnItemTapped)
    }

public async Task GetData()
    {
        for (int i = 0; i < 10; i++)
        {
            if (i == 3)
                sampleList.Add(new MainPageModel { sampleText = "Selected", isFav = true});
            else
                sampleList.Add(new MainPageModel { sampleText = "UnSelected"+i.ToString(), isFav = null});
    }
    }
    private void OnFavTapped(MainPageModel arg)
    {
        if (arg.isFav == null) arg.isFav = true;
        else
            arg.isFav = !arg.isFav;
    }
    private void OnItemTapped(MainPageModel arg)
    {
        System.Diagnostics.Debug.WriteLine("Button Value: "+arg.sampleText);
        System.Diagnostics.Debug.WriteLine("Selected Item Value: "+selectedItem.sampleText);
    }
    }

Binding should be like this 绑定应该是这样的

<Button x:Name="btnFav" Grid.Column="1"  Height="60" Width="60" HorizontalAlignment="Right" Background="Transparent" Command="{Binding ElementName=UserControl, Path=Tag.favTapped}" CommandParameter="{Binding}"/>

Update 更新

<ListView  ItemsSource="{x:Bind ViewModel.sampleList}"  x:Name="Listview"IsItemClickEnabled="True" SelectedItem="{Binding ViewModel.selectedItem,Mode=TwoWay}">
                    <ListView.ItemTemplate>
                        <DataTemplate>                       
                                <userControls:MainPageUserControl Tag="{Binding DataContext,ElementName=Listview}"/>                       
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
 <Button x:Name="btnFav" Grid.Column="1"  Height="60" Width="60" HorizontalAlignment="Right" Background="Transparent" Command="{Binding ElementName=UserControl, Path=Tag.favTapped}" CommandParameter="{Binding}"/>

Update2 using EventTriggerBehavior 使用EventTriggerBehavior的Update2

 favTapped = new DelegateCommand<RoutedEventArgs>(this.OnFavTapped);

private void OnFavTapped(RoutedEventArgs arg)
        {
         var item =  (( arg.OriginalSource )as Button).DataContext as MainPageModel
        }

<Button n x:Name="btnFav" Grid.Column="1"  Height="60" Width="60" HorizontalAlignment="Right" Background="Transparent"   >
            <interact:Interaction.Behaviors>

                <interactcore:EventTriggerBehavior EventName="Click" >
                    <interactcore:InvokeCommandAction Command="{Binding ElementName=usercontrol, Path=Tag.favTapped}" />
                </interactcore:EventTriggerBehavior>
            </interact:Interaction.Behaviors>
        </Button>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM