๐Ÿ–ฅ๏ธ/Windows WPF

[WPF DevExpress] GridControl์ด ํ•˜์œ„ ๊ฐ์ฒด ์†์„ฑ ๋ณ€๊ฒฝ์ด UI์— ๋ฐ˜์˜๋˜์ง€ ์•Š์„ ๋•Œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•

HanaV 2025. 4. 12. 17:17
728x90

DevExpress์˜ GridControl๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ๋•Œ, ํ•˜์œ„ ๊ฐ์ฒด์˜ ์†์„ฑ ๋ณ€๊ฒฝ์ด UI์— ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๋ฅผ ๊ฒช๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
GridControl์—์„œ ์ค‘์ฒฉ ๊ฐ์ฒด์˜ ์†์„ฑ ๋ฐ”์ธ๋”ฉ์€ ๋งค์šฐ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.
Customer.Name, Product.Category.Name๊ณผ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๋ฐ”์ธ๋”ฉํ•  ๋•Œ,
๊ฐ’์€ ์ž˜ ํ‘œ์‹œ๋˜์ง€๋งŒ ๋ณ€๊ฒฝ์ด ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ๊ทธ ์ƒํ™ฉ์„ ์žฌํ˜„ํ•ด๋ณด๊ณ , ์ด๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ• ๋‘ ๊ฐ€์ง€์— ๋Œ€ํ•ด ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค.


์‹œ๋‚˜๋ฆฌ์˜ค

์˜ˆ๋ฅผ ๋“ค์–ด ๋‹ค์Œ๊ณผ ๊ฐ™์ด Order์™€ Customer ํด๋ž˜์Šค๋ฅผ ํฌํ•จํ•˜๋Š” ๊ตฌ์กฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ฉ๋‹ˆ๋‹ค.
UI์—์„œ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก INotifyPropertyChanged๋ฅผ ์ƒ์†๋ฐ›๋Š” BindableData๋„ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

public class BindableData : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) {
            return false;
        }

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

public class Customer : BindableData
{
    private string name;
    public string Name
    {
        get => name;
        set => SetProperty(ref name, value);
    }
}

public class Order : BindableData
{
    private int id;
    public int Id
    {
        get => id;
        set => SetProperty(ref id, value);
    }

    private Customer customer;
    public Customer Customer
    {
        get => customer;
        set => SetProperty(ref customer, value);
    }
}

๊ทธ๋ฆฌ๊ณ  ViewModel์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํ•œ ์ฃผ๋ฌธ ๋ชฉ๋ก๊ณผ Customer Name์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

public class MainViewModel
{
    public virtual ObservableCollection<Order> Orders { get; set; }

    public MainViewModel()
    {
        Orders = new ObservableCollection<Order>
        {
            new Order { Id = 1, Customer = new Customer { Name = "ํ™๊ธธ๋™" } },
            new Order { Id = 2, Customer = new Customer { Name = "๊น€์ฒ ์ˆ˜" } }
        };
    }

    public void ChangeCustomerName(string newValue)
    {
        Orders[0].Customer.Name = newValue;
    }
}

XAML ๊ตฌ์„ฑ

GridControl์„ ์‚ฌ์šฉํ•˜์—ฌ Order ๋ชฉ๋ก์„ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
Customer์˜ ์ด๋ฆ„๋„ ์ปฌ๋Ÿผ์œผ๋กœ ํ‘œ์‹œํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค:

<StackPanel>
    <dxg:GridControl MaxHeight="1000" ItemsSource="{Binding Orders}">
        <dxg:GridControl.Columns>
            <dxg:GridColumn FieldName="Id" Header="์ฃผ๋ฌธ ๋ฒˆํ˜ธ"/>
            <dxg:GridColumn FieldName="Customer.Name" Header="๊ณ ๊ฐ ์ด๋ฆ„"/>
        </dxg:GridControl.Columns>
    </dxg:GridControl>

    <Button Content="์ด๋ฆ„ ๋ณ€๊ฒฝ" Height="20" Width="100" HorizontalAlignment="Left"
            Click="Button_Click"/>
