欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

c# WPF實(shí)現(xiàn)Windows資源管理器(附源碼)

 更新時(shí)間:2021年03月02日 08:43:44   作者:Hello 尋夢(mèng)者!  
這篇文章主要介紹了c# WPF實(shí)現(xiàn)Windows資源管理器的示例(附源碼),幫助大家更好的理解和學(xué)習(xí)使用c#,感興趣的朋友可以了解下

    今天我來寫一篇關(guān)于利用WPF來實(shí)現(xiàn)Windows的資源管理器功能,當(dāng)然只是局部實(shí)現(xiàn)這個(gè)功能,因?yàn)樵诤芏鄷r(shí)候我們需要來實(shí)現(xiàn)對(duì)本機(jī)資源的管理,當(dāng)然我們可以使用OpenFileDialog dialog = new OpenFileDialog()這個(gè)Microsoft.Win32命名空間下的這個(gè)類來實(shí)現(xiàn)一些資源查找和導(dǎo)入的功能,但是在很多時(shí)候我們可能需要更多的功能,并且希望能夠集成到我們自己的項(xiàng)目中,但是我們這個(gè)時(shí)候就不得不自己來寫一套來集成到我們的軟件中去了,因?yàn)镺penFileDialog這個(gè)是無法作為一個(gè)UserControl加入到我們的項(xiàng)目中的,當(dāng)然我們只是實(shí)現(xiàn)了其中的一部分功能,因?yàn)閃indows的資源管理器也是一個(gè)重量級(jí)的應(yīng)用,也是十分龐大和復(fù)雜的,這里只是通過這個(gè)Demo來加深對(duì)WPF的MVVM模式及軟件基本功的鞏固。

  在正式介紹整體框架之前,首先來看看整體的結(jié)構(gòu),從而對(duì)其有一個(gè)大概的了解。

  整個(gè)界面從大的方面來說主要包括三個(gè)方面:1 文件及文件夾顯示區(qū)域、2 導(dǎo)航區(qū)域、3 路徑顯示區(qū)域,其實(shí)在整個(gè)界面中,2和3都是圍繞1來進(jìn)行操作的,三個(gè)區(qū)域之間的耦合性其實(shí)是非常高的,所以常規(guī)的做法就是三個(gè)部分分為三個(gè)UserControl,并且同時(shí)綁定到一個(gè)ViewModel中,這樣整個(gè)層次也就比較清晰了,缺點(diǎn)是一個(gè)ViewModel中代碼太多,職責(zé)非常大,所以在這個(gè)DEMO中嘗試將三個(gè)部分分開,三個(gè)ViewModel來操作三個(gè)View里面的內(nèi)容,整個(gè)實(shí)現(xiàn)下來其實(shí)也有一些不足之處,那就是容易將問題復(fù)雜化,很多在一個(gè)類中就能夠完成的工作,最終要通過各種類與類之間的耦合來完成,所以通過這個(gè)DEMO希望自己能夠多一些思考,從而在軟件的設(shè)計(jì)中能夠再多一些經(jīng)驗(yàn),能夠把握好軟件粒度的問題,下面就軟件的具體內(nèi)容來深入分析一下。

      第一部分:FileList

  這個(gè)部分是整個(gè)文件和文件夾的顯示部分,再三權(quán)衡下,決定采用自定義DataGrid的方式來展現(xiàn)整個(gè)部分。       

