本文通過 WPF 的數據觸發器 (DataTrigger) 和多重綁定 (MultiBinding),在一組普通按鈕 (Button) 上實現了像單選按鈕 (RadioButton) 那樣的,同一時間只有一個按鈕具有當前樣式(本文演示的是背景顏色)的效果。 ...
WPF 讓一組 Button 實現 RadioButton 的當前樣式效果
概述:本文通過 WPF 的數據觸發器 (DataTrigger) 和多重綁定 (MultiBinding),在一組普通按鈕 (Button) 上實現了像單選按鈕 (RadioButton) 那樣的,同一時間只有一個按鈕具有當前樣式(本文演示的是背景顏色)的效果。
需求起因:公司項目中有個 WPF 項目,有個界面下方有一塊顯示當前信息的區域,並且有幾個按鈕,意圖是點擊之後可以切換為另一區域的信息。由於到目前為止,業務中都還只有一個區域,所以之前同事就沒寫這切換的邏輯。經過本人的不懈努力,切換邏輯寫好了,就差切換後按鈕樣式的轉移了,如下圖。
這種需求本來最好是直接使用 RadioButton,然後更改顯示模板的。由於內部還有其它邏輯,改起來也沒有那麼輕鬆,加上之前觸發器用得比較少,多重綁定也沒怎麼用過,正好可以藉此機會練練手,所以就還是基於普通按鈕來實現這個需求。
首先給出幾個按鈕的代碼:
<Button Command="{Binding CommandEntranceSwitch}" CommandParameter="1" Tag="{Binding LeftEntranceSelected.Tag}" Style="{DynamicResource RadioStyleButton}"/> <Button Command="{Binding CommandEntranceSwitch}" CommandParameter="2" Tag="{Binding LeftEntranceSelected.Tag}" Style="{DynamicResource RadioStyleButton}"/> <Button Command="{Binding CommandEntranceSwitch}" CommandParameter="3" Tag="{Binding LeftEntranceSelected.Tag}" Style="{StaticResource BorderStyleButton}"/>
Command 綁定了按鈕的命令,用於切換當前需要顯示的數據(即後面的 LeftEntranceSelected ),命令的代碼與本文關係不大,就不展示了;
CommandParameter 是命令的參數,也就是作為區分按鈕的編號;
Tag 綁定了當前選中信息的 Tag 屬性,用於與按鈕編號進行比較,三個按鈕的 Tag 值是一樣的;
Style 就是本次添加了觸發器的樣式,可以看到第三個按鈕還是原來的樣式,這是我故意給出的錯誤示範,因為之前忘了元素上的樣式優先順序更高,以為外面的 Style 指定了 TargetType 就行,這裡也給大家提個醒。還有一個坑就是,要使用 DynamicResource,不能使用 StaticResource,不然沒有反應。
然後就是本次新增的樣式(樣式里有數據觸發器,觸發器里有多重綁定):
<Grid.Resources> <Style TargetType="Button" BasedOn="{StaticResource BorderStyleButton}" x:Key="RadioStyleButton"> <Style.Triggers> <DataTrigger Value="true"> <DataTrigger.Binding> <MultiBinding Converter="{StaticResource EqualConverter}"> <Binding RelativeSource="{RelativeSource Self}" Path="Tag"></Binding> <Binding RelativeSource="{RelativeSource Self}" Path="CommandParameter"></Binding> </MultiBinding> </DataTrigger.Binding> <Setter Property="Background" Value="#4BEF9E"/> </DataTrigger> </Style.Triggers> </Style> </Grid.Resources>
可以看到,此樣式目標為 Button,基於原樣式 BorderStyleButton,取名為 RadioStyleButton。DataTriggers 的 Value 設為 true,表明 Binding 中計算的值為 true 時,設置 Setter 中指定的樣式(此處為背景色)。那麼關鍵就是 Binding 中如何計算了。
此處使用了多重綁定(MultiBinding),綁定了每個應用了該樣式的 Button 元素上的 Tag 和 CommandParameter,因為每個 Button 自己的 CommandParameter 是確定的,而 Tag 隨著選中項變化,當兩者相等,說明自己被選中了,隨即被設置上當前樣式。
那麼怎麼判斷兩者是否相等呢?答案就是使用 MultiBinding 的轉換器(Converter)EqualConverter:
<converters:EqualConverter x:Key="EqualConverter"></converters:EqualConverter>
轉換器代碼為:
/// <summary> /// [dlgcy]相等比較器(判斷給定的數據的字元串形式是否都相等) /// </summary> public class EqualConverter:IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values == null || values.Length == 0) throw new ArgumentNullException(nameof(values), "values can not be null or empty"); return values.All(x => x+"" == values[0]+""); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { return null; } }
最終效果為:
希望大家多多討論,不吝賜教。
同步首發:
http://dlgcy.com/wpf-button-as-radiobutton/