Я впервые публикую здесь вопрос, поэтому заранее прошу прощения, если я что-то пропустил в своем вопросе, если я не предоставлю достаточно подробностей.
Прежде всего, я обнаружил очень похожую проблему, описанную в этом посте, которая довольно четко описывает то, чего я пытаюсь достичь: Авторазмер столбцов списка просмотра при обновлении контента однако ограничения репутации делаютне позволяйте мне комментировать, и поэтому я создаю этот вопрос.
По моей конкретной проблеме:
Я впервые создаю приложение WPF и пытаюсь обернуть головувокруг шаблона MVVM. В моем представлении у меня есть listView с сеткой. ItemSource списка просмотра связан с ICollectionView в моем ViewModel, который имеет свой CollectionViewSource, обновленный различными ObservableCollections в зависимости от того, какую категорию растений выбирает пользователь. Наблюдаемые коллекции извлекают свои данные из локальной базы данных в зависимости от ввода поискового запроса от пользователя.
Моя проблема в том, что когда пользователь впервые вводит данные для поиска, список заполняется результатами иширина каждого из столбцов gridview корректируется, чтобы соответствовать самой длинной строке в каждом столбце.
Однако, когда пользователь вводит другой поисковый запрос, и я обновляю наблюдаемую коллекцию, ширина столбцов gridview не корректируется для соответствия новым данным, поэтому ширина останется такой, какой она была установлена в результатепервого поискового запроса.
Я хотел бы иметь возможность динамически устанавливать ширину каждого столбца, чтобы соответствовать самому длинному элементу в этом столбце, но не могу обернуться, как это сделать правильно, не нарушая шаблон MVVM.
Решения, предложенные в предыдущем упомянутом посте, предлагают отредактировать мой файл xaml.cs, который, на мой взгляд, не следует делать в MVVM, поскольку файл codebehind для представления не должен содержать никакой логики. Насколько я понимаю, правильный подход состоит в том, чтобы выставить свойства в модели представления, а затем связать их с представлением через xaml.
Мой наивный подход состоял в том, чтобы выставить свойство Width в моей ViewModel, однако, поскольку у меня есть несколько столбцов в моем представлении, мне нужно было бы выставить свойства width для каждого и пересчитать их ширину путем итерации покаждый объект во вновь полученных результатах находит самую длинную строку среди них, что кажется утомительным и неправильным подходом.
Итак, мой вопрос в основном: каков наилучший способ пересчитать ширину столбцов сетки в представлении, когда ItemSource в модели представления обновляется, не имея представления модели представления о представлении?
Должен ли я выставить свойства для ширины в моей модели представления или я могу каким-то образом вызвать событие в модели представления и подписаться на это в моем представлении? Буду признателен за любую помощь или советы по этому поводу!
Вот код xaml для моего списка:
<ListView x:Name="lvPlantCollection" ItemsSource="{Binding ActiveView}" SelectedItem="{Binding SelectedPlant}" Grid.Row="0">
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding Name}">
<GridViewColumnHeader Content="Navn" Tag="Name" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding MotherPlant.Name}">
<GridViewColumnHeader Content="Mor" Tag="MotherPlantName" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding FatherPlant.Name}">
<GridViewColumnHeader Content="Far" Tag="FatherPlantName" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding CaNumber}">
<GridViewColumnHeader Content="Ca nummer" Tag="CaNumber" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding BreedersReference}">
<GridViewColumnHeader Content="Breeders ref" Tag="BreedersReference" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Elite}">
<GridViewColumnHeader Content="Elite" Tag="Elite" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
<GridViewColumn Header="DNA">
<GridViewColumn.CellTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding DNA}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="MutationNameTxtBlock" Text="{Binding Name}" Visibility="Collapsed"></TextBlock> <!--Negated logic, set to collapsed as standard, and then only show if value if mutationscore is actually M-->
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding WildType}" Value="M">
<Setter TargetName="MutationNameTxtBlock" Property="Visibility" Value="Visible"></Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn DisplayMemberBinding="{Binding Comment}">
<GridViewColumnHeader Content="Kommentar" Tag="Comment" Command="{Binding SortActiveViewByColumnCommand}" CommandParameter="{Binding RelativeSource={RelativeSource self}, Path=Tag }"></GridViewColumnHeader>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
И ViewModel:
public ParentMenuViewModel(DataStore ds)
{
IBarleyDatabaseDAO db = BarleyDatabaseMysqlDAO.Instance;
this.ds = ds;
DHPlants = ds.DHPlants;
DonorPlants = ds.DonorPlants;
BreedersReferencePlants = ds.BreedersReferencePlants;
ElitePlants = ds.ElitePlants;
DMIPlants = ds.DMIPlants;
_activeView = CollectionViewSource.GetDefaultView(new List<Plant>());
}
ICollectionView _activeView;
public ICollectionView ActiveView
{
get
{
return _activeView;
}
set
{
if (_activeView != value)
{
_activeView = value;
_activeView.SortDescriptions.Clear();
_activeView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending));
OnPropertyChanged("ActiveView");
}
}
}
ObservableCollection<Plant> _activeList;
public ObservableCollection<Plant> ActiveList
{
get { return _activeList; }
set
{
if (_activeList != value)
{
_activeList = value;
ActiveView = CollectionViewSource.GetDefaultView(_activeList);
OnPropertyChanged("ActiveList");
}
}
}
public void UpdatePlants(string selectedPlantType)
{
if (!string.IsNullOrEmpty(Filter))
{
switch (selectedPlantType)
{
case "CA":
ds.UpdatePlantList(PlantType.DH, Filter, Page * 100);
ActiveList = DHPlants;
break;
case "Donor":
ds.UpdatePlantList(PlantType.DONOR, Filter, Page * 100);
ActiveList = DonorPlants;
break;
case "DMI":
ds.UpdatePlantList(PlantType.DMI, Filter, Page * 100);
ActiveList = DMIPlants;
break;
case "Breeders Reference":
ds.UpdatePlantList(PlantType.BREEDERS_REFERENCE_INTERNAL, Filter, Page * 100);
ActiveList = BreedersReferencePlants;
break;
case "Elite":
ds.UpdatePlantList(PlantType.ELITE_INTERNAL, Filter, Page * 100);
ActiveList = ElitePlants;
break;
default:
return;
}
}
else
{
ds.ClearPlantCollecetions();
}
}