<UserControl x:Class="FileSelectorDemo.Views.FileList"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:converter="clr-namespace:FileSelectorDemo.Converters"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:defines="clr-namespace:FileSelectorDemo.Defines"
             xmlns:local="clr-namespace:FileSelectorDemo.Views"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <converter:CountToVisibilityConverter x:Key="CountToVisibilityConverter"></converter:CountToVisibilityConverter>
        <converter:TypeToVisibleConverter x:Key="TypeToVisibleConverter"></converter:TypeToVisibleConverter>
        <converter:TypeToCollapsedConverter x:Key="TypeToCollapsedConverter"></converter:TypeToCollapsedConverter>
        <converter:CollectionSelectedCountConverter x:Key="CollectionSelectedCountConverter"></converter:CollectionSelectedCountConverter>      
    </UserControl.Resources>
    <Grid>     
        <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
            <Grid>
                <StackPanel Orientation="Vertical">
                    <DataGrid x:Name="fileList" Style="{StaticResource DefaultDataGrid}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" defines:MouseDoubleClick.Command="{Binding OpenCurrentDirectory}"
                              defines:MouseDoubleClick.CommandParameter="{Binding SelectedItem,RelativeSource={RelativeSource Self}}"  IsReadOnly="True"
                              defines:MouseLeftButtonUpClick.Command="{Binding SelectCurrentFileListItem}" ItemsSource="{Binding CurrentFileList}"  CanUserAddRows="False"  AutoGenerateColumns="False" GridLinesVisibility="None">
                        <DataGrid.Columns>
                            <DataGridTemplateColumn  MinWidth="60">
                                <DataGridTemplateColumn.Header>
                                    <CheckBox Content="全選" Margin="2" FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" IsChecked="{Binding DataContext.IsStateCheckAll,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type DataGrid}}}"></CheckBox>
                                </DataGridTemplateColumn.Header>
                                <DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <Grid HorizontalAlignment="Center" VerticalAlignment="Center">
                                            <TextBlock Text="不可選" FontSize="12" Foreground="Black" Visibility="{Binding CurrentType,Converter={StaticResource TypeToCollapsedConverter}}" HorizontalAlignment="Left" VerticalAlignment="Center" ></TextBlock>
                                            <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" IsThreeState="False" IsHitTestVisible="False" Visibility="{Binding CurrentType,Converter={StaticResource TypeToVisibleConverter}}"  HorizontalAlignment="Left" VerticalAlignment="Center" ToolTip="點(diǎn)擊選中當(dāng)前對(duì)象"></CheckBox>
                                        </Grid>
                                    </DataTemplate>
                                </DataGridTemplateColumn.CellTemplate>
                            </DataGridTemplateColumn>
                            <DataGridTemplateColumn Header="名稱" >
                                <DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
                                            <Image Source="{Binding Icon}" Margin="2"  HorizontalAlignment="Center" VerticalAlignment="Center"></Image>
                                            <TextBlock Text="{Binding Name}" Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
                                        </StackPanel>
                                    </DataTemplate>
                                </DataGridTemplateColumn.CellTemplate>
                            </DataGridTemplateColumn>
                            <DataGridTextColumn Header="修改日期"   Binding="{Binding CreateTime}"/>
                            <DataGridTextColumn Header="類型"   Binding="{Binding CurrentType}"/>
                            <DataGridTextColumn Header="大小"  Binding="{Binding Size}"/>
                        </DataGrid.Columns>
                    </DataGrid>
                    <TextBlock Margin="2 5" HorizontalAlignment="Left" VerticalAlignment="Center" >
                        <Run>總共 </Run>
                        <Run Text="{Binding CurrentFileList.Count,Mode=OneWay}"></Run>
                        <Run> 個(gè)項(xiàng)目</Run>
                        <Run>(已選中 </Run>
                        <Run Text="{Binding CurrentFileList,Converter={StaticResource CollectionSelectedCountConverter},Mode=OneWay}"></Run>
                        <Run> 個(gè)項(xiàng)目)</Run>
                    </TextBlock>
                </StackPanel>
                <TextBlock Text="該文件為空"  Visibility="{Binding CurrentFileList.Count,Converter={StaticResource CountToVisibilityConverter}}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
            </Grid>
        </ScrollViewer>         
    </Grid>
