0

Xamarin.Forms 2.4를 사용하여 소셜 포스트 공유 응용 프로그램을 작성 중이며 내 API와 대화합니다.Xamarin Forms보기 모델에서 목록보기 데이터 템플릿의 단추로 명령 바인딩

PostsPage에 정의 된 ListView에 ObservableCollection을로드하기 위해 PostDataViewModel을 사용하는 PostsPage가 있습니다. 리스트 뷰의 데이터 템플릿은 뷰 파일을 가리 킵니다. 그러나 포스트 뷰 템플릿에서는 내 포스트 모델의 개별 속성에 바인딩 할 수 있지만 ViewModel에있는 명령에 바인딩은 작동하지 않습니다. 나는 x : 행운과 참조를 시도했다.

내 모델 :

using System; 
using System.Collections.Generic; 

namespace SOD_APP_V2.Model 
{ 
public class PostDataModel 
{ 
    public string ID { get; set; } 
    public string Title { get; set; } 
    public string Message { get; set; } 
    public string Image { get; set; } 
    public string SocialMedia { get; set; } 
    public string AvailableTime { get; set; } 
    public string Audiences { get; set; } 
    public string Topics { get; set; } 
    public List<PostVersion> Versions { get; set; } 

    public PostDataModel PostDetails 
    { 
     get 
     { 
      return this; 
     } 
    } 
} 
public class PostVersion 
{ 
    public string SocialMediaID { get; set; } 
    public string IconPath { get; set; } 
    public int CharacterCount { get; set; } 
    public string Message { get; set; } 
} 
} 

내보기 모델 :

namespace SOD_APP_V2.ViewModel 
{ 
public class PostDataViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    //Bindable properties 
    public ObservableCollection<PostDataModel> PostDataCollection { get; set; } 
    public ICommand LoadMorePostsCommand { get; private set; } 
    public ICommand RejectPostCommand { get; private set; } 

    public static JObject SocialmediaSites { get; set; } 
    public object SelectedItem { get; set; } 

    bool isLoadMoreEnabled; 
    public bool IsLoadMoreEnabled 
    { 
     get 
     { 
      return isLoadMoreEnabled; 
     } 
     set 
     { 
      if (isLoadMoreEnabled != value) 
      { 
       isLoadMoreEnabled = value; 
       OnPropertyChanged((nameof(IsLoadMoreEnabled))); 
      } 
     } 
    } 

    string pageTitle; 
    public string PageTitle 
    { 
     get 
     { 
      return pageTitle; 
     } 
     set 
     { 
      if (pageTitle != value) 
      { 
       pageTitle = value; 
       OnPropertyChanged(nameof(PageTitle)); 
      } 
     } 
    } 

    int currentPage = 1; 
    public int CurrentPage 
    { 
     get 
     { 
      return currentPage; 
     } 
     set 
     { 
      if(currentPage != value) 
      { 
       currentPage = value; 
       OnPropertyChanged(nameof(CurrentPage)); 
      } 
     } 
    } 

    public PostDataViewModel() 
    { 
     PostDataCollection = new ObservableCollection<PostDataModel>(); 
     SocialmediaSites = default(JObject); 

     IsLoadMoreEnabled = true; 
     LoadMorePostsCommand = 
      new Command(async() => await GetPosts(),() => IsLoadMoreEnabled); 

     RejectPostCommand = new Command<PostDataModel>((post) => 
     { 
      System.Diagnostics.Debug.WriteLine("Reject command executed"); 
      System.Diagnostics.Debug.WriteLine("Post ID: " + post.ID); 
     }); 

     string deployment = ConfigController.GetDeploymentName(ApiController.DeploymentDomain); 

     MessagingCenter.Subscribe<PostsPage, JArray>(this, "translations", (sender, arg) => { 
      PageTitle = (arg[0].ToString() != "") ? arg[0].ToString() : "Posts from " + deployment; 
     }); 
     if (deployment != null) 
     { 
      //TODO: lang packs 
      PageTitle = "Posts from " + deployment; 
     } 
    } 

    public async Task<bool> GetPosts() 
    { 
     ... 
    } 