</StackPanel>

์˜ˆ์ƒํ•œ ๋™์ž‘

  • ์ด๋ฆ„ ๋ณ€๊ฒฝ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด Customer.Name์˜ ๊ฐ’์ธ 'Hanav'๊ฐ€ '๋ณ€๊ฒฝ ์™„๋ฃŒ!'๋กœ ๋ณ€๊ฒฝ๋˜์–ด GridControl์˜ ํ•ด๋‹น ์…€๋„ ํ•จ๊ป˜ ๊ฐฑ์‹ ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์‹ค์ œ ๋™์ž‘

  • Customer.Name์ด ๋ณ€๊ฒฝ๋˜์–ด๋„ GridControl์€ UI๋ฅผ ๊ฐฑ์‹ ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ช…ํžˆ ๋ณ€๊ฒฝํ–ˆ์Œ์—๋„, ์…€ ๋‚ด์šฉ์ด ๊ทธ๋Œ€๋กœ ์œ ์ง€๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• 1 โ€“ GridControl์— DetectNestedPropertyChanges ์„ค์ •

์ด ๋ฌธ์ œ๋Š” GridControl์— ๋‹ค์Œ๊ณผ ๊ฐ™์ด
DetectNestedPropertyChanges="True" ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

<dxg:GridControl DetectNestedPropertyChanges="True">
    ...
</dxg:GridControl>

์ด ์†์„ฑ์„ ์„ค์ •ํ•˜๋ฉด GridControl์ด ์ค‘์ฒฉ๋œ ๊ฐ์ฒด์˜ PropertyChanged ์ด๋ฒคํŠธ๋„ ์ž๋™์œผ๋กœ ๊ตฌ๋…ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ Customer.Name์ด ๋ณ€๊ฒฝ๋˜๋ฉด ํ•ด๋‹น ์…€์„ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.


ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• 2 - Binding={Binding Property, UpdateSourceTrigger=PropertyChanged}

GridColumn์— FieldName="Customer.Name" ๋Œ€์‹  Binding="{Binding ...}"์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด,
DevExpress๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ WPF์˜ ํ‘œ์ค€ ๋ฐ”์ธ๋”ฉ ์‹œ์Šคํ…œ์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ฅด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ฆ‰, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Converter ๋“ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ผ์š”.

<dxg:GridControl MaxHeight="1000" ItemsSource="{Binding Orders}">
    <dxg:GridControl.Columns>
        <dxg:GridColumn FieldName="Id" Header="์ฃผ๋ฌธ ๋ฒˆํ˜ธ"/>
        <dxg:GridColumn Binding="{Binding Customer.Name, UpdateSourceTrigger=PropertyChanged}" Header="๊ณ ๊ฐ ์ด๋ฆ„"/>
    </dxg:GridControl.Columns>
</dxg:GridControl>

์ด ๋ฐ”์ธ๋”ฉ์€ ์†์„ฑ์ด INotifyPropertyChanged๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด
Customer.Name์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์…€ ๋‚ด์šฉ๋„ ์ฆ‰์‹œ ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.


์ •๋ฆฌ

ํ•ญ๋ชฉ ์„ค๋ช…
๋ฌธ์ œ GridControl์ด ์ค‘์ฒฉ ์†์„ฑ(Customer.Name)์˜ ๋ณ€๊ฒฝ์„ ๊ฐ์ง€ํ•˜์ง€ ๋ชปํ•จ
์›์ธ ๋‚ด๋ถ€ ๊ฐ์ฒด์˜ ๋ณ€๊ฒฝ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž๋™ ์ถ”์ ๋˜์ง€ ์•Š์Œ
ํ•ด๊ฒฐ 1. GridControl์— DetectNestedPropertyChanges="True" ์„ค์ •
  2. Binding="{Binding ...}"์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •
728x90