</UserControl>

  這里都是一些常規(guī)的定義,這里就不再贅述,DataGrid樣式是引用Themes文件夾下面的CustomDataGrid的樣式,這里面也包括自定義的ScrollViewer樣式和ScrollBar的樣式,讀者也可以進(jìn)行思考,另外需要注意設(shè)置下面的幾個(gè)屬性。

  1  IsReadOnly="True"這個(gè)屬性能夠保證在鼠標(biāo)點(diǎn)擊時(shí)候,不再顯示內(nèi)部的TextBox,從而使使用者不能夠隨意進(jìn)行編輯。

  2  GridLinesVisibility="None" 這個(gè)能夠使整個(gè)DataGrid不再顯示分割線,從而使其樣式更加接近Windows的原生樣式。

  3  CanUserAddRows="False" 這個(gè)屬性也非常重要,不然在整個(gè)顯示區(qū)域的下面會(huì)多出一行,當(dāng)用戶點(diǎn)擊它的時(shí)候會(huì)增加行。

  4  AutoGenerateColumns="False"這個(gè)就比較熟悉了,一般不讓其自動(dòng)增加列。

  5   SelectionUnit=“FullRow” 表示鼠標(biāo)點(diǎn)擊時(shí)選擇的單位是整行,而不是其中的單元格或者其他,關(guān)于其它的幾個(gè)枚舉值,讀者也可查閱相關(guān)了解。

  6   SelectionMode=“Extended”允許多選,當(dāng)按下鼠標(biāo)的Ctrl鍵進(jìn)行點(diǎn)擊的時(shí)候能夠選中多個(gè)對(duì)象。

  7   最后一個(gè)就是關(guān)于設(shè)置DataGrid的虛擬化容器了,具體設(shè)置方法是:

 <Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True"></Setter>
 <Setter Property="VirtualizingStackPanel.VirtualizationMode" Value="Recycling" />

  WPF中的VirtualizingStackPanel.VirtualizationMode 附加屬性指定 ItemsControl 中的面板如何虛擬化其子項(xiàng)。默認(rèn)情況下,VirtualizingStackPanel 將為每個(gè)可見項(xiàng)創(chuàng)建一個(gè)項(xiàng)容器,并在不再需要時(shí)(比如當(dāng)項(xiàng)滾動(dòng)到視圖之外時(shí))丟棄該容器。當(dāng) ItemsControl 包含多個(gè)項(xiàng)時(shí),創(chuàng)建和廢棄項(xiàng)容器的過程可能會(huì)對(duì)性能產(chǎn)生負(fù)面影響。如果 VirtualizingStackPanel.VirtualizationMode 設(shè)置為 Recycling,VirtualizingStackPanel 將重用項(xiàng)容器,而不是每次都創(chuàng)建新的項(xiàng)容器,這個(gè)是摘錄自MSDN的相關(guān)資料,由于我們加載的DataGrid的項(xiàng)不是很多,如果足夠多的情況下,效果可能會(huì)更加明顯,關(guān)于更多的“虛擬化”技術(shù)可以參考更多的資料。

  這里我們需要重點(diǎn)關(guān)注的是當(dāng)我們雙擊DataGridRow時(shí)會(huì)打開對(duì)應(yīng)的子文件夾,同時(shí)單擊時(shí)會(huì)選中當(dāng)前的DataGridRow,這里關(guān)于事件的綁定我們使用的不是System.Windows.Interactivity這種方式來綁定事件的,這里我們通過自定義一個(gè)附加屬性來實(shí)現(xiàn)的,這里以鼠標(biāo)左鍵雙擊為例來進(jìn)行說明。

  這里需要進(jìn)行說明的就是在OnMouseDoubleClick中,我們通過當(dāng)前鼠標(biāo)的點(diǎn)擊的Point來查找最終的DataGridRow 然后觸發(fā)綁定的Command事件,在前臺(tái)View中,我們只需要通過綁定到對(duì)應(yīng)的ICommand即可。

public class MouseDoubleClick
{
    public static DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached("Command",
        typeof(ICommand),
        typeof(MouseDoubleClick),
        new UIPropertyMetadata(CommandChanged));
 
    public static DependencyProperty CommandParameterProperty =
        DependencyProperty.RegisterAttached("CommandParameter",
                                            typeof(object),
                                            typeof(MouseDoubleClick),
                                            new UIPropertyMetadata(null));
 
    public static void SetCommand(DependencyObject target, ICommand value)
    {
        target.SetValue(CommandProperty, value);
    }
 
    public static void SetCommandParameter(DependencyObject target, object value)
    {
        target.SetValue(CommandParameterProperty, value);
    }
    public static object GetCommandParameter(DependencyObject target)
    {
        return target.GetValue(CommandParameterProperty);
    }
 