    protected virtual void OnPropertyChanged(String propertyName) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(nameof(propertyName))); 
     } 
    } 
} 

}

내 게시물 페이지 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:local="clr-namespace:SOD_APP_V2" 
xmlns:view="clr-namespace:SOD_APP_V2.View;assembly=SOD_APP_V2" 
xmlns:viewModel="clr-namespace:SOD_APP_V2.ViewModel;assembly=SOD_APP_V2" 
xmlns:controls="clr-namespace:SOD_APP_V2.Controls;assembly=SOD_APP_V2" 
x:Class="SOD_APP_V2.PostsPage" x:Name="PostsPage" 
> 
<ContentPage.BindingContext> 
    <viewModel:PostDataViewModel/> 
</ContentPage.BindingContext> 
<ContentPage.Content> 
    <StackLayout> 
     <StackLayout Orientation="Vertical" Padding="10, 5, 10, 5"> 
      <Label x:Name="titleLabel" Text="{Binding PageTitle}" 
        VerticalOptions="Start" 
        HorizontalTextAlignment="Center" 
        VerticalTextAlignment="Center" 
        BackgroundColor="Transparent" 
        HorizontalOptions="CenterAndExpand" /> 
      <controls:InfiniteListView x:Name="listView" 
         SelectedItem="{Binding SelectedItem,Mode=TwoWay}" 
         IsLoadMoreItemsPossible="{Binding IsLoadMoreEnabled}" 
         LoadMoreInfiniteScrollCommand="{Binding LoadMorePostsCommand}" 
         IsEnabled="true" 
         IsBusy="{Binding IsBusy}" 
         HasUnevenRows="true" 
         ItemsSource="{Binding PostDataCollection}" 
         SeparatorVisibility="None"> 
       <controls:InfiniteListView.ItemTemplate> 
        <DataTemplate> 
         <ViewCell> 
          <view:PostViewTemplate/> 
         </ViewCell> 
        </DataTemplate> 
       </controls:InfiniteListView.ItemTemplate> 
      </controls:InfiniteListView> 
     </StackLayout> 
     <StackLayout HorizontalOptions="FillAndExpand" 
      VerticalOptions="End"> 
      <Label x:Name="infoLabel" Text="test" 
        Opacity="0" 
        TextColor="White" 
        BackgroundColor="#337ab7" 
        HorizontalTextAlignment="Center"> 
       </Label> 
     </StackLayout> 
    </StackLayout> 
</ContentPage.Content> 

,

그리고 각 게시물을 설명 마지막으로 내 게시물보기 템플릿 :

<?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:model="clr-namespace:SOD_APP_V2.Model;assembly=SOD_APP_V2" 
xmlns:controls="clr-namespace:SOD_APP_V2.Controls;assembly=SOD_APP_V2" 
x:Class="SOD_APP_V2.View.PostViewTemplate"> 
<ContentView.Resources> 
    <ResourceDictionary> 
     <Style TargetType="controls:AwesomeButton"> 
      <Setter Property="BorderWidth" Value="1"/> 
      <Setter Property="TextColor" Value="White"/> 
      <Setter Property="BorderRadius" Value="7"/> 
      <Setter Property="FontFamily" Value="FontAwesome"/> 
     </Style> 
    </ResourceDictionary> 
