본문 바로가기
Framework/MAUI

[MAUI] 상대 바인딩 - 상위 항목에 바인딩

by Kor-IT 2022. 10. 11.
반응형

상위 항목에 바인딩

 

상대 바인딩 - 상위 항목에 바인딩 모드는 시작 전 트리에서 특정 유형의 부모 요소에 바인딩하는 데 사용된다. FindAncestor 모드는 Element 형식에서 파생되는 부모 요소에 바인딩하는 데 사용된다. FindAncestorBidningContext 모드는 부모 요소의 BindingContext에 바인딩하는 데 사용된다.

FindAncestor 및 FindAncestorBindingContext 상대 바인딩 모드(상위 항목에 바인딩)를 사용할 때는 AncestorType 속성을 Type으로 설정해야 한다. 그러지 않으면 XamlParseException 이 throw 된다.

 

Mode 속성이 설정되지 않은경우, AncestorType 속성을 Element에서 파생된 형식으로 설정하면 Mode 속성이 암시적으로 FindAncestor로 설정된다.

 

 

예제)

 

PersonViewModel.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace MauiApp1.ViewModel
{
    public class PersonViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;
        private int age;

        public string Name
        {
            get => this.name;
            set
            {
                SetProperty(ref this.name, value);
            }
        }

        public int Age
        {
            get => this.age;
            set
            {
                SetProperty(ref this.age, value);
            }
        }

        public static ICollection<PersonViewModel> All { get; private set; }

        static PersonViewModel()
        {
            List<PersonViewModel> list = new List<PersonViewModel>();

            for (int i = 0; i < 10; i++)
            {
                list.Add(new PersonViewModel
                {
                    Name = $"name{i}",
                    Age = i
                });
            }

            All = list;
        }

        private bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;

            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

 

 

EmployeeViewModel.cs

using System.Collections.ObjectModel;
using System.Windows.Input;

namespace MauiApp1.ViewModel
{
    public class EmployeeViewModel
    {
        public ObservableCollection<PersonViewModel> Employees { get; set; }

        public ICommand DeleteEmployeeCommand { get; private set; }

        public EmployeeViewModel()
        {
            DeleteEmployeeCommand = new Command((employee) =>
            {
                Employees.Remove(employee as PersonViewModel);
            });
        }
    }
}

 

반응형

 

TestPage.xaml.cs

using MauiApp1.ViewModel;
using System.Collections.ObjectModel;

namespace MauiApp1;

public partial class TestPage : ContentPage
{
    public EmployeeViewModel DefaultViewModel { get; } = new EmployeeViewModel
    {
        Employees = new ObservableCollection<PersonViewModel>
        {
            new PersonViewModel
            {
                Name = "Lee",
                Age = 10
            },
            new PersonViewModel
            {
                Name = "Kim",
                Age = 18
            },
            new PersonViewModel
            {
                Name = "Park",
                Age = 29
            }
        }
    };

    public TestPage()
    {
        InitializeComponent();
    }
}

 

 

TestPage.xmal

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
    x:Class="MauiApp1.TestPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MauiApp1"
    xmlns:vm="clr-namespace:MauiApp1.ViewModel"
    Title="TestPage"
    Padding="20"
    BindingContext="{Binding Source={RelativeSource Mode=Self}, Path=DefaultViewModel}">

    <StackLayout Margin="10,0">

        <ListView ItemsSource="{Binding Employees}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <Label Text="{Binding Name}" />
                            <Button
                                Command="{Binding Source={RelativeSource AncestorType={x:Type vm:EmployeeViewModel}}, Path=DeleteEmployeeCommand}"
                                CommandParameter="{Binding}"
                                HorizontalOptions="End"
                                Text="삭제" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </StackLayout>
</ContentPage>

 

실행 결과

 

해당 예제에서 페이지의 BindContext 가 자기 자신(Self)의 DefaultViewModel 속성으로 설정되어있다. 해당 속성은 페이지 코드 숨김 파일에 정의되어있다. ListView는 ViewModel의 Employees 속성에 바인딩된다. Button의 Command 속성은 EmployeeViewModel의 DeleteEmployeeCommand에 바인딩된다. Button 클릭 시 탭한 직원이 삭제된다.

반응형

댓글