WPF中ItemContainerStyle不適用的一種情況

來源:互聯網
上載者:User

WPF中的ItemsControl定義了ItemContainerStyle這一屬性,顧名思義,該屬性用來給ItemsControl中包含的每一個Item的容器定義樣式。

比如在ListBox中這個容器就是ListBoxItem,在TabControl中這個容器就是TabItem。

下面是ItemContainerStyle的一種簡單應用:

XAML:

 

<Window ......>    <StackPanel>        <ListBox Name="itemsControl" ItemsSource="{Binding}">            <ListBox.ItemContainerStyle>                <Style TargetType="ListBoxItem">                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=OneTime}"/>                </Style>            </ListBox.ItemContainerStyle>            <ListBox.ItemTemplate>                <DataTemplate>                    <TextBlock Text="{Binding Text}"/>                </DataTemplate>            </ListBox.ItemTemplate>        </ListBox>    </StackPanel></Window>

 

在這段XAML中定義了一個ListBox,在其ItemTemplate中有一個TextBlock綁定到資料實體的Text屬性上。在其ItemContainerStyle中將其每個Item的IsSelected屬性綁定到資料實體的IsSelected上。其資料實體的產生在下面的代碼中:

public partial class ComboBoxTest : Window    {        public ComboBoxTest()        {            InitializeComponent();            itemsControl.DataContext = GetData();        }        private object GetData()        {            Collection<object> data = new Collection<object>();            for (int i = 1; i <= 10; i++)            {                data.Add(new { Text = i.ToString(), IsSelected = i == 5 });            }            return data;        }    }

為了簡單,沒有單獨定義實體類而是用了匿名對象。一共產生十個匿名實體,把其中第五個的IsSelected設定為true,把這十個實體放入一個Collection中賦值給控制項的DataContext,這樣XAML中對ItemsSource的綁定(ItemsSource="{Binding}")就會起效。當然,直接把這個Collection賦值給ItemsSource也可以。

運行一下,結果和預期的一樣,第五項被選中了。

試試把XAML中的ListBox換成TabControl,更換之後的XAML如下:

<Window ......>    <StackPanel>        <TabControl Name="itemsControl" ItemsSource="{Binding}">            <TabControl.ItemContainerStyle>                <Style TargetType="TabItem">                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=OneTime}"/>                </Style>            </TabControl.ItemContainerStyle>            <TabControl.ItemTemplate>                <DataTemplate>                    <TextBlock Text="{Binding Text}"/>                </DataTemplate>            </TabControl.ItemTemplate>        </TabControl>    </StackPanel></Window>

僅僅是把ListBox換成了TabControl,把ListBoxItem換成了TabItem而已,C#代碼沒有改。試著運行一下,結果還是和預期的一樣,第五項會被選中。

ListBox和TabControl都是間接繼承自ItemsControl而直接繼承自Selector的,那是不是所有Selector的子類都會有如上的行為呢?

實際上不是,把Selector的另一個子類ComboBox拿出來試試。

仍然是只改XAML,不改C#代碼,改完之後的XAML如下:

<Window ......>    <StackPanel>        <ComboBox Name="itemsControl" ItemsSource="{Binding}">            <ComboBox.ItemContainerStyle>                <Style TargetType="ComboBoxItem">                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=OneTime}"/>                </Style>            </ComboBox.ItemContainerStyle>            <ComboBox.ItemTemplate>                <DataTemplate>                    <TextBlock Text="{Binding Text}"/>                </DataTemplate>            </ComboBox.ItemTemplate>        </ComboBox>    </StackPanel></Window>

運行之後的效果如下:

可見啟動後沒有任何選中項。而只有當用滑鼠將ComboBox展開時第五項才會被選中。對這種現象,我的猜測是因為ItemContainerStyle只有在所有Item載入之後才會開始應用,而ComboBox預設情況下並不會把其Items展示出來,所以直到用滑鼠將ComboBox展開時才會有選中效果。

對這種情況有一個不太完美的解決方案,把C#代碼中的GetData方法修改如下:

private object GetData()        {            Collection<object> data = new Collection<object>();            for (int i = 1; i <= 10; i++)            {                data.Add(new { Text = i.ToString() });            }            return new { Data = data, SelectedData = data[4] };        }

上面的代碼中再次應用了匿名對象,把整個實體集合賦值給新的匿名對象中的Data屬性,並把集合的第五項賦值給新的匿名對象的SelectedData屬性。這樣GetData方法的傳回值--也就是這個新的匿名對象就會被賦值到控制項的DataContext上去。

然後修改XAML,把ComboBox的ItemsSource綁定到匿名對象的Data屬性,把SelectedValue綁定到匿名對象的SelectedData屬性。修改後的XAML如下:

<Window ......>    <StackPanel>        <ComboBox Name="itemsControl" ItemsSource="{Binding Data}" SelectedValue="{Binding SelectedData, Mode=OneTime}">            <ComboBox.ItemTemplate>                <DataTemplate>                    <TextBlock Text="{Binding Text}"/>                </DataTemplate>            </ComboBox.ItemTemplate>        </ComboBox>    </StackPanel></Window>

這次直接綁定SelectedValue,就不用像使用Style一樣等到Item載入之後才會生效了。

再運行,啟動效果如下:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.