</ContentView.Resources> 
<ContentView.Content> 
    <Frame HasShadow="false" CornerRadius="5" IsClippedToBounds="true" OutlineColor="#09478e" Padding="0" Margin="10"> 
    <Grid 
     Padding="0"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="1" /> 
      <ColumnDefinition Width="1" /> 
      <ColumnDefinition Width="*" /> 
      <ColumnDefinition Width="*" /> 
      <ColumnDefinition Width="1" /> 
      <ColumnDefinition Width="1" /> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="50"></RowDefinition> 
      <RowDefinition Height="50"></RowDefinition> 
      <RowDefinition Height="1"></RowDefinition> 
      <RowDefinition Height="100"></RowDefinition> 
      <RowDefinition Height="1"></RowDefinition> 
      <RowDefinition Height="40"></RowDefinition> 
      <RowDefinition Height="40"></RowDefinition> 
      <RowDefinition Height="1"></RowDefinition> 
     </Grid.RowDefinitions> 
     <StackLayout Orientation="Horizontal" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="6" BackgroundColor="#B0C4DB" Padding="5"> 
      <Label x:Name="postTitle" Text="{Binding Title}" TextColor="#09478e" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/> 
      <StackLayout Orientation="Horizontal" VerticalOptions="CenterAndExpand" HorizontalOptions="End"> 
      <controls:AwesomeButton Clicked="OnAvailableTimePopupClicked" CommandParameter="{Binding AvailableTime}" Text="&#xf017;" TextColor="#09478e" BorderWidth="0" Margin="-5" BackgroundColor="Transparent" WidthRequest="36" FontSize="24"></controls:AwesomeButton> 
      <controls:AwesomeButton Clicked="OnAudiencesPopupClicked" CommandParameter="{Binding Audiences}" Text="&#xf0c0;" TextColor="#09478e" BorderWidth="0" Margin="-5" BackgroundColor="Transparent" WidthRequest="36" FontSize="24"></controls:AwesomeButton> 
      <controls:AwesomeButton Clicked="OnTopicsPopupClicked" CommandParameter="{Binding Topics}" Text="&#xf02c;" TextColor="#09478e" BorderWidth="0" Margin="-5" BackgroundColor="Transparent" WidthRequest="36" FontSize="24"></controls:AwesomeButton> 
      </StackLayout> 
     </StackLayout> 
     <controls:RepeaterView Grid.Row="1" Grid.Column="2" 
           ItemsSource="{Binding Versions}" 
           NoOfColumns="3" 
           > 
      <controls:RepeaterView.ItemTemplate> 
       <DataTemplate> 
        <StackLayout Spacing="0" > 
         <Label Text="{Binding Message}" IsVisible="false"/> 
         <Image Source="{Binding IconPath}"> 
          <Image.GestureRecognizers> 
           <TapGestureRecognizer 
             Tapped="OnMessageVersionClicked" 
             NumberOfTapsRequired="1" /> 
          </Image.GestureRecognizers> 
         </Image> 
        </StackLayout> 
       </DataTemplate> 
      </controls:RepeaterView.ItemTemplate> 
     </controls:RepeaterView> 

     <Image BackgroundColor="White" Grid.Row="3" Grid.Column="2" Source="{Binding Image}" VerticalOptions="FillAndExpand"/> 
     <Label x:Name="postMessage" BackgroundColor="White" Grid.Row="3" Grid.Column="3" Text="{Binding Message}" TextColor="#09478e" VerticalOptions="FillAndExpand" /> 

     <controls:AwesomeButton Clicked="OnSharePostClicked" CommandParameter="{Binding ID}" BackgroundColor="#5cb85c" Grid.Row="5" Grid.Column="2" Text="&#xf1e0; Share" BorderColor="#5cb85c"></controls:AwesomeButton> 
     <controls:AwesomeButton Clicked="OnSchedulePostClicked" CommandParameter="{Binding ID}" BackgroundColor="#5bc0de" Grid.Row="5" Grid.Column="3" Text="&#xf073; Schedule" BorderColor="#5bc0de"></controls:AwesomeButton> 

     <controls:AwesomeButton Clicked="OnEditPostClicked" CommandParameter="{Binding PostDetails}" TextColor="#09478e" BackgroundColor="White" Grid.Row="6" Grid.Column="2" Text="&#xf040; Edit" BorderColor="#09478e"></controls:AwesomeButton> 
     <controls:AwesomeButton Command="{Binding Path=DataContext.RejectPostCommand}" CommandParameter="{Binding}" BackgroundColor="#d9534f" Grid.Row="6" Grid.Column="3" Text="&#xf00d; Reject" BorderColor="#d9534f"></controls:AwesomeButton> 
     <!-- Inner Border --> 
     <BoxView Grid.Row="2" Grid.RowSpan="3" Grid.Column="1" BackgroundColor="#09478e"></BoxView> 
     <BoxView Grid.Row="2" Grid.RowSpan="3" Grid.Column="4" BackgroundColor="#09478e"></BoxView> 
     <BoxView Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="2" BackgroundColor="#09478e"></BoxView> 
     <BoxView Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="4" BackgroundColor="#09478e"></BoxView> 
    </Grid> 
    </Frame> 
