英文:
With WinUI3 and C#, how do you take a Observable list of Image paths and display them as a horizontal list that fills width?
问题 {#heading}
我有一组图像路径,并希望在单个水平行中显示它们引用的图像。每个图像的宽度应相同,并且它们应根据窗口的调整大小填充窗口的高度或其分配的宽度。
我尝试使用StackPanel来实现这一点,但它不会像具有*大小调整的Grid那样调整图像。
<ItemsControl
x:Name="HandImages"
Padding="5"
ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image
Source="{Binding}"
Tapped="ImageTapped"
Stretch="UniformToFill"
FlyoutBase.AttachedFlyout="{StaticResource ImagePreviewFlyout}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
英文:
I have a list of image paths and would like to display the images they refer to in a single horizontal row. The width of each image should be the same and they should all fill the Window's height or their allocated width as the window is resized.
I tried to do this with a StackPanel, but it does not resize the images like a Grid with *-sizing would.
<ItemsControl
x:Name="HandImages"
Padding="5"
ScrollViewer.HorizontalScrollBarVisibility="Visible">
&lt;ItemsControl.ItemsPanel&gt;
&lt;ItemsPanelTemplate&gt;
&lt;StackPanel Orientation=&quot;Horizontal&quot;/&gt;
&lt;/ItemsPanelTemplate&gt;
&lt;/ItemsControl.ItemsPanel&gt;
&lt;ItemsControl.ItemTemplate&gt;
&lt;DataTemplate&gt;
&lt;Image
Source=&quot;{Binding}&quot;
Tapped=&quot;ImageTapped&quot;
Stretch=&quot;UniformToFill&quot;
FlyoutBase.AttachedFlyout=&quot;{StaticResource ImagePreviewFlyout}&quot;/&gt;
&lt;/DataTemplate&gt;
&lt;/ItemsControl.ItemTemplate&gt;
&lt;/ItemsControl&gt;
答案1 {#1}
得分: 1
你可以使用Windows CommunityToolkit 中的UniformGrid,并将其用作ItemsPanel
。
-
命名你的页面。我们需要这样做来从
DataTemplate
到页面的Items.Count
属性进行绑定。 -
安装CommunityToolkit.WinUI.UI.Controls.Primitives NuGet包。
-
还有这个:
<ItemsControl ItemsSource="{x:Bind Items, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:UniformGrid
Columns="{Binding ElementName=RootPage, Path=Items.Count}"
Rows="0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
英文:
You could use the UniformGrid from the Windows CommunityToolkit and use it as an ItemsPanel
.
-
Name your page. We need to to do this to do bindings from the
DataTemplate
to theItems.Count
property in the page. -
Install the CommunityToolkit.WinUI.UI.Controls.Primitives NuGet package.
-
And this:
<ItemsControl ItemsSource="{x:Bind Items, Mode=OneWay}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:UniformGrid
Columns="{Binding ElementName=RootPage, Path=Items.Count}"
Rows="0" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
答案2 {#2}
得分: 0
这是XAML部分的翻译:
可以以最小的XAML代码以编程方式完成这个任务。以下是我使用的XAML。
<Grid x:Name="HandGrid"
RowDefinitions="*">
</Grid>
这是C#部分的翻译:
// 然后创建一个视图的可观察集合。我在我的情况下使用了以下代码。
public ObservableCollection<string> images = new();
// 接着,添加代码以响应集合的变化,就像这样。
// 在安全的地方观察集合
viewModel.images.CollectionChanged += HandChanged;
...
private readonly List<ColumnDefinition> ColumnDefinitions = new();
private readonly List<string> ImagePaths = new();
private readonly List<Image> Images = new();
private void HandChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(e.OldItems != null)
{
foreach (string item in e.NewItems)
{
HandGrid.ColumnDefinitions.Remove(ColumnDefinitions[^1]);
ColumnDefinitions.RemoveAt(ColumnDefinitions.Count - 1);
Images.RemoveAt(ImagePaths.IndexOf(item));
ImagePaths.Remove(item);
}
}
if (e.NewItems != null)
{
foreach (string item in e.NewItems)
{
ColumnDefinition cd = new()
{
Width = new GridLength(1, GridUnitType.Star)
};
ColumnDefinitions.Add(cd);
HandGrid.ColumnDefinitions.Add(cd);
Image image = new() {
Source = new BitmapImage(new Uri(FileUtil.GetFullPath(item))),
Stretch = Stretch.Uniform,
};
Images.Add(image);
ImagePaths.Add(item);
Grid.SetColumn(image, Images.Count - 1);
HandGrid.Children.Add(image);
}
}
}
这是您要求的翻译,不包含其他内容。 英文:
It is possible to do this programmatically with minimal XAML. Here is the XAML I used.
<Grid x:Name="HandGrid"
RowDefinitions="*">
&lt;/Grid&gt;
Then create an observable collection of the views. I used this in my case.
public ObservableCollection<string> images = new();
Then, add code to respond to changes in the collection like this.
// Observe the collection somewhere where it is safe to do so
viewModel.images.CollectionChanged += HandChanged;
...
private readonly List<ColumnDefinition> ColumnDefinitions = new();
private readonly List<string> ImagePaths = new();
private readonly List<Image> Images = new();
private void HandChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(e.OldItems != null)
{
foreach (string item in e.NewItems)
{
HandGrid.ColumnDefinitions.Remove(ColumnDefinitions[^1]);
ColumnDefinitions.RemoveAt(ColumnDefinitions.Count - 1);
Images.RemoveAt(ImagePaths.IndexOf(item));
ImagePaths.Remove(item);
}
}
if (e.NewItems != null)
{
foreach (string item in e.NewItems)
{
ColumnDefinition cd = new()
{
Width = new GridLength(1, GridUnitType.Star)
};
ColumnDefinitions.Add(cd);
HandGrid.ColumnDefinitions.Add(cd);
Image image = new() {
Source = new BitmapImage(new Uri(FileUtil.GetFullPath(item))),
Stretch = Stretch.Uniform,
};
Images.Add(image);
ImagePaths.Add(item);
Grid.SetColumn(image, Images.Count - 1);
HandGrid.Children.Add(image);
}
}
}