در این مقاله مفاهیم مختلفی را در ارتباط با DataBinding بررسی خواهیم کرد:
• One Way Binding بخش اول
• INPC بخش اول
• Tow Way Binding بخش اول
• List Binding بخش دوم
• Element Binding بخش دوم
• Data Conversion بخش دوم
در ابتدا مفهوم انقیاد دادهها یا همان DataBinding را مرور میکنیم. به فرآیند مرتبط سازی منابع اطلاعاتی به کنترلها در برنامهها یا به بیان امروزیتر، به Viewها و نمایش اطلاعات در آنها، انقیاد (Databinding) گویند.
One Way Data Binding (انقیاد یک طرفه)
در این حالت اطلاعات را صرفا در یک View و یا یک کنترل نمایش میدهیم و تغییر اطلاعات در View، تاثیری بر روی منبع اطلاعاتی نخواهد داشت.
مثال: یک پروژهی WPF ساده را ایجاد و سپس کلاس Employee را با خصوصیات زیر، تعریف میکنیم:
public class Employee
{
public string Name { get; set; }
public string Title { get; set; }
public static Employee GetEmployee()
{
var emp = new Employee
{
Name = "Mani",
Title = "CEO"
};
return emp;
}
}
در بخش markup فایل MainWindow.xaml کدهای زیر را ایجاد میکنیم:
<Grid>
<StackPanel Name="Display">
<StackPanel Orientation="Horizontal">
<TextBlock>First Name :</TextBlock>
<TextBlock Margin="5,0,0,0" Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock>Title :</TextBlock>
<TextBlock Margin="5,0,0,0" Text="{Binding Title}"></TextBlock>
</StackPanel>
</StackPanel>
</Grid>
در markup فوق برای بایند کردن اطلاعات شیء Employee به خصوصیت Text در Textblock، از روش خاصی استفاده میکنیم. ابتدا یک {} ایجاد میکنیم و درون آن عبارت Binding و خصوصیت مورد نظر جهت عملیات انقیاد دادهها را مینویسیم. برای تکمیل و انجام عملیات Binding کافی است خصوصیت DataContext را با استفاده از متد استاتیک تعریف شدهی در کلاس Employee پر کنیم.
public MainWindow()
{
InitializeComponent();
DataContext = Employee.GetEmployee();
}
در ادامهی بحث لازم است کمی مفهوم DataContext را بررسی کنیم. منبع داده پیش فرض در WPF شیء DataContext است؛ مگر اینکه منبع داده را خودمان تغییر دهیم. DataContext یک خصوصیت از کلاس FrameworkElement است که بیشتر کنترلهای بخش UI در WPF از این کلاس مشتق میشوند.
INPC یا INotifyPropertyChanged Interface
پس از بایند کردن اطلاعات به View مورد نظر، ممکن است منبع داده در طول زمان استفاده تغییر کند. از این رو لازم است که این تغییرات، به View اعمال شوند. بدین منظور میبایست ابتدا Interface ، INotifyPropertyChanged را برای کلاس Employee پیاده سازی کنیم:
public class Employee :INotifyPropertyChanged
{
public string Name { get; set; }
public string Title { get; set; }
public static Employee GetEmployee()
{
var emp = new Employee
{
Name = "Mani",
Title = "CEO"
};
return emp;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged
([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
پس از پیاده سازی Interface، خصوصیات کلاس Employee نبایستی بصورت AutoProperty باشند. پس پیاده سازی خصوصیات را با تعریف فیلدهای مورد نیاز تغییر میدهیم.
علت تغییر پیاده سازی، لزوم فراخوانی رویداد dOnPropertyChange در بلاک Set خصوصیات کلاس Employee میباشد:
private string _name;
private string _title;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public string Title
{
get { return _title; }
set
{
_title = value;
OnPropertyChanged();
}
}
در ادامه ، در بخش CodeBehind در سازنده کلاس کدهای زیر را جایگزین کدهای قبلی می کنیم :
private Employee emp;
public MainWindow()
{
InitializeComponent();
emp = new Employee()
{
Name = "Mani",
Title = "CEO"
};
DataContext = emp;
}
سپس در بخش Markup، یک یک دکمه را ایجاد و رویداد کلیک آن را تعیین میکنیم:
<StackPanel Orientation="Horizontal">
<Button Click="btnClick" Width="70" Height="30" Content="Change"/>
</StackPanel>
در بخش CodeBehind، رویداد Click را به شکل زیر پیاده سازی میکنیم:
private void btnClick(object sender, RoutedEventArgs e)
{
emp.Name = "Amir";
emp.Title = "Manager";
}
در برنامهی فوق، در ابتدا View با اطلاعات ارسالی در بخش سازنده، پر میشود و با کلیک بر روی دکمه، منبع داده بهروز شده (در اینجا شیء emp) و بهصورت اتوماتیک View ما بهروز خواهد شد.
Tow Way Data binding (انقیاد دو طرفه)
در این حالت از Data binding، با تغییر View، تغییرات بر روی منبع داده نیز اعمال میشوند.
ابتدا بخش markup مثال فوق را با اضافه کردن ویژگی Mode در کنار ویژگی Binding به شکل زیر تغییر میدهیم:
<Grid>
<StackPanel Name="Display" >
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0">Name :</TextBlock>
<TextBox Margin="5,0,0,0" Text="{Binding Name, Mode=TwoWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0">Title :</TextBlock>
<TextBox Margin="5,0,0,0" Text="{Binding Title,Mode=TwoWay}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0">Name :</TextBlock>
<TextBlock Margin="5,0,0,0" Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0">Title :</TextBlock>
<TextBlock Margin="5,0,0,0" Text="{Binding Title}"/>
</StackPanel>
</StackPanel>
</Grid>
اگر ویژگی Mode نوشته نشود بصورت پیش فرض بهصورت OneWay تعبیر میشود. حالت قبل. همچنین در کد بالا دو Textbox در صفحه قرار داده شدهاند تا با تغییر محتوای آن بتوانیم تاثیر عملیات دوطرفهی انقیاد را بر روی Textblockهای بعدی مشاهده کنیم.
پس از اجرای برنامه (بخش CodeBehind نیازی به اصلاح ندارد) مقداری جدید در Textbox موجود در صفحه تایپ کنید. کافی است Focus از روی کنترلی که محتوای آن را تغییر دادهاید، عوض شود، بلافاصله Textblock متناظر با آن، با محتوای جدیدی که در منبع داده اعمال شده است بهروز میشود.