</ContentView.Content> 

당신이 포스트보기 템플릿에서 보는 바와 같이

, 나는 뷰 모델에 RejectPostCommand을 결합하려고하지만, 결합하지 않습니다. x : PostsPage에 대한 참조를 시도했지만 예외가 발생했습니다. 내 View Template에서 해당 페이지를 찾을 수 없습니다. 어떻게 든 명령에 액세스 할 수 있어야합니다. 아무도 아이디어가 있니?

+0

나는 https://techsolutions2017.blogspot.it/2017/01/listview-in-xamarin-forms-in-mvvm.html#comment-form을이 문서가 매우 도움이 내가 찾은 –

+0

유일한 작업 솔루션을 발견했다 x : reference가 작동하고 명령이 실행 중일 때 PostsPage와 동일한 XAML 파일에 뷰 템플릿을 포함시키는 것입니다. 하지만보기를 분리하여 유지할 수있는 방법이 있습니까? – kaktusas2598

+0

시도하십시오이 명령 = "{바인딩 원본 = {x : 참조 listView}, 경로 = BindingContext.RejectPostCommand}" –

답변

1

한 가지 해결책은 모델에 ICommand 속성을 추가 한 다음 viewModel에 PostDataCollection에 게시물을 추가하기 전에 새 ICommand 속성 값을 viewmodel의 desire 명령으로 설정하는 것입니다. 다음과 같이하십시오 :

public async Task<bool> GetPosts() 
{ 
    var response = await FetchPostsFromApi(); 
    foreach(var post in response.posts) 
    { 
     post.NewCommand = RejectPostCommand; 
     PostDataCollection.Add(post) 
    } 
    return response.HasMoreItems; 
} 

이제 Post View Template에서 모델의 새 ICommand 속성을 바인딩하십시오.

+0

해줘서 고마워요! 게시물 페이지 내에서 PostViewTemplate 코드를 움직이는 내 문제를 해결하고 게시물 처리자에게도 문제를 해결했습니다. 이제 모델을보기위한 내 명령이 실제로 작동하고 파일을 적게 사용합니다! – kaktusas2598

0

그래서이 문제는 ViewModel의 PostViewTemplate에서 바인딩을 설정하는 것과 관련이 있습니다. 다른 파일에 있었기 때문에 listView 나 PostsPage를 바인딩 소스로 참조 할 수 없었습니다. PostViewTemplate XAML을 PostsPage로 이동하여이 문제를 해결했습니다. 이제 사용할 수 있습니다

{Binding Path=BindingContext.RejectPostCommand, Source={x:Reference listView}} 

그리고 작동합니다!

0

PostViewTemplate에서 명령을 만든 다음 ListView에 바인딩 할 수 있습니다.

PostViewTemplate.xaml.cs : 다음은 예입니다

public partial class PostViewTemplate : ContentView 
{ 
    public static BindableProperty RejectPostCommandProperty = BindableProperty.Create(
     nameof(RejectPostCommand), 
     typeof(ICommand), 
     typeof(PostViewTemplate), 
     default(ICommand), 
     defaultBindingMode: BindingMode.OneWay); 

    public ICommand RejectPostCommand 
    { 
     get { return (ICommand)GetValue(RejectPostCommandProperty); } 
     set { SetValue(RejectPostCommandProperty, value); } 
    } 
} 

및 PostViewTemplate.xaml에서

<?xml version="1.0" encoding="UTF-8"?> 
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    x:Name="PostViewTemplate" 
    xmlns:model="clr-namespace:SOD_APP_V2.Model;assembly=SOD_APP_V2" 
    xmlns:controls="clr-namespace:SOD_APP_V2.Controls;assembly=SOD_APP_V2" 
    x:Class="SOD_APP_V2.View.PostViewTemplate"> 
