PDA

View Full Version : سوال: معرفی منبع آموزش Binding



Shahab_H
چهارشنبه 25 اسفند 1389, 12:23 عصر
با سلام
من تو این چند روز کلی Ebook داونلود کردم تو همشون اولش Binding خیلی ساده شروع میشه مثل

CODE]<textblock text="{binding elementname=textbox1,path=text}"></textblock>[/CODE]


یدفعه بی هیچ مقدمه ای میره سراغ data template و conventor و ... اونم به صورت کاملا حرفه ای!

اگر ممکنه یه منبع مناسب معرفی کنید برای یادگیری

ricky22
چهارشنبه 25 اسفند 1389, 13:25 عصر
سلام.
به نظر من این لینک ها مفید هستند.


http://www.wpftutorial.net/Databinding.html
http://www.codeproject.com/KB/WPF/wpf6.aspx

موفق باشید.

مهدی فرزاد
چهارشنبه 25 اسفند 1389, 14:02 عصر
سلام
توی اینترنت سرچ کنید منابع زیاد هست من بشخصه منبع خاصی سراغ ندارم اما بهترین راه تجربه کردنه
من پیشنهاد میکنم شما با منابع موجود شروع کنید هر کجا سئوالی بود مطرح کنید اگر من یا هر کدوم از دوستان بدونیم جواب میدیم و اینجوری به نظر من بهتر نتیجه خواهی گرفت

Shahab_H
چهارشنبه 25 اسفند 1389, 19:58 عصر
با تشکر از پاسختون
تو این کدها بعضی جاها کنترل ها رو مستقیما با Name="name" نامگذاری کرده بعضی جاها به صورت x:Name="name" فرق اینا چیه؟ و چه موقع باید از هر کدوم استفاده کرد؟
در قسمت Converter همچین کدی هست:
<StackPanel>
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="boolToVis" />
</StackPanel.Resources>

<CheckBox x:Name="chkShowDetails" Content="Show Details" />
<StackPanel x:Name="detailsPanel"
Visibility="{Binding IsChecked, ElementName=chkShowDetails,

Converter={StaticResource boolToVis}}">
</StackPanel>




چرا در قسمت stackpanel.respurces تعریف شده؟
<BooleanToVisibilityConverter x:Key="boolToVis" />
یعنی چی؟:خجالت:

می دونم converter وقتی باید استفاده شه که نوع خاصیت مبدا و مقصد متفاوته ولی بعضی جاها خودش مثلا int به string رو تبدیل می کنه! از کجا میشه
فهمید باید کی از converter استفاده کرد؟

مهدی فرزاد
پنج شنبه 26 اسفند 1389, 01:29 صبح
سلام
اول بهتر بود هر سئوال رو جدا گانه میپرسیدید

در مورد سئوال اول در عمل تفاوتی در نوشتن X:Name و Name برای شما ایجاد نمیشه
x: برای مپ کردن فضای نام http://schemas.microsoft.com/winfx/2006/xaml استفاده شد، که فضای نام اختصاصی XAML است
عنصرهای XAML در قالب کاری WPF، پراپرتی Name را به ارث می برند، که معادل x:Name تعریف شده XAML است.

حالا سئوال دوم
خیلی ساده میگم
شما برای اینکه بتونید از کلاس converter که نوشتید استفاده کنید باید اونو در قالب یک ریسورس معرفی کنید و این کار رو میتونید هم در Windows.Resources معرفی کنید هم در ریسورس کنترلی که اون کانورتر درون زیر مجموعه هاش قراره اعمال بشه (مثل همین مثالی که نوشتید )
قبل از اون باید فضای نام کانورتر رو معرفی کنید به عنوان مثال

xmlns:local="clr-namespace:Baarbari"
.
.
.
<UserControl.Resources>

<local:MonyConvertor2 x:Key="MonyConvertor2"/>


</UserControl.Resources>

حالا میتونم به شکل زیر ازش استفاده کنم

<MyTextBox Text="{Binding CostStroage, Converter={StaticResource MonyConvertor2}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

