Переоценка строк и столбцов UniformGrid WPF
Я пытаюсь создать видеоплеер, который может воспроизводить несколько видео одновременно. Я заставил игроков работать, и теперь я пытаюсь позволить пользователю добавлять дополнительные видео во время выполнения. Я отображаю видео в единой сетке, которая использует конвертер, чтобы решить, сколько строк и столбцов следует сгенерировать, основываясь на количестве видео. Он отлично работает, когда вы определяете, сколько игроков есть до запуска, однако, когда я добавляю игрока во время его работы, единая сетка не обновляет строки или столбцы. Это просто добавляет другое видео к любой структуре, которая у него была раньше. Есть ли в любом случае, что я могу заставить его пересмотреть строки / столбцы?
TL; DR: Могу ли я пересмотреть строки и столбцы единой сетки при просмотре? Как?
XAML для контроля ниже. Дополнительная информация, которая может быть полезна:
1. Игроки - это ObservableCollection
2. Элемент управления представлен с TabControl
<UserControl x:Class="Views.AllVideos"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-Views"
mc:Ignorable="d">
<ItemsControl ItemsSource="{Binding Players}"
x:Name="AllVideosControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding Players, Converter={StaticResource CountToColumns}, Mode=OneWay}"
Rows="{Binding Players, Converter={StaticResource CountToRows}, Mode=OneWay}"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="{DynamicResource AccentBrush}"
BorderThickness="1"
Margin="5">
<ls:PanelPreview DataContext="{Binding}"/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
2 ответа
Проблема, как представляется, заключается в том, что ничто не уведомляет о привязке, что количество элементов в Players
изменилось: привязка сидит в ожидании вашей модели представления, чтобы сказать, что есть новая Players
коллекция.
Но с тех пор Players
является ObservableCollection
поднимет PropertyChanged
когда это Count
изменения. Итак, простейший случай:
<UniformGrid
Rows="{Binding Players.Count}"
...
/>
Следующее работает для меня, чтобы обновить количество строк и столбцов при добавлении элементов в Players
, Арифметика в конвертере может потребовать небольшой работы, но дело в том, что привязки обновляются UniformGrid.Rows
а также UniformGrid.Columns
каждый раз Players
изменения. Это работает, потому что ObservableCollection
повышения PropertyChanged("Count")
каждый раз, когда элемент добавляется или удаляется. Потому что я привязан к свойству ObservableCollection
привязка подписывается на ObservableCollection
"s PropertyChanged
событие, поэтому он знает, чтобы обновить, когда Count
изменения.
C#
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void AddButton_Click(object sender, RoutedEventArgs e)
{
(DataContext as ViewModel).Players.Add($"Player {(DataContext as ViewModel).Players.Count + 1}");
}
private void RemoveButton_Click(object sender, RoutedEventArgs e)
{
if ((DataContext as ViewModel).Players.Count > 0)
(DataContext as ViewModel).Players.RemoveAt(0);
}
}
public class ViewModel
{
private ObservableCollection<String> _players = new ObservableCollection<string>();
public ObservableCollection<String> Players
{
get { return _players; }
}
}
public class RowsColumnsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Math.Ceiling(Math.Sqrt((int)value));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ItemsControl
Grid.Row="1"
ItemsSource="{Binding Players}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid
Rows="{Binding Players.Count, Converter={StaticResource RowsColumns}}"
Columns="{Binding Players.Count, Converter={StaticResource RowsColumns}}"
/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Button
Content="Add Player"
Click="AddButton_Click"
Margin="2"
Width="100"
/>
<Button
Content="Remove Player"
Click="RemoveButton_Click"
Margin="2"
Width="100"
/>
</StackPanel>
</Grid>
Настройка Rows
а также Columns
не нужен вообще. Все будет работать без них тоже. UniformGrid
поместит все равномерно внутри любого контейнера.
Если вы все еще хотите использовать Binding
, тогда следующие работы для меня, Cols
зафиксированы здесь. Converters
не нужны.
void Players_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
Rows = (int)Math.Ceiling(Players.Count / Cols);
}