خواندن داده اکسل و نمایش آن در کامبوباکس به‌همراه عکس در WPF

موضوعات : تخصصی, سی‌شارپ, زمل

خواندن داده برای یک برنامه‌نویس بخصوص اگر بخواهد برنامه‌هایی که برپایه دیتا(دیتابیس) هستند بنویسد بسیار مهم خواهدبود، بخش مهمی از این نوع برنامه‌ها عملیات‌هایی چون جستجو، درج, بروزرسانی‌ و حذف داده‌ها را شامل می‌شوند. این عملیات‌ها اگر با استفاده از اوراکل(Oracle)، اس‌کیوال(SQL) و یا برنامه‌هایی مشابه باشد تا حدود زیادی ساده و راحت است اما اگر داده‌ها در یک فایل متنی یا یک اکسل ذخیره شده‌باشد این‌گونه عملیات‌ها سخت‌تر و مشکل‌تر خواهدبود چرا که ساختار داده خوانده شده، یک ساختار جدولی نیست و امکاناتی چون جستجو، درج، بروزرسانی و حذف را باید توسط برنامه شبیه‌سازی کرد. در اینجا هدف فقط خواندن داده‌ها از یک شیت(Sheet) خاص از یک فایل اکسل است و نمایش آن‌ها درون یک کامبوباکس است، البته می‌خواهیم کامبوباکس‌مان عکس را نیز نشان دهد. در گذشته(منظور برنامه‌های فرم‌بیس) گذاشتن عکس در کامبوباکس مشکلات فراوانی داشت و نیاز به استفاده از APIها بود.


نکته: پیش از آغاز باید توجه کنید که فایل‌های اکسل و نمونه عکس‌های پرسنل درون یک فولدر به نام Resource قرار گرفته ولی اگر شما فایل اکسل و عکس‌ها را جای دیگری ذخیره‌کرده‌اید باید کدهای زیر را براساس فولدر محل ذخیره تغییردهید. 

برنامه ویژوال‌استودیو را اجرا و یک برنامه از نوع WPFایجاد کنید. در پنجره MainWindow(و در بخش زمل) میان دو دستور Gridکد زیر را وارد کنید:

<ComboBox HorizontalAlignment="Left" 
                  x:Name="myCombo"
                  Margin="114,10,0,0"
                  VerticalAlignment="Top"
                  Width="275"
                  SelectedValuePath="code"
                  DisplayMemberPath ="name"/>
        <Button Content="Button"
                HorizontalAlignment="Left"
                Margin="114,117,0,0"
                VerticalAlignment="Top"
                Width="275" Click="Button_Click"/>
        <TextBlock HorizontalAlignment="Right"
                   Height="75"
                   Margin="0,37,128,0"
                   TextWrapping="Wrap"
                   Text="{Binding ElementName=myCombo,Path=SelectedValue}"
                   VerticalAlignment="Top"
                   Width="275"
                   Background="AliceBlue"/>

در اینجا یک کامبوباکس به نام myCombo داریم که نام(name) پرسنل را نشان می‌دهد اما پس از انتخاب، کد(code) را به عنوان خروجی ارسال می‌کند. دکمه Button وظیفه خواندن داده‌ها را دارد(کدهای آن در زیر خواهد آمد) و TextBlock کد فرد انتخاب شده را نشان‌میدهد. در خط 17 گفته‌شده که مقدار متنی TextBlock ما با المان myCombo و با مقدار انتخاب شده(SelectedValue) که یکی از خواص(Property) کامبوباکس است مرتبط یا بایند(Bind) است. وقتی یک فرد انتخاب می‌شود بدون‌ درنگ کد شخص در TextBlock نمایش داده می‌شود.

اما کد اصلی خواندن داده‌ها از یک شیت از یک فایل اکسل:

نخست کد زیر را در مکان خودش وارد کرده(توجه کنید تا اطلاعات تکراری نباشد):

using System.Windows;
using System.Data;
using System.Data.OleDb;

و سپس این کد را درون کلاس MainWindow قراردهید.  