    private static void CommandChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        Control control = target as Control;
        if (control != null)
        {
            if ((e.NewValue != null) && (e.OldValue == null))
            {
                control.MouseDoubleClick += OnMouseDoubleClick;
            }
            else if ((e.NewValue == null) && (e.OldValue != null))
            {
                control.MouseDoubleClick -= OnMouseDoubleClick;
            }
        }
    }
 
    private static void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        DataGrid datagrid = sender as DataGrid;
        Point point = e.GetPosition(datagrid);
        IInputElement obj = datagrid.InputHitTest(point);
        DependencyObject target = obj as DependencyObject;
 
        while (target != null)
        {
            if (target is DataGridRow)
            {
                ICommand command = (ICommand)datagrid.GetValue(CommandProperty);
                object commandParameter = datagrid.GetValue(CommandParameterProperty);
                if (null != commandParameter)
                {
                    command.Execute(commandParameter);
                }
                break;
            }
            target = VisualTreeHelper.GetParent(target);
        }
    }
}  
defines:MouseDoubleClick.Command="{Binding OpenCurrentDirectory}"  defines:MouseDoubleClick.CommandParameter="{Binding SelectedItem,RelativeSource={RelativeSource Self}}"

  其中我們需要定義命名空間defines,這種方法為我們綁定View層中的各種事件提供能了一種新的方式,這個(gè)是我們需要不斷去總結(jié)和分析的地方。

  第二部分:Navigation

      這一部分是我們的導(dǎo)航欄的部分,通過向前、向后、向上等快捷操作,我們能夠快速切換文件夾,從而使切換路徑變得更加容易,這一部分就是需要著重說一下最近瀏覽項(xiàng)目這個(gè)功能,它能夠保存用戶最近瀏覽的10個(gè)目錄(開發(fā)者自定義),從而方便用戶迅速切換不同的路徑,這個(gè)是通過ToggleButton和Popup這一對(duì)經(jīng)典的組合來實(shí)現(xiàn)的,具體實(shí)現(xiàn)請(qǐng)參考源代碼。這一部分重點(diǎn)來說一下當(dāng)鼠標(biāo)移動(dòng)到不同的位置時(shí),能夠變換綁定的圖標(biāo)是向前還是向后抑或選中狀態(tài),這個(gè)其實(shí)是通過綁定每一個(gè)Model的一個(gè)CurrentDirection來實(shí)現(xiàn)的,這里需要重點(diǎn)掌握DataTrigger的使用方法。

<Popup Placement="Bottom" PlacementTarget="{Binding ElementName=NavigationPanel}" StaysOpen="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
               IsOpen="{Binding IsChecked,ElementName=History,Mode=OneWay}" PopupAnimation="Slide">
            <ItemsControl Background="#f5f5f5" BorderBrush="Gray" BorderThickness="1" Padding="0"
                          ItemsSource="{Binding AttachedDataContext.DirectoryHistory,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}}">
                <ItemsControl.Template>
                    <ControlTemplate TargetType="{x:Type ItemsControl}">
                        <Border x:Name="outer" Padding="0 2" Background="#f5f5f5">
                            <StackPanel Orientation="Vertical" IsItemsHost="True"></StackPanel>
                        </Border>                       
                    </ControlTemplate>
                </ItemsControl.Template>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Button x:Name="radioButton" Command="{Binding AttachedDataContext.SwitchDirectory,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}}"
                                CommandParameter="{Binding}">
                            <Button.Template>
                                <ControlTemplate TargetType="{x:Type Button}">
                                    <Border x:Name="bg" Padding="0" Background="#f5f5f5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                                        <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center">
                                            <Path x:Name="path" Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" Stroke="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"  Width="24" Height="24"
                                                  Opacity="0" StrokeThickness="2"  StrokeLineJoin="Round"  SnapsToDevicePixels="False">                                               
                                            </Path>                                        
                                            <Image Source="{Binding Icon}" Width="24" Height="24" Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center"></Image>
                                            <TextBlock Text="{Binding Name}" Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
                                        </StackPanel>
                                    </Border>
                                    <ControlTemplate.Triggers>
                                        <DataTrigger Binding="{Binding CurrentDirection}" Value="選中">
                                            <Setter Property="Opacity" Value="1" TargetName="path"></Setter>
                                            <Setter Property="Data" Value="M 2,10 L 8,14 18,6" TargetName="path"></Setter>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding CurrentDirection}" Value="向前">
                                            <Setter Property="Opacity" Value="0" TargetName="path"></Setter>
                                            <Setter Property="Data" Value="M8,6 L1,11 8,16 M0,11 L15,11" TargetName="path"></Setter>
                                        </DataTrigger>
                                        <DataTrigger Binding="{Binding CurrentDirection}" Value="向后">
                                            <Setter Property="Opacity" Value="0" TargetName="path"></Setter>
                                            <Setter Property="Data" Value="M8,6 L15,11 8,16 M0,11 L15,11" TargetName="path"></Setter>
                                        </DataTrigger>
                                        <Trigger Property="IsMouseOver" Value="true">
                                            <Setter Property="Background" Value="#91c9f7" TargetName="bg"></Setter>
                                            <Setter Property="Opacity" Value="1" TargetName="path"></Setter>
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Button.Template> 
                        </Button>                                     
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </Popup>

   第三部分:BreadCrumbView

   這個(gè)部分是用來顯示當(dāng)前文件夾路徑,并進(jìn)行快速切換準(zhǔn)備的,這個(gè)部分是一個(gè)組合控件,主要是通過ItemsControl和ToggleButton和Popup來實(shí)現(xiàn)的,這個(gè)里面需要注意的是這里面綁定的命令和方法都是在FileList的ViewModel中定義的,這里為了最大程度的實(shí)現(xiàn)代碼的重用。很多時(shí)候我們會(huì)發(fā)現(xiàn)通過這種方式我們需要能夠隨時(shí)訪問到FileListViewModel中的內(nèi)容,這個(gè)是整個(gè)DEMO中最重要的部分,所以如何才能夠引用到FileListViewModel里面的內(nèi)容呢?

public partial class BreadCrumbView : UserControl
    {
        public BreadCrumbView()
        {
            InitializeComponent();
            Loaded +=new RoutedEventHandler(BreadCrumbView_Loaded);
        }
 
        private void BreadCrumbView_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = new ViewModels.BreadCrumbViewModel(AttachedDataContext);
        }
 
        /// <summary>
        /// 當(dāng)前FileList的DataContext對(duì)象
        /// </summary>
        public object AttachedDataContext
        {
            get { return (object)GetValue(AttachedDataContextProperty); }
            set { SetValue(AttachedDataContextProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty AttachedDataContextProperty =
            DependencyProperty.Register("AttachedDataContext", typeof(object), typeof(BreadCrumbView), new PropertyMetadata(null));
    }

    通過定義一個(gè)AttachedDataContext對(duì)象,我們能夠?qū)ileListViewModel中定義的屬性分散到各個(gè)ViewModel中,這樣在一定程度上能夠保證避免FileListViewModel中代碼過多同時(shí)職責(zé)過重的問題,但是同時(shí)我們也發(fā)現(xiàn)了,如果彼此之間的耦合過大,采用這種方式會(huì)加重代碼之間的復(fù)雜度,因?yàn)橛袝r(shí)不得不通過Action或者事件等方式來進(jìn)行ViewModel之間的交互和通訊,所以降到這里我們不得不說一些較大較復(fù)雜的項(xiàng)目中使用框架的重要性了,比如Prism亦或是Caliburn.Micro等框架能夠使整個(gè)軟甲架構(gòu)看起來更加清楚和明白,這也是為了更好地增加軟件的模塊化和靈活性。

   通過這個(gè)DEMO的分析,我們需要在不斷的實(shí)踐中去總結(jié)這類型的經(jīng)驗(yàn),從而使整個(gè)軟件顯得更加合理,最終使自己能夠真正地對(duì)軟件的架構(gòu)的思想有一個(gè)比較深入的了解。

       最后需要整個(gè)Demo的請(qǐng)點(diǎn)擊此處進(jìn)行下載!

以上就是c# WPF實(shí)現(xiàn)Windows資源管理器(附源碼)的詳細(xì)內(nèi)容,更多關(guān)于c# WPF實(shí)現(xiàn)Windows資源管理器的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論