WPF開發為按鈕提供添加,刪除和重新排列ListBox內容的功能

来源:https://www.cnblogs.com/langda/archive/2019/03/04/10473467.html
-Advertisement-
Play Games

介紹 我有一種情況,我希望能夠將項目添加到列表中,併在列表中移動項目,這似乎是使用a的最簡單方法ListBox。我立刻想到瞭如何以通用的方式做到這一點,然後,也許,可以使用行為來做到這一點。這似乎是一個非常有用的想法。我決定以一種簡單的方式為我正在開發的應用程式做這件事,但我想我會創建一個演示項目來 ...


介紹

我有一種情況,我希望能夠將項目添加到列表中,併在列表中移動項目,這似乎是使用a的最簡單方法ListBox我立刻想到瞭如何以通用的方式做到這一點,然後,也許,可以使用行為來做到這一點。這似乎是一個非常有用的想法。我決定以一種簡單的方式為我正在開發的應用程式做這件事,但我想我會創建一個演示項目來探索這個想法。這是結果。

概觀

該行為實際上有四個獨立的部分,可以在一個類中執行不同的功能:

  • 添加項目
  • 將所選項目向上移動一個位置
  • 將所選項目向下移動一個位置
  • 刪除所選項目。

每個函數的代碼結構非常相似,只有一些細節不同。

將要檢查的代碼是Move Up函數的代碼

首先是以下定義DependencyProperty

隱藏   複製代碼
public static readonly DependencyProperty MoveItemUpProperty =
    DependencyProperty.RegisterAttached("MoveItemUp",
        typeof(Selector), typeof(ListHelperBehavior),
            new PropertyMetadata(null, OnMoveItemUpChanged));

public static Selector GetMoveItemUp(UIElement uiElement)
{ return (Selector)uiElement.GetValue(MoveItemUpProperty); }

public static void SetMoveItemUp(UIElement uiElement, Selector value)
{ uiElement.SetValue(MoveItemUpProperty, value); }

這用於為包含列表Selector(或ListBox)控制項提供綁定它用於Button執行動作,在這種情況下是將所選項目向上移動一個位置。對於這個動作的代碼需要有機會獲得ItemsSourceSelectedIndexSelector控制,首先要真正能夠做到移動,第二知道要移動的項目。

對於所有操作,此代碼幾乎相同,只是Add Item不需要監視SelectionChanged事件Selector,並且Button永遠不會禁用。

當此DependencyProperty更改時,將OnMoveUpItemChanged執行事件處理程式此事件處理程式在DependencyPropertyRegisterAttached方法的FrameworkMetadata參數中指定

隱藏   複製代碼
private static void OnMoveItemUpChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    if (e.OldValue is Selector Selector1)
    {
        Selector1.SelectionChanged -= SetMoveItemUpButtonIsEnabled;
    }
    if (e.NewValue is Selector Selector)
    {
        var Button = CheckForButtonBase(d);
        Button.Click -= MoveItemUpEvent;
        Button.Click += MoveItemUpEvent;
        Selector.SetValue(MoveUpButton, Button);
        Selector.SelectionChanged += SetMoveItemUpButtonIsEnabled;
        SetMoveItemUpButtonIsEnabled(Selector, null);
    }
}

此代碼將事件處理程式附加到ButtonClick事件和Selector SelectionChanged事件。為了確保Button在訂閱事件之前沒有雙重訂閱Click事件,並且刪除SelectionChanged事件的事件處理程式Selector(如果存在)。此外,Button它保存在附件DependencyProperty中,Selector以便可以找到它以供SelectionChanged事件處理程式使用最後,Button通過使用SelectionChanged事件處理程式調整IsEnabled值

為的保存代碼ButtonSelector被下麵的私人DependencyProperty從而使Button被啟用和禁用,可以發現:

隱藏   複製代碼
private static readonly DependencyProperty MoveUpButton =
    DependencyProperty.RegisterAttached("MoveUpButton",
        typeof(ButtonBase), typeof(ListHelperBehavior),
            new PropertyMetadata(null));