private void Button_Click(object sender, RoutedEventArgs e)
        {
            string _path = @"..\..\Resource\c#.xlsx";
            string _connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + _path + ";Extended Properties=Excel 12.0;";
            using (OleDbDataAdapter _adaptor = new OleDbDataAdapter("SELECT * FROM [Sheet2$]", _connStr))
            {
                DataSet _ds = new DataSet();
                _adaptor.Fill(_ds);
                myCombo.ItemsSource = _ds.Tables[0].DefaultView;
            }
        }

می‌دانیم اطلاعات مورد نظر در یک فایل به‌نام c#.xlsx و در شیت Sheet2 و درون فولدری به نام Resource که درون فولدر اصلی برنامه قراردارد(چون فایل اجرایی برنامه پس از کمپایل شدن در فولدر bin\Debug قراردارد لذا از ..\..\ استفاده شده است یعنی دو فولدر به عقب برمی‌گردیم) ذخیره‌شده. توجه کنید _connStr برای ورژن‌های مختلف Office می‌تواند متفاوت باشد، برنامه را ذخیره و اجرا کنید اگر مشکلی نباشد با زدن دکمه Button، اطلاعات را پس از لود و می‌توانید از کامبوباکس انتخاب کنید.

در اینجا فقط نام و کد وجود دارد اما تصویر چگونه باید نمایش داده‌شود؟ برای این‌که تصویر هم نمایش داده‌شود یک پنجره جدید به‌نام ImageWindow ایجاد نمایید و در بخش کد زمل در تعریف Window کد زیر را اضافه کنید.

xmlns:local="clr-namespace:YourProgramNamespace"

که در آن YourProgramNamespace نام نیم‌اسپیس برنامه شما است مثلا برای برنامه ضمیمه به این صورت می‌باشد:

<Window x:Class="ReadExcelFileInWPF.ImageWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ReadExcelFileInWPF"
        Title="ImageWindow" Height="300" Width="300">

در اینجا نیم‌اسپیس برنامه ReadExcelFileInWPF می‌باشد. با این دستور هرگاه بخواهیم از یک کلاس تعریف شده درون برنامه‌مان را در کدزمل استفاده کنیم کافی است جلوی نام کلاس کلمه local قراردهیم.

در میان دو دستور Grid کد زیر را اضافه کنید:

<ComboBox HorizontalAlignment="Left" 
    		x:Name="imgCombo"
    		Margin="7,13,0,0"
    		VerticalAlignment="Top"
    		Width="275"
    		SelectedValuePath="empCode">
            <ComboBox.ItemTemplate>
                <ItemContainerTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image MaxWidth="64" MaxHeight="64" Source="{Binding empImage}" />
                        <TextBlock Text="{Binding empName}" VerticalAlignment="Center"/>
                    </StackPanel>
                </ItemContainerTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <Button Content="Button"
    		HorizontalAlignment="Left"
    		Margin="7,120,0,0"
    		VerticalAlignment="Top"
    		Width="275" Click="Button_Click"/>

خط شماره 7، تمپلیت مرتبط با آیتم‌های کامبوباکس را تعیین می‌کند، در اینجا یک استک‌پانل StackPanel به همراه دو المان Image(برای نمایش تصویر) و TextBlock(برای نمایش نام) قراردارد و از آنجایی که ItemTemplate یک کامبوباکس به ItemSource آن مرتبط است لذا باید دو فیلد empName و empImage در ItemSource موجودباشند. در نهایت کد زیر را درون کلاس ImageWindow وارد کنید:

private void Button_Click(object sender, RoutedEventArgs e)
        {
            string _path = @"..\..\Resource\c#.xlsx";
            string _connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + _path + ";Extended Properties=Excel 12.0;";
            using (OleDbDataAdapter _adaptor = new OleDbDataAdapter("SELECT * FROM [Sheet3$]", _connStr))
            {
                DataSet _ds = new DataSet();
                _adaptor.Fill(_ds);
                imgCombo.ItemsSource = _ds.Tables[0].DefaultView;
            }
        }

