استفاده از ItemsControl جهت ساختن کنترل های پویا در WPF
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: سه دقیقه

از ItemsControl برای ارائه مجموعه ای از کنترل‌ها استفاده می‌شود،در اینجا قرار است از آن استفاده کنیم و یک کنترل پویا ایجاد کنیم.برای مثال در نظر بگیرید،قرار است یک DropDownPanel ایجاد کنیم و در جاهای مختلف برنامه کنترل‌های مختلفی را درون آن  قرار بدهیم.برای ایجاد آن به صورت زیر عمل میکنیم:

<UserControl x:Class="MySystem.Common.Controls.DropDownPanel"
             …              
             x:Name="This">
    <Grid>
        <ToggleButton x:Name="ShowPopupButton"/>
        <Popup
            PlacementTarget="{Binding ElementName=ShowPopupButton}"
            Placement="{Binding PopupPlacement, ElementName=this}"
            PopupAnimation="Slide"
            AllowsTransparency="True"
            Focusable="True" 
            StaysOpen="False"
            IsOpen="{Binding IsChecked, ElementName=ShowPopupButton }">
            <Border Background="#FFE3EAF3" BorderThickness="1" Padding="2">
                <Grid>
                    <ItemsControl ItemsControl.ItemsSource="{Binding Path=PanelItems,ElementName=This }">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <Grid>

                                </Grid>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                    </ItemsControl>
                </Grid>
            </Border>
        </Popup>
    </Grid>
</UserControl>

همانگونه که در کد بالا می‌بینید ،برای ایجاد DropDownPanel  از یک ToggleButton و یک Popup که خصوصیت IsOpenآن به IsChecked مربوط به ToggleButton وصل شده است، استفاده کردیم و در قسمت بدنه کنترل به جای قراردان کنترل هایی که قرار است در آن نمایش داده شوند،از یک ItemsControl استفاده کردیم که خصوصیت ItemsSource آن به یک خصوصیت پیوست شده از نوع ObservableCollection<UIElement>در Code Behind، مقید شده است.تعریف این خصوصیت پیوست شده به صورت زیر است:

  public static readonly DependencyProperty PanelItemsProperty = DependencyProperty.Register("PanelItems"
            , typeof(ObservableCollection<UIElement>)
            , typeof(DropDownPanel)
            , new PropertyMetadata(new ObservableCollection<UIElement>()));
        public ObservableCollection<UIElement> PanelItems
        {
            get
            {
                return (ObservableCollection<UIElement>)GetValue(PanelItemsProperty);
            }
            set
            {
                SetValue(PanelItemsProperty, value);
            }
        }

برای استفاده از کنترل یک وهله از این کنترل را ایجاد می‌کنیم و کنترل هایی که قرار است درDropDownPanelنمایش داده شوندرا بهPanelItems  اضافه میکنیم:

<Window x:Class="MySystem.UI.View.Window1"
              ….
             xmlns:controls ="clr-namespace:MySystem.Common.Controls;assembly=GoldAccountingSystem.Common.Controls">
    <Grid>
        <controls:DropDownPanel>
            <controls:DropDownPanel.PanelItems>
                    !--Put Controls Here--!
            </controls:DropDownPanel.PanelItems>
        </controls:DropDownPanel>
    </Grid>
</Window>

تا این مرحله کنترل مورد نظر را ایجاد و استفاده کردیم.اما یک مشکل وجود دارد،چنانچه از این کنترل چند بار در یک فرم استفاده شود، به درستی عمل نمیکند به اینصورت که فرزندان PanelItems تمام شی‌های ساخته شده از کنترل در یک فرم برابر هم و برابر مقداری می‌شود که برای آخرین کنترل قرارداده ایم. دلیل این امر این است که ما یکبار در هنگام تعریف خصوصیت PanelItems یک وهله از آن را به عنوان مقدار پیش فرض ایجاد کردیم و برای همه‌ی نمونه هایی از کنترل که در فرم قرار می‌گیرند از همان وهله استفاده می‌شود.

برای حل مشکل فوق یک کلاس از نوع ObservableCollection<UIElement> ایجاد کرده و هنگام ساختن کنترل در فرم از این کلاس برای وهله سازی مجدد از PanelItems استفاده می‌کنیم:

namespace MySystem.Common.Controls
{
    public class UIElementCollection : ObservableCollection<UIElement> { }
}

همانطور که گفته شد از کلاس ایجاد شده برای وهله سازی به صورت زیر استفاده می‌شود:

<Window x:Class="MySystem.UI.View.Window1"
              ….
             x:Name="This"
             xmlns:controls ="clr-namespace:MySystem.Common.Controls;assembly=GoldAccountingSystem.Common.Controls">
    <Grid>
        <commonControls:DropDownPanel>
            <commonControls:DropDownPanel.PanelItems>
                <commonControls:UIElementCollection>
                    !--Put Controls Here--!
                </commonControls:UIElementCollection>
            </commonControls:DropDownPanel.PanelItems>
            </commonControls:DropDownPanel>
    </Grid>
</Window>
یک مثال ساده از توضیحات بالا را از آدرس روبرو می‌توانید دریافت نمایید: ItemsControlTest-a349625a156d4aeaaca288f000ae6d7a.rar  
  • #
    ‫۱۱ سال و ۳ ماه قبل، پنجشنبه ۶ تیر ۱۳۹۲، ساعت ۲۳:۰۲
    اگر امکانش باشه این مطلب رو به صورت یک مثال یا پروژه ساده قابل دریافت قرار بدید، امکان پیگیری اون بیشتر خواهد شد. ممنون.
    • #
      ‫۱۱ سال و ۳ ماه قبل، یکشنبه ۹ تیر ۱۳۹۲، ساعت ۱۳:۳۷
      سلام،ممنون از پیشنهادتون،یک مثال خیلی ساده به توضیحات بالا اضافه کردم.