WPF Как разрешить всем элементам treeview иметь одинаковое поле со списком, связанное с каждым элементом

#c# #wpf #mvvm #combobox #treeview

#c# #wpf #mvvm #поле со списком #просмотр дерева

Вопрос:

Я столкнулся с проблемой в отношении моего приложения WPF, чего я в идеале пытаюсь достичь здесь, чтобы в treeview с дочерними элементами рядом с каждым элементом было поле со списком, а в этом поле со списком было 3 текстовых значения. Например

ParentItem1 Выпадающий список с 3 элементами ChildItem1 Выпадающий список с 3 элементами ChildItem2 Выпадающий список с 3 элементами ParentItem2 Выпадающий список с 3 элементами ChildItem1 Выпадающий список с 3 элементами ChildItem2 Выпадающий список с 3 элементами ChildItem3 Выпадающий список с 3 элементами

К счастью, я дошел до того, что перечислил некоторые фиктивные данные для treeview и представил поле со списком, но, к сожалению, 3 значения не отображаются. здесь я использую шаблон MVVM, где я привязываю свои данные к viewmodel и наоборот. вот код, который у меня есть на данный момент:

Код Xaml:

 <Grid.Resources>
    <HierarchicalDataTemplate x:Key="servicesKey" DataType="{x:Type src:Service}" ItemsSource="{Binding Path=Children}">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="{Binding Path=Name}" Margin="5,10,0,0" />
            <ComboBox Name="cmbStatusList" 
                      ItemsSource="{Binding StateList}"
                      IsTextSearchEnabled="True"
                      SelectionChanged="cmb_SelectionChanged"
                      DisplayMemberPath="State"
                      IsEditable="True"
                      IsReadOnly="True"
                      SelectedValuePath="StateID"
                      Width="150" 
                      Margin="20,0,0,0">
            <ComboBox.SelectedValue>
                <Binding Path="NewIncident.StateID" Mode="TwoWay" UpdateSourceTrigger="Explicit">
                    <Binding.ValidationRules>
                        <validation:ComboBoxRules />
                    </Binding.ValidationRules>
                </Binding>
            </ComboBox.SelectedValue>
            </ComboBox>
        </StackPanel>
    </HierarchicalDataTemplate>
</Grid.Resources>

<TreeView Name="treeServices"
          ContextMenuOpening="ContextMenu_ContextMenuOpening"
          ItemsSource="{Binding ServiceModel.Services}"
          ItemTemplate="{StaticResource servicesKey}"
          VirtualizingPanel.IsVirtualizing="True"
          Margin="0,0,10,10">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}"  BasedOn="{StaticResource {x:Type TreeViewItem}}"/>
    </TreeView.ItemContainerStyle>
</TreeView>
  

Представление сервиса-модель

 public class ServiceViewModel : ViewModelBase
{
    private List<Service> _services;
    public ServiceViewModel()
    {
        _services = new List<Service>();
    }

    public List<Service> Services
    {
        get { return _services; }
        set { _services = value; OnPropertyChanged("Services"); }
    }

    public override void OnChange()
    {
        throw new NotImplementedException();
    }
}
public class Service : INotifyPropertyChanged
{
    public Service(Service parent = null)
    {
        Children = new List<Service>();
    }
    public Guid Guid { get; set; }
    public string Name { get; set; }
    public List<Service> Children { get; set; }
    public string State { get; set; }
    public ServiceState StateID { get; set; }

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}
  

Модель

     var statesmodel = _oakStatusProvider.GetServiceState()
        .Select(p => new Service()
        {
            StateID = p.StateID,
            State = p.State
        });

        _incidentViewModel.StateList = new List<Service>(statesmodel);
this.DataContext = _incidentViewModel;
  

Получить метод обслуживания

 public List<ServiceDTO> GetServiceState()
{
    List<ServiceDTO> servicestatelist = new List<ServiceDTO>
    {
        new ServiceDTO { StateID = ServiceState.Normal, State = "Normal" },
        new ServiceDTO { StateID = ServiceState.Degraded, State = "Degraded" },
        new ServiceDTO { StateID = ServiceState.Critical, State = "Critical" },
    };
    return servicestatelist;
}
  

Состояния, которые будут использоваться в CMBbox

 public enum ServiceState
    {
        Normal = 0,
        Degraded = 10,
        Critical = 20,
    }
  

Результат:
Результирующее поле со списком с treeview

Привязка непосредственно к полю со списком работает нормально, кажется, что DataTemplete все портит?

                                     <ComboBox Name="cmbSstatusList" 
                                  ItemsSource="{Binding StateList}"
                                  IsTextSearchEnabled="True"
                                  SelectionChanged="cmb_SelectionChanged"
                                  DisplayMemberPath="State"
                                  IsEditable="True"
                                  IsReadOnly="True"
                                  SelectedValuePath="StateID"
                                  materialDesign:HintAssist.Hint="State" 
                                  Style="{StaticResource MaterialDesignFloatingHintComboBox}" 
                                  Width="150" 
                                  Height="45" 
                                  FontSize="15" >
                            <ComboBox.SelectedValue>
                                <Binding Path="NewIncident.StateID" Mode="TwoWay" UpdateSourceTrigger="Explicit">
                                    <Binding.ValidationRules>
                                        <validation:ComboBoxRules />
                                    </Binding.ValidationRules>
                                </Binding>
                            </ComboBox.SelectedValue>
                        </ComboBox>
  

Результат:

Рабочий CMB

Заранее спасибо за любую помощь :). по любым вопросам, пожалуйста, дайте мне знать.

Ответ №1:

Выпадающий элемент управления не получает свойство StateList.

Вам нужно назвать Window screen, а затем выполнить привязку элемента, чтобы заставить работать привязку списка состояний для раскрывающегося элемента управления.

 <Window x:Class="WpfApp11.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp11"
        mc:Ignorable="d" x:Name="Window1"
        Title="MainWindow" Height="450" Width="800">
  

А для управления полем Combox используйте ElementBinding для привязки списка.

  <ComboBox Name="cmbStatusList" 
                      ItemsSource="{Binding ElementName=Window1, Path=DataContext.StateList}"
                      IsTextSearchEnabled="True"
                      DisplayMemberPath="State"
                      IsEditable="True"
                      IsReadOnly="True"
                      SelectedValuePath="StateID"
                      Width="150" 
                      Margin="20,0,0,0">
                </ComboBox>
  

Комментарии:

1. @S.Leu Ознакомьтесь с решением, дайте мне знать, оно подходит для вас?

2. Спасибо, Сатиш, странно, что, поскольку я предполагал, что поле со списком будет работать так же, как если бы оно было само по себе, похоже, с этим разобрались. Еще раз спасибо 🙂

3. Приветствия, рад, что смог вам помочь.