سئوال سوم
شما در زمان Binding بر روی خروجی و ورودی اطلاعات از دیتابیس به کنترل و بلعکس نظارت کمی دارید مثلا میخواد تاریخ میلادی در ج شده در دیتابیس رو به صورت شمسی در تکس باکس نمایش بدید یا برعکس تاریخ درج شده شمسی رو به شکل میلادی در دیتابیس ذخیره کنید اینجا کانورتر به داد شما میرسه و در بیان بسیار ساده میشه گفت یک سد در سر راه رد و بدل شدن اطلاعات قرار میگیره و ابتدا اونو به شکل دلخواه شما ویرایش میکنه بعد اون ها رو رد و بدل میکنه

یک مثال دیگه اینکه شما یک تکس باکس رو بایند کردید به دیتابیس و میخواد اگر خالی بود مقدار Null رو به دیتا بیس بفرسته ولی وقتی تکس باکس خالیه یک مقدار String.Empty ارسال میه نه مقدار Null ، خوب شما یک کانورتر میگذارید و نیجه رو اگر Empty بود به صورت Null برای دیتابیس یا هر منبع دیگه ای که قرار اطلاعات رو دریافت کنه (میتونه یک کنترل دیگه باشه) ارسال مکنید
این هم یک نمونه کد کانورتر برای تبدیل تاریخ ها از میلادی به شمسی و بر عکس



class DateConvertor : IValueConverter

{



PCalendar p = new PCalendar(); //کلاس ساخته شده برای تبدیل تاریخ ها



public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{



//دریافت اطلاعات از دیتابیس و تبدیل به تاریخ شمسی به صورت استرینگ





if (value != null)



return p.ConvertToPersionDate((DateTime)value);



else



return string.Empty;

}



public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{





// بازگشت اطلاعات از تکس باکس و تبدیل به دیتا تایم و تاریخ میلادی برای درج در دیتابیس



if (value.ToString() != string.Empty || value!= null)



return p.ConvertToEnglishDate(value.ToString());



else



return null;

}

}


البته این ساده ترین حالت برای تعریف کانورتر هست
شما در کانورتر اعمال پیچیده تری رو هم میتونید انجام بدید مثلا بر اساس value یک سری اعمال دیگه و حتی محاسبات پیجیده و اعمال نتیجه اونها در یک فرم یا کلاس دیگه رو هم انجام بدید مثلا اگر Value == 1 شد در فرم دیگه یک سری اطلاعات بخونه و در دیتابیس درج کنه و چند تکس باکس و هم Hide کنه!! و ..................

امیدوارم کمکی کرده باشم

Shahab_H
جمعه 27 اسفند 1389, 11:14 صبح
ممنون خیلی عالی و کامل توضیح دادین خیلی از مشکلاتم بر طرف شد

1 سوال دیگه:
در این خط کد

<local:MonyConvertor2 x:Key="MonyConvertor2"/>
منظور از local چیه؟ منظورش اینه که کلاس تعریف شده در داخل خود برنامه ست؟
و اگه اشتباه نکم MonyConvertor2 اول همون نام کلاس Converter نوشته شده در قسمت C# و دومی تعریف کلید برای دسترسی بهش در محیط XAML ئه؟

مهدی فرزاد
جمعه 27 اسفند 1389, 12:05 عصر
سلام
با اشاره به آموزشهای آقای کیانی :
با به کار بردن کلمه xmlns می توانید فضای نام های مورد نظر را در اسناد XAML خود، تعریف کنید. قاعده نحوی تعریف فضای نام ها به صورت زیر می باشد:

xmlns="clr-namespace:[NameSpace Name];assembly=[Assembly Name]"

در تعریف فوق، به جای [NameSpace Name] بایستی نام فضای نام مروبطه را قرار دهید. و به جای [Assembly Name] بایستی نام فایل اسمبلی را که آن فضای نام در آن قرار گرفته است را قرار دهید