این کد چندان تفاوتی با بالایی ندارد(تنها تفاوت در قرار کیری اطلاعات در Sheet3 می‌باشد). برنامه را برای بازشدن پنجره ImageWindow تنظیم و اجرا کنید.

در اینجا اگر به فایل اکسل و شیت سوم آن نگاه کنید در ستون empImage همه عکس‌ها با ../../Resource/ شروع می‌شوند، به این دلیل که محل فایل‌ها در اینجا قرار دارد، اگر محل فایل‌ها همگی در یک فولدر باشد و بخواهیم آن فولدر را پیش‌فرض تصاویر کنیم چگونه ممکن است؟ یک راه آن افزودن کد محل پیش‌فرض در زمان لود داده‌ها است. اما راهی بهتر هم وجود دارد که از قابلیت‌های شگفت‌انگیز در WPF می‌باشد. استفاده از Converterها.

سپس یک پنجره جدید به‌نام ImageFolderStrWindow ایجاد کنید، درون کلاس کد زیر را اضافه کنید:

private void Button_Click(object sender, RoutedEventArgs e)
        {
            string _path = @"..\..\Resource\c#.xlsx";
            string _connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + _path + ";Extended Properties=Excel 12.0;";
            using (OleDbDataAdapter _adaptor = new OleDbDataAdapter("SELECT * FROM [Sheet4$]", _connStr))
            {
                DataSet _ds = new DataSet();
                _adaptor.Fill(_ds);
                imgCombo.ItemsSource = _ds.Tables[0].DefaultView;
            }
        }

کد زیر را اضافه کنید(درصورت موجود نبودن)

using System.Windows.Data;

درون نیم‌اسپیس(توجه کنید نه کلاس بلکه نیم‌اسپیس) یک کلاس از نوع IValueConverter با نام ImageFolderConverter ایجاد کنید یا کد زیر را اضافه کنید:

class ImageFolderConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value != null)
                return "../../Resource/" + value.ToString();
            else
                return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return value.ToString();
        }
    }

درون فایل زمل پنجره پس از تعریف local که دربالا شرح دادیم ریسورس(Resource) زیر را اضافه کنید:

<Window.Resources>
        <local:ImageFolderConverter x:Key="ImageFolderConverter"/>
    </Window.Resources>

در این دستور کلاس ImageFolderConverter با یک کلید که در زمل قابل فهم است که در اینجا تصادفی همان ImageFolderConverter(و می‌توانست هر چیزدیگری نیز باشد) است جایگزین می‌گردد، و کد زیر را در بین دو دستور گرید قراردهید:

<ComboBox HorizontalAlignment="Left" 
    		x:Name="imgCombo"
    		Margin="7,13,0,0"
    		VerticalAlignment="Top"
    		Width="275"
    		SelectedValuePath="empCode">
            <ComboBox.ItemTemplate>
                <ItemContainerTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image MaxWidth="64" MaxHeight="64" Source="{Binding empImage,Converter={StaticResource ImageFolderConverter}}" />
                        <TextBlock Text="{Binding empName}" VerticalAlignment="Center"/>
                    </StackPanel>
                </ItemContainerTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
        <Button Content="Button"
    		HorizontalAlignment="Left"
    		Margin="7,120,0,0"
    		VerticalAlignment="Top"
    		Width="275" Click="Button_Click"/>

در اینجا فقط خط 10 را شرح می‌دهیم آن‌هم بخش Converter را:

فرض کنید آیتم نخست برای نمایش در کامبوباکس خوانده می‌شود دستور Converter اطلاعات را از طریق نام زملی ImageFolderConverter که در بخش ریسورس تعریف شده  به کلاس ImageFolderConverter ارجاع می‌دهد، تابع Converter مقدار value را با "../../Resource/" + value.ToString(); جایگزین کرده و به کد زمل برمی‌گرداند و کار تمام است.


فایلهای مطلب

کپی
لینک اشتراک گذاری

  • 818
  • 0