There are several grids. All of them are hidden until ComboBox is selected in the ComboBoxItem . When I select one of the ComboBoxItem one of the grids should appear accordingly. I try to make a binding in XAML without twisting the model:

  <Grid x:Name="Cash" Visibility="{Binding ElementName=cmb_Security, Path=SelectedValue.Cash}" > 

Cash is an Item in a combobox but the grid itself is visible regardless of whether something is selected in boxing at all. How to fix this markup extension?

  • Visibility must have the appropriate values Visible , Hidden or Collapsed ( msdn ). You are not clear what they bind at all ... - MihailPw
  • The Visibility property has one type, SelectedValue.Cash has another type. Need to add a converter. - Artem Nikolaevich
  • @ AGS17 without twisting the model can not do? - Sergey
  • Only if the converter. - MihailPw
  • one
    @ Sergey, the converter is part of View, not VM, if you are about it;) - Andrey NOP

2 answers 2

Usually this problem is solved as follows.

  1. You have a collection of VM objects, each of which contains data for its own grid and combo box string.
  2. You bind this collection to the Combobox ItemsSource , set the DisplayMemberPath to what should be displayed in the combobox.
  3. To show a grid, you use Binding if all grids are the same and differ only in data. Or ContentPresenter and DataTemplate ' set, if they are different.

Example:

VM class:

 class ItemVM { public string Header { get; } public string Content { get; } public ItemVM(string header, string сontent) { Header = header; Content = Content; } } 

Well, a collection wrapper:

 class MainVM { public IEnumerable<ItemVM> Items { get; private set; } public ItemVM SelectedItem { get; set; } // ещё нужен конструктор } 

XAML (I’m showing a simple case here, with the same grid layout):

 <DockPanel LastChildFill="True"> <ComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" DisplayMemberPath="Header" IsSynchronizedWithCurrentItem="True" DockPanel.Dock="Top" /> <Grid DataContext="{Binding Items/}" Margin="10"> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Header}" FontWeight="Bold" Margin="0,5"/> <TextBlock Text="{Binding Content}"/> </StackPanel> </Grid> </DockPanel> 

Result:

testiki, whom testiki, fly


Note that SelectedItem="{Binding SelectedItem}" only needed to make the initial value in the combo box empty. This value is no longer used in the code (although you may need it somewhere else in the VM).

  • VladD, why not an option with Visibility ? If the Grid contained more different elements, the proposed solution would no longer work. - sp7
  • @ sp7 why wouldn't it work? This is a standard solution, only ContentControl is used instead of Grid - look at the link to the blog that you provided in your answer. The option with Visibility in this case, in my opinion, does not fit well, since it is absolutely not flexible. In other words, all controls will be described in one file. Imagine how difficult it will be to work with him. The navigation option makes it very easy to add / delete pages and the code is clearly divided “by section” - user227049
  • By the way, in the line Grid DataContext="{Binding Items/}" is not a typo accidentally, should there not be a Grid DataContext="{Binding SelectedItem}" ? - sp7
  • 2
    @ sp7 notice IsSynchronizedWithCurrentItem="True" - user227049
  • Did not quite understand how it works. MSDN says that Установка свойства IsSynchronizedWithCurrentItem="True" гарантирует, что выбранный элемент всегда задается как свойство CurrentItem . Actually, it is not clear what the CurrentItem where does it CurrentItem from then, in general, and why do items from the StackPanel view the data in it? - sp7

In my question in my opinion contain two separate.

The first is how to display an item only if there is a selected item. This problem can be solved by using a trigger to check that SelectedIndex ! = -1 . The simplest example is:

 <Grid HorizontalAlignment="Center"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <ComboBox Name="some" Grid.Row="0" Margin="10" MinWidth="120" ItemsSource="{Binding Data}" /> <TextBlock Grid.Row="1" Text="{Binding Path=SelectedItem, ElementName=some}" Margin="10"> <TextBlock.Style> <Style> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=some, Path=SelectedIndex}" Value="-1"> <Setter Property="TextBlock.Visibility" Value="Collapsed" /> </DataTrigger> </Style.Triggers> </Style> </TextBlock.Style> </TextBlock> </Grid> 

For completeness, I give a trivial context for the data.

 module Context2 = open Gjallarhorn.Bindable let create() = let source = Binding.createSource() [|"Some1"; "Some2" ; "Some3" |] |> Binding.constantToView "Data" <| source source 

The second - as depending on the selected item in the list to display the relevant data. In short - you create a list of "paged" VMs and link it to your ComboBox . You can directly display the selected item in ContentControl through a binding to SelectedItem or get a property in the main VM which will be responsible for the selected VM .

There is a great article Navigation with MVVM on this subject, where you can read about this approach in more detail, and also look at the implementation of a simple example.