نکته:
اگر به خاطر داشته باشید، می توانستید برای فضای نام های موجود، یک اسم مستعار معرفی کنید و از از آن اسم در برنامه خود استفاده نمایید. به عنوان مثال می توانید کدی به صورت زیر داشته باشید:

using sys=System;


توسط این کد، شما نام مستعار sys را برای System انتخاب کرده اید. حال به راحتی می توانید از کلمه sys به جای کلمه Systsem در برنامه خود استفاده کنید و به فضای نام ها و کلاس های داخلی آن دسترسی داشته باشید.
در فایل های XAML نیز می توانید، عملی مشابه به این را انجام دهید. به قطعه کد زیر توجه کنید:
xmlns:local="clr-namespace:Baarbari"
همانطور که مشاهده می کنید، از کلمه local به عنوان نام مستعار برای فضای نام مذکور، استفاده شده است. حال می توانید توسط این کلمه به کلاس های درون فضای نام خود دسترسی داشته باشید. (این کلمه میتونه هر چی دلتون میخواد باشه چون من با نرم افزار Blend کار کرده بودم خودش این نام رو انتخاب کرده بود!)

برای قسمت دوم سئوال شما : بله برای این کانورتر یک کلید تعریف شده تا در برنامه با استفاده از این کلید به آن دسترسی داشته باشید

Shahab_H
جمعه 27 اسفند 1389, 19:48 عصر
جناب Mehdi550u (http://barnamenevis.org/member.php?67273-Mehdi550u) واقعا از توجهتون خیییلی ممنونم و وقتی که برای پاسخ دادن میذارین:خجالت:
در این سمپل مثلا 1 کلاس دارم به اسم Employee که این شکل تعریفش کردم
class Employee
{
private string name;
private string family;
private string id;

public string Name
{
get { return name; }
set { name = value; }
}

public string Family
{
get { return family; }
set { family = value; }
}

public string ID
{
get { return id; }
set { id = value; }
}
}

در فرم اصلی 3 تا textbox دارم که داخلش مقادیر رو قرار می دم و 1 دکمه دارم که با زدنش یک کارمند جدید اضافه می کنه

using System;
using System.Collections.Generic;
using System.Linq;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace EmployeesDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
Employee newe = new Employee();
newe.Name = newe.Name=nameTextBox.Text;
newe.Family = familyTextBox.Text;
newe.ID =IDTextBox.Text;
employeec.Add(newe);


}

ObservableCollection<Employee> employeec = new ObservableCollection<Employee>();

}
}


سوال اول: راستش نمی دونم دقیقا ObservableCollection چرا باید تعریف کنم! علتش اینه که در لیست باکس وقتی آیتم رو سلکت کنم به جای StackPanel مستقیما خود Employee انتخاب میشه؟

یک لسیت باکس هم تعریف کردم که می خوام اطلاعات کرمند ها رو نشون بده.

تعریف لیست باکس:
<ListBox Grid.Column="2" Grid.RowSpan="3" ItemsSource="{Binding MainWindow1, Path=epmloyeec}"
ItemTemplate="{StaticResource edt}">

</ListBox>

منظورم از MainWindow1 همون MainWindow هستش که خاصیت Name ش رو MainWindow1 گذاشتم


تعریف Data Template:
<Window.Resources>
<DataTemplate x:Key="edt">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Name}"> </TextBlock>
<TextBlock Text="{Binding Path=Family}"></TextBlock>
</StackPanel>
</DataTemplate>
</Window.Resources>

وقتی برنامرو Run می کنم لیست باکس خالیه و نمی دونم مشکل از کجاست خیلی ممنون میشم راهنمایی کنید

مهدی فرزاد
شنبه 28 اسفند 1389, 00:12 صبح
سلام
پاسخ اول شما باید این نام و نام خانوادگی را در یک کالکش ذخیره کنید برای همین حالا در اینجا شما ObservableCollection را انتخاب کرده اید میتوانید از انواع کالکشن دیگر هم استفاده کنید

