我是否正确创建了这个网格?

Am I creating this grid properly?

我正在尝试创建一个应用程序(目前)查看您的相机胶卷并在网格中显示您的图像。我设法让一个图像开始显示,但是当我尝试动态创建网格行时,没有图像显示。有人可以指出我可能做错了什么以及如何正确地做到这一点吗?我是 C# 编程和 Windows Phone 开发的新手,所以对于这个业余问题,我深表歉意。

public async void PrintInformation()
    {
        try
        {
            TextBlock.Text = "";
            IReadOnlyCollection<StorageFile> PicLib = await KnownFolders.CameraRoll.GetFilesAsync();
            IEnumerator<StorageFile> PicLibEnum = PicLib.GetEnumerator();
            Debug.WriteLine(PicLib.Count);
            int Count = 0;
            foreach (StorageFile Pic in PicLib)
            {
                if (Count % 3 == 0)
                {
                    Debug.WriteLine("Creating new row..." + Count % 3);
                    MainGrid.RowDefinitions.Add(new RowDefinition());
                }
                Image imageblock = new Image();
                imageblock.SetValue(Grid.ColumnProperty, Count % 3);
                imageblock.SetValue(Grid.RowProperty, Count / 3);
                Debug.WriteLine(imageblock);
                TextBlock.Text += Pic.Path + "\n";
                IRandomAccessStream PicStream = await Pic.OpenReadAsync();
                BitmapImage Bmp = new BitmapImage();
                await Bmp.SetSourceAsync(PicStream);
                //Uri Uri = new Uri(Pic.Path, UriKind.Absolute);
                //Bmp.UriSource = Uri;
                imageblock.Source = Bmp;
                //break;
                Count++;
            }
        }
        catch (Exception e)
        {
            TextBlock.Text = e.ToString();
        }
    }

首先,不要使用:

imageblock.SetValue(Grid.ColumnProperty, Count % 3);

而改用相当于

Grid.SetColumn(imageblock, Count % 3);

在我看来,第二个看起来更简单易用 :)

第二,动态添加新的行和列不是一个好主意:每次您 添加新行/列 从您的collection 中删除一个项目。 尝试使用 ListView,将源绑定到可观察的 collection 并在 ListView 内使用 Horizo​​ntal WrapGrid。 然后简单地创建你自己的带有图像的 DataTemplate,将它的源绑定到你的 ObservableCollection 的每个元素,你就起来了:)

您将能够添加新图像而无需担心布局和网格索引。

编辑:这是一般的想法,在XAML

<ListView ItemsSource="{Binding Source}"
          ItemTemplate="{StaticResource ImageTemplate}"                  
    <ListView.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapGrid Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ListView.ItemsPanel>
</ListView>

或者像Rob Caplan说的那样,你可以用一个GridView,最后的结果几乎是一样的。

然后在你的 Page.Resources 部分,像这样:

<DataTemplate x:Key="ImageTemplate">
    <Grid Margin="5,5,5,0" Height="45" Width="45">
        <Image Source="{Binding}"/>
    </Grid>
</DataTemplate>

然后您必须创建一个 class 实现 INotyfy属性Changed,在您的页面构造函数中创建一个实例并将其分配给您的 DataContext。

在那个 class 里面,你会有这样的东西:

private ObservableCollection<ImageSource> _Source = new ObservableCollection<ImageSource>();

public ObservableCollection<ImageSource> Source
{
    get
    {
        return this._Source;
    }
    set
    {
        if (this._Source != value)
        {
            this._Source = value;
            this.OnPropertyChanged();
        }
    }
}

现在 ListView 将从您的 ViewModel 中的那个 属性 获取源 collection,并且由于源 属性 是一个 ObservableColleciton,每次您添加一个项目时,ListView 都会收到通知,它将更新其布局:)

图像不显示的原因是您没有将它们添加到网格中。设置图像后,将它们添加到 MainGrid 的子节点,您的代码应该可以工作

MainGrid.Children.Add(imageblock);

除此之外,您的代码还不错,尽管比必要的要复杂。正如 Sergio 建议的那样,您可以通过数据绑定大大简化这一过程。数据绑定可以让您将数据和表示分开:您可以在代码中保存一组图像并描述它们在 Xaml 中的显示方式。

如果您创建一个包含相机胶卷中的位图图像的 ObservableCollection,您可以根据需要添加到它,绑定将自动在 Xaml 中显示新图像(ObservableCollection 实现 INotifyCollectionChanged 添加或删除项目时报告的魔法)。您还可以绑定到具有不同外观的多个控件。如果您只需要图像,可以将它们直接添加到集合中。更常见的是,您还会将 class 与其他数据绑定,例如,您可能会包含图像及其名称。

在 Xaml 中,您将使用 ItemsControl 来显示集合。由于您需要网格,因此 GridView 是一个不错的选择。如果你想要一个列表,每个项目都在它自己的行中,那么 ListView 会更好。您可以设置 ItemTemplate 来控制图像的显示方式:

<GridView ItemsSource="{Binding}">
    <GridView.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Image Source="{Binding Image}" />
                <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>            
</GridView>

有关详细信息,请参阅 MSDN 上的 Data binding overview (XAML)