Как установить ItemSource сетки данных в коллекцию внутри объекта с помощью MVVM

#c# #wpf #data-binding #datagrid #combobox

#c# #wpf #привязка к данным #datagrid #поле со списком

Вопрос:

У меня есть поле со списком, в котором содержится список StrategyViewModels. StrategyViewModel имеет внутри себя наблюдаемую коллекцию StrategyParameterViewModels. У меня есть StrategyViewModel с именем SelectedStrategy, который я привязал к свойству SelectedItem в выпадающем списке. Когда пользователь выбирает стратегию из выпадающего списка, я хотел бы установить itemsource сетки данных в StrategyParameters внутри этой стратегии. Я перепробовал все разные способы, но, похоже, ничего не работает.

Вот XAML:

 <ComboBox Height="23" Margin="0,12,0,0" Name="cbxStrats" VerticalAlignment="Top" ItemsSource="{Binding Strategies}" DisplayMemberPath="Name" SelectedItem="{Binding Path=SelectedStrategy,Mode=TwoWay}" />

 <DataGrid AutoGenerateColumns="False" Margin="12,97,14,35" Name="dgSettings" ItemsSource="{Binding SelectedStrategy.Parameters, Mode=TwoWay}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name"  Binding="{Binding Path=Name}" IsReadOnly="True"/>
            <DataGridTextColumn Header="Value" Binding="{Binding Path=Value}" IsReadOnly="False"/>
        </DataGrid.Columns>
    </DataGrid>
  

Вот стратегия ViewModel:

 public class StrategyViewModel : ViewModelBase
{
    public StrategyObject Strategy { get; set; }

    public int Id
    {
        get { return Strategy.Id; }
        set 
        {
            if (value == Strategy.Id)
                return;
            Strategy.Id = value;
            OnPropertyChanged("Id");
        }
    }

    public string Name
    {
        get { return Strategy.Name; }
        set 
        {
            if (value == Strategy.Name)
                return;
            Strategy.Name = value;
            OnPropertyChanged("Name");
        }
    }

    public ObservableCollection<StrategyParameterViewModel> Parameters { get { return _parameters; } }
    public ObservableCollection<StrategyParameterViewModel> _parameters;

    public StrategyViewModel()
    {
        Strategy = new StrategyObject();
        _parameters = new ObservableCollection<StrategyParameterViewModel>();
    }

    public StrategyViewModel(StrategyObject o, IEnumerable<StrategyParameterObject> pms)
    {
        Strategy = o;
        _parameters = new ObservableCollection<StrategyParameterViewModel>();
        foreach (StrategyParameterObject s in pms)
        {
            _parameters.Add(new StrategyParameterViewModel(s));
        }
    }   
}
  

И вот параметр StrategyParameter ViewModel:

 public class StrategyParameterViewModel : ViewModelBase
{
    public StrategyParameterObject StrategyParameter { get; set; }

    public int Id
    {
        get { return StrategyParameter.Id; }
        set 
        {
            if (value == StrategyParameter.Id)
                return;
            StrategyParameter.Id = value;
            OnPropertyChanged("Id");
        }
    }

    public int StrategyId
    {
        get { return StrategyParameter.StrategyId; }
        set 
        {
            if (value == StrategyParameter.StrategyId)
                return;
            StrategyParameter.StrategyId = value;
            OnPropertyChanged("StrategyId");
        }
    }

    public string Name
    {
        get { return StrategyParameter.Name; }
        set 
        {
            if (value == StrategyParameter.Name)
                return;
            StrategyParameter.Name = value;
            OnPropertyChanged("Name");
        }
    }

    public string Value
    {
        get { return StrategyParameter.Value; }
        set 
        {
            if (value == StrategyParameter.Value)
                return;
            StrategyParameter.Value = value;
            OnPropertyChanged("Value");
        }
    }

            public StrategyParameterViewModel() 
    {
        StrategyParameter = new StrategyParameterObject();
    }

    public StrategyParameterViewModel(StrategyParameterObject o) 
    {
        StrategyParameter = o;
    }   
}
  

Ответ №1:

Проблема в том, что вы пытаетесь настроить двустороннюю привязку со свойством, доступным только для чтения. Вам нужно либо добавить параметр для SelectedStrategy.Параметры или использовать одностороннюю привязку к источнику itemssource для datagrid.

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

1. боже, я чувствую себя глупо. Я установил для него значение oneway, и оно все еще не работало. Затем я понял, что не реализовал INotifyChanged в моем объекте SelectedStrategy. Как только я это сделал, все работает отлично.

Ответ №2:

С моей точки зрения, я не думаю, что вы делаете что-то неправильно в отношении вашего XAML.

Общеизвестно, что привязка данных является сложной задачей. Я предлагаю добавить PresentationTraceSources, чтобы получить больше отладочной информации о том, что найдено. Это отправит несколько строк данных о результатах привязки к вашему окну вывода.

     <ComboBox Height="23" Margin="0,12,0,0" Name="cbxStrats" VerticalAlignment="Top" DisplayMemberPath="Name">
        <ComboBox.ItemsSource>
            <Binding Path="Strategies" PresentationTraceSources.TraceLevel="High"/>
        </ComboBox.ItemsSource>
        <ComboBox.SelectedItem>
            <Binding Path="SelectedStrategy" Mode="TwoWay" PresentationTraceSources.TraceLevel="High"/>
        </ComboBox.SelectedItem>
    </ComboBox>

    <DataGrid AutoGenerateColumns="False" Margin="12,97,14,35" Name="dgSettings">
        <DataGrid.ItemsSource>
            <Binding Path="SelectedStrategy.Parameters" Mode="TwoWay" PresentationTraceSources.TraceLevel="High"/>
        </DataGrid.ItemsSource>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name"  Binding="{Binding Path=Name}" IsReadOnly="True"/>
            <DataGridTextColumn Header="Value" Binding="{Binding Path=Value}" IsReadOnly="False"/>
        </DataGrid.Columns>
    </DataGrid>
  

Кроме того, может помочь WPF Inspector, поскольку вы можете настраивать выражения привязки данных в режиме реального времени при запуске вашего реального приложения.http://wpfinspector.codeplex.com /