ببینید Binding شما اشکال دارد
شما باید خاصیت DataContext لیست باکس خود را یا Panel که لیست باکس در آن قرار دارد را ست کنید
پس public MainWindow()
{
InitializeComponent();
listbox.DataContext = employeec;
}

و کد لیست باکس رو هم به شکل زیر اصلاح کنید
<ListBox Name="listbox" ItemsSource="{Binding}" ItemTemplate="{StaticResource edt}" Margin="80,102,121,65"></ListBox>

مشکل کد شما با این دو کار حل میشه

Shahab_H
شنبه 28 اسفند 1389, 11:45 صبح
خیلی خیلی ممنون واقعا لطف کردین:لبخندساده:

اگر به جای observable collection مثلا از arraylist استفاده کنم وقتی روی آیتم کلیک می کنم آیتم رو به صورت Container مثلا stack panel میشناسه؟ منظورم از کجا می فهمه Item انتخاب شده از نوع Employee هستش و خیلی راحت با این کد میشه نام رو ازش گرفت:
class Selected_Converter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null)
{
var sitem = (Employee)value;
return "you selected: " + sitem.Name;
}
else return "you Selected Nothing";
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
به جای این که به stackpanel تبدیل شه بعد از فرزندانش انواع متنی رو انتخاب کرد

مهدی فرزاد
شنبه 28 اسفند 1389, 12:11 عصر
سلام نیازی به این کار هم نیست خیلی ساده
مثلا

private void listbox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{


MessageBox.Show(((Employee)this.listbox.SelectedIt em).Name + ((Employee)this.listbox.SelectedItem).Family);

}

Shahab_H
شنبه 28 اسفند 1389, 13:12 عصر
1- فرق DataContext با ItemSource چیه؟

2- یک مثال مشابه دیگه نوشتم ولی موقع run شدن هنگ می کنه
Exception has been thrown by the target of an invocation.

ممنون میشم راهنمایی کنید
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Binding_To_Object
{
class Company
{
private string name;
private string city;
private string street;

public string Name
{
get { return name; }
set { name = value; }
}

public string City
{
get { return city; }
set { city = value; }
}

public string Street
{
get { return street; }
set { street = value; }
}
}
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Binding_To_Object
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
List<Company> companies = new List<Company>();

public MainWindow()
{
Company comp = new Company();
comp.Name = "پایتخت";
comp.City = "تهران";
comp.Street = "میرداماد";
companies.Add(comp);

comp.Name = "اسکان";
comp.City = "تهران";
comp.Street = "میرداماد";
companies.Add(comp);

comp.Name = "علاالدین";
comp.City = "تهران";
comp.Street = "جمهوری";
companies.Add(comp);

lstbox1.DataContext = companies;
InitializeComponent();
}


}
}


<Window x:Class="Binding_To_Object.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Name="this1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<ListBox Name="lstbox1" Grid.Row="0" DisplayMemberPath="Name" ItemsSource="{Binding}"></ListBox>
<StackPanel Grid.Row="1" Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<TextBlock>Name</TextBlock>
<TextBlock Margin="0,5,0,0">City</TextBlock>
<TextBlock Margin="0,5,0,0">Street</TextBlock>
</StackPanel>
<StackPanel Orientation="Vertical" DataContext="{Binding ElementName=lstbox1, Path=SelectedItem}">
<TextBox Text="{Binding Path=Name}" ></TextBox>
<TextBox Text="{Binding Path=City}"></TextBox>
<TextBox Text="{Binding Path=Street}"></TextBox>
</StackPanel>
</StackPanel>
</Grid>

</Window>

مهدی فرزاد
شنبه 28 اسفند 1389, 13:41 عصر
سلام

کنترل هایی که ItemSource دارن میشه از این گزینه در کد نویسی بجای
DataContext
استفاده کنید ولی کنترلی مثل StackPanel دارای ItemSource نیست و شما میخواهید کنترل های درون آن را Bind کنید پس DataContext بکار میبرید
البته کاربرد و تفاوت های اون ها بیشتر هم هست و فقط بحث دیتا بیس نیست