Add Item代碼不需要監視SelectionChanged事件,因為Button從不禁用它。
的Click事件Button下移功能如下:

隱藏   複製代碼
private static void MoveItemUpEvent(object sender, RoutedEventArgs e)
{
    Debug.Assert(sender is ButtonBase);
    var Button = (ButtonBase)sender;
    var Selector = GetMoveItemUp(Button);
    var IList = CheckForIList(Selector);
    var itemNumber = Selector.SelectedIndex;
    var item = IList[itemNumber];
    IList.RemoveAt(itemNumber);
    var type = IList.GetType().GetGenericArguments().Single();
    var castInstance = Convert.ChangeType(item, type);
    IList.Insert(itemNumber - 1, castInstance);
    if (itemNumber == 1) Button.IsEnabled = false;
    Selector.SelectedIndex = itemNumber - 1;
}

sender參數必須強制轉換為ButtonBase類型,然後用於獲取Selector作為ButtonBase中附加屬性保存控制項的值然後使用它來獲取IList綁定到Selector ItemsSource DependencyPropertySelectedItemSelectorIList然後複製所選項目,轉換為正確的類型(使用Type類的Reflection GetGenericArgument方法獲取類型,然後使用Convert.ChangeType方法將其強制轉換),然後從IList(RemoveAt方法)中刪除IList)。然後使用該Selector Insert方法插入刪除的項目

接下來檢查是否現在是第一個項目,禁用Button它是否為,並且Selector SelectedIndex設置為仍然指向同一個項目。

碼幾乎是相同的,則刪除要簡單得多,因為它沒有保存已刪除的項目,然後將其放回IList

最後,有適當的代碼啟用或禁用Button取決於是否存在SelectedItemSelectedItem是第一個(用於上)或最後一個項目IList(用於下移)。這是SelectedItemSelector觸發事件時調用的事件處理程式

隱藏   複製代碼
private static void SetMoveItemUpButtonIsEnabled(object sender, RoutedEventArgs e)
 {
 <code>    Debug.Assert(sender is Selector);
     var Selector = (Selector)sender;
     var IList = CheckForIList(Selector);
     var itemNumber = Selector.SelectedIndex;
     var Button = (ButtonBase) Selector.GetValue(MoveUpButton);
     Button.IsEnabled = (itemNumber >= 1 && itemNumber < IList.Count);
 }</code>

對於這種需要IList綁定到ItemsSourceSelectedIndex,並需要得到Button保存為一個附加屬性在此功能Selector對於Remove函數,只需要知道if SelectedIndex是否等於-1,這樣簡單得多。

使用行為

要使用此行為,只需要一個從Selector控制項派生的列表控制項,Name為此控制項關聯一個值,並Button為每個應該實現的函數定義一個網站源碼。在每一個Button XAML只包括ListHelperBahaviorDependencyProperty它有關聯BindingSelector

隱藏   收縮 WPF行為的圖像1為按鈕提供了添加,刪除和重新排列ListBox內容的功能   複製代碼
<Grid Margin="10">
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ListBox Name="TheList"
             ItemsSource="{Binding List}"
             HorizontalAlignment="Stretch"
             VerticalAlignment="Stretch"  >
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="30"/>
                        <ColumnDefinition Width="200"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding ItemNumber}"/>
                    <TextBlock Grid.Column="1"
                               Text="{Binding TimeCreated}"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <StackPanel Grid.Row="2"
                Margin="-5 5"
                Orientation="Horizontal"
                HorizontalAlignment="Right">
        <Button Content="Add"
                Width="70"
                Margin="5"
                local:ListHelperBehavior.AddToList="{Binding ElementName=TheList}"/>
        <Button Content="Remove"
                Width="70"
                Margin="5"
                local:ListHelperBehavior.RemoveFromList="{Binding ElementName=TheList}"/>
        <Button Content="Move Up"
                Width="70"
                Margin="5"
                local:ListHelperBehavior.MoveItemUp="{Binding ElementName=TheList}"/>
        <Button Content="Move Down"
                Width="70"
                Margin="5"
         local:ListHelperBehavior.MoveItemDown="{Binding ElementName=TheList}"/>
    </StackPanel>