<ContentView.Content> 
    .... 
    <controls:AwesomeButton Command="{Binding RejectPostCommand, Source={x:Reference PostViewTemplate}}" CommandParameter="{Binding}" BackgroundColor="#d9534f" Grid.Row="6" Grid.Column="3" Text="&#xf00d; Reject" BorderColor="#d9534f"></controls:AwesomeButton> 
    .... 
</ContentView.Content> 
</ContentView> 

공지 사항 내가 지금

PostViewTemplate.xaml

에 내용 없음의 이름을 설정하면 이 새로운 Command를 ContentPage에 바인드하려면 다음과 같이하십시오.

<?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:local="clr-namespace:SOD_APP_V2" 
    xmlns:view="clr-namespace:SOD_APP_V2.View;assembly=SOD_APP_V2" 
    xmlns:viewModel="clr-namespace:SOD_APP_V2.ViewModel;assembly=SOD_APP_V2" 
    xmlns:controls="clr-namespace:SOD_APP_V2.Controls;assembly=SOD_APP_V2" 
    x:Class="SOD_APP_V2.PostsPage" x:Name="PostsPage"> 
    <ContentPage.BindingContext> 
     <viewModel:PostDataViewModel/> 
    </ContentPage.BindingContext> 
    <ContentPage.Content> 
     .... 
     <controls:InfiniteListView x:Name="listView" 
       SelectedItem="{Binding SelectedItem,Mode=TwoWay}" 
       IsLoadMoreItemsPossible="{Binding IsLoadMoreEnabled}" 
       LoadMoreInfiniteScrollCommand="{Binding LoadMorePostsCommand}" 
       IsEnabled="true" 
       IsBusy="{Binding IsBusy}" 
       HasUnevenRows="true" 
       ItemsSource="{Binding PostDataCollection}" 
       SeparatorVisibility="None"> 
      <controls:InfiniteListView.ItemTemplate> 
       <DataTemplate> 
        <ViewCell> 
         <view:PostViewTemplate RejectPostCommand="{Binding BindingContext.RejectPostCommand, Source={x:Reference listView}}"/> 
        </ViewCell> 
       </DataTemplate> 
      </controls:InfiniteListView.ItemTemplate> 
     </controls:InfiniteListView> 
     .... 
    </ContentPage.Content> 
</ContentPage> 
2

PostViewTemplate XAML을 PostsPage로 이동해도 작동하지만 이제 재사용 가능한 템플릿이 없습니다.

원래 코드의 다음 3 가지 사소한 변경 사항으로 재사용 가능한 솔루션을 만들 수 있습니다.

과 같이 코드 뒤에 PostViewTemplate에 바인딩 속성을 추가

<view:PostViewTemplate ParentBindingContext="{Binding Source={x:Reference Home}, Path=BindingContext}"/> 

지금 당신은 "당신에 액세스 할 수 있습니다 : 당신의 PostsPage XAML에서 뷰 모델에 대한 특성과 같이하는 것을

public static BindableProperty ParentBindingContextProperty = 
     BindableProperty.Create(nameof(ParentBindingContext), typeof(object), 
     typeof(PostViewTemplate), null); 

    public object ParentBindingContext 
    { 
     get { return GetValue(ParentBindingContextProperty); } 
     set { SetValue(ParentBindingContextProperty, value); } 
    } 

바인딩 parent "viewmodel을 PostViewTemplate의 바인딩에서 직접 가져옵니다 (참고). 바인딩 소스로 사용할 ContentView에 x : Name을 추가해야합니다.

<ContentView ... x:Name="PostView" ...> 

<controls:AwesomeButton BindingContext="{Binding Source={x:Reference PostView}, Path=ParentBindingContext}" Command="{Binding OnTopicsPopupClicked}" CommandParameter="{Binding Topics}" Text="&#xf02c;" TextColor="#09478e" BorderWidth="0" Margin="-5" BackgroundColor="Transparent" WidthRequest="36" FontSize="24"></controls:AwesomeButton> 
+0

감사! 이것은 받아 들여진 대답이어야합니다. –

관련 문제