کد ها رو بعد از InitializeComponent(); بنویسید و حتما بعد از هر Add مجددا بنویسید
comp = new Company();
البته اگر به شکل زیر بنویسید بهتره



List<Company> companies = new List<Company>();



public MainWindow()

{

InitializeComponent();


companies.Add(
new Company { Name = "پایتخت", City = "تهران", Street = "میرداماد" });


companies.Add(
new Company { Name = "اسکان", City = "تهران", Street = "میرداماد" });


companies.Add(
new Company { Name = "علاالدین", City = "تهران", Street = "جمهوری" });

lstbox1.DataContext = companies;

}

Shahab_H
شنبه 28 اسفند 1389, 16:21 عصر
شرمنده انقد سوال می کنم واقعا این همه ebook و منبعی که دیدم هیچ کدوم به اندازه ی این تاپیک کمکم نکرده واقعا ممنونم

علت این که در مثال اول با استفاده از item source برنامه درست کار نمی کرد ولی با data context درست شد چیه؟ ممنون میشم راهنمایی کنید

مهدی فرزاد
شنبه 28 اسفند 1389, 18:11 عصر
علت Itemsource یا data context نبود علت نوشتن این کد بود که من اصلاحش کردم
ItemsSource="{Binding MainWindow1, Path=epmloyeec}"
این اشتباه
و همچنین شما در هیچ کجای کد C# برنامه نه dataContext رو معرفی کرده بودید و نه ItemSource

Shahab_H
یک شنبه 29 اسفند 1389, 11:30 صبح
من از view استفاده کردم با چنین کدی:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace ViewDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private DataClasses1DataContext northwndCustomers = null;
CollectionView customerView = null;

private void Window_Loaded(object sender, RoutedEventArgs e)
{

northwndCustomers = new DataClasses1DataContext();
this.DataContext = northwndCustomers.Customers;
customerView = (CollectionView)CollectionViewSource.GetDefaultVie w(northwndCustomers.Customers);
customerView.MoveCurrentToFirst();
}

private void Button_Click(object sender, RoutedEventArgs e)
{
if (customerView.CurrentPosition < customerView.Count - 1)
customerView.MoveCurrentToNext();
}
}
}


الان با زدن دکمه ی next رکورد بعدی در textbox هام نمایش داده میشه
سوالم اینه که از کجا این ارتباط بین CollectionView و DataContext صفحه ی اثلی ایجاد شده؟ چون من هیچ جا هیچ ارتباطی بینشون تعریف نکردم تنها نقطه ی اشتراکشون اینه که منبع اطلاعاتی هر دوشون یک Table از یک Dataset هستش

مهدی فرزاد
یک شنبه 29 اسفند 1389, 11:43 صبح
سلام
(CollectionView)CollectionViewSource.GetDefaultVie w(northwndCustomers.Customers);

البته در هنگام استفاده از دیتابیس روش خیلی مناسب تر و بهتر برای استفاده از CollectionViewSource هست که من بعدا یک مثال با اون براتون میگذارم

مهدی فرزاد
یک شنبه 29 اسفند 1389, 11:56 صبح
این فایل رو با دقت بررسی کنید

Mehran Badami
یک شنبه 19 شهریور 1391, 15:08 عصر
با سلام و خسته نباشید
من در برنامم از یک ObservableCollection استفاده کردم و ان را به یک لیست مقید کردم وقتی از ObservableCollection یک هیتم کم یا زیاد میکنم رو UI منعکس میشه ولی وقتی یکی از فیلدا کلاس تغییر میدم نمیشه من قبلا با کلاسایی که Linq میداد کار میکردم جواب میداد
ممنون میشم کمک کنید

مهدی فرزاد
دوشنبه 20 شهریور 1391, 08:02 صبح
سلام
آیا در کلاس شما Property Change Notification رو پیاده سازی شده؟
این لینک رو ببینید
http://msdn.microsoft.com/en-us/library/ms743695.aspx