WPF行為的圖像2為按鈕提供了添加,刪除和重新排列ListBox內容的功能

問題

行為存在一些限制,其中一些可以使用其他代碼進行處理。
其中一個問題是行為預期綁定到該類型Selector的類型的IList,這意味著這兩個ListObservableCollection可使用,但Array Type不能。這可以編碼,但需要Array每次重新創建

另一個限制是Add只有Type在它IList是一個類時才有效,並且有一個預設的構造函數。

當然另一個限制是它只處理從控制項派生的Selector控制項。

結論

這是一個非常好的小行為,因為它允許更改列表的順序,並通過僅將行為添加Button到實現該功能的每個項目來添加或刪除項目ViewModel中無需任何操作即可提供此功能。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前面介紹了集合與映射兩類容器,它們的共同特點是每個元素都是唯一的,並且採用二叉樹方式的類型還自帶有序性。然而這兩個特點也存在弊端:其一,為啥內部元素必須是唯一的呢?像手機店賣出了兩部Mate20,雖然這兩部手機一模一樣,但理應保存兩條銷售記錄才是。其二,不管是哈希類型還是二叉類型,居然都不允許按照加 ...
  • 【路徑】 絕對路徑:從根目錄開始鏈接的路徑 >cd C:\Windows\Boot\DVD\EFI\en-US 相對路徑:不從根目錄開始鏈接的路徑 > cd Boot\DVD\EFI\en-US Python的文件名是以 .py 結尾的 dir是查看當前目錄下的文件cd 路徑 跳轉到指定路徑cd . ...
  • 作者:石杉的架構筆記 寫在前面 春節長假轉眼已過,即將迎來的是一年一度的金三銀四跳槽季。 假如你準備在金三銀四跳槽的話,那麼作為一個Java工程師,應該如何利用1個月的時間,快速的為即將到來的面試進行充分的準備呢? 這兩篇文章,專門站在面試官的角度,給大家分析了平時互聯網公司是如何全方位的考察一個候 ...
  • 1.如果子進程先於父進程退出, 同時父進程又沒有調用wait/waitpid,則該子進程將成為僵屍進程 2.如果fork完就不管了可以使用 忽略子進程信號, 防止僵屍進程 pcntl_signal(SIGCLD, SIG_IGN); 3.如果在主進程中,可以等待子進程的退出 , 這樣也能防止出現僵屍 ...
  • 1、背景:接手公司新項目時,無論用vs2013還是用vs2017都打開不了 2、解決辦法:先把.suo文件刪掉, 結果:vs2013可以打開,vs2017依舊打不開。 3、繼續解決:上網搜了一下,把隱藏的.vs文件夾刪除 結果:完美解決 4、到底與哪一個步驟有關呢?經測試(只刪除.vs文件夾又測試了 ...
  • 通過調用指定目錄下的所有模板,逐一按照數據表生成獨立的代碼文件。支持多模板調用、支持所有數據表生成或批量指定多個生成、支持自動的文件目錄結構、支持代碼文件格式化命名等。 背景:最近一個新項目一高興選了Mysql 8,結果出了好幾個麻煩。 Toad for mysql 連不上了,習慣的動軟代碼生成器也 ...
  • 耗時兩個多月,堅持寫這個入門系列文章,就是想給後來者更好更快的上手體驗,這個系列可以說是從入門到進階,適合沒有 .NETCore 編程經驗到小白同學,也適合從 .NET Framework 遷移到 .NETCore 的朋友。 ...
  • 索引: 目錄索引 一.API 列表 C# 代碼中 介面 IList.Contains() 方法生成 SQL 對應的 in(val1,val2,... ...) 如:.Queryer<Agent>() ... ... .Where(it => new AgentLevel?[] { AgentLeve ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...