You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET MAUI中ListView的IsVisible属性代码后置不生效问题

问题:MAUI中ListView初始隐藏后无法显示选中内容

我想在UI的ListView里展示选中的图片或文件,初始把ListView的IsVisible设为false,选择项目后设为true,但选择后ListView还是不显示。如果移除XAML里的IsVisible="false",项目能正常显示,但我需要ListView初始处于隐藏状态。


初始代码

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MediaPickerDemo.MainPage">

    <ScrollView>
        <VerticalStackLayout
            Spacing="25"
            Padding="30,0"
            VerticalOptions="Start">

            <Button
                x:Name="CounterBtn"
                Text="Click me"
                SemanticProperties.Hint="Counts the number of times you click"
                Clicked="OnClicked"
                HorizontalOptions="Center" />

            <ListView 
                x:Name="attachment_listview"
                IsVisible="false"
                Margin="0,10,0,0"
                HasUnevenRows="True"
                SelectionMode="None">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout
                                Margin="5,10"
                                HorizontalOptions="CenterAndExpand"
                                VerticalOptions="CenterAndExpand"
                                Orientation="Vertical">

                                <Image 
                                    Grid.Row="0"
                                    x:Name="attachmentPicture"
                                    Source="{Binding ImageSource}"
                                    HorizontalOptions="CenterAndExpand"
                                    Aspect="AspectFill"
                                    VerticalOptions="Start">
                                    <Image.WidthRequest>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>100</OnIdiom.Phone>
                                            <OnIdiom.Tablet>150</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>100</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Image.WidthRequest>
                                    <Image.HeightRequest>
                                        <OnIdiom x:TypeArguments="x:Double">
                                            <OnIdiom.Phone>100</OnIdiom.Phone>
                                            <OnIdiom.Tablet>150</OnIdiom.Tablet>
                                            <OnIdiom.Desktop>100</OnIdiom.Desktop>
                                        </OnIdiom>
                                    </Image.HeightRequest>
                                </Image>

                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="55*"/>
                                        <RowDefinition Height="45*"/>
                                    </Grid.RowDefinitions>

                                    <Label 
                                        Grid.Row="0"
                                        x:Name="attachmentname_label"
                                        Text="{Binding attachemntName}"
                                        TextColor="{Binding TextColor}"
                                        HorizontalTextAlignment="Center"
                                        HorizontalOptions="CenterAndExpand">
                                        <Label.FontSize>
                                            <OnIdiom x:TypeArguments="x:Double">
                                                <OnIdiom.Phone>13</OnIdiom.Phone>
                                                <OnIdiom.Tablet>20</OnIdiom.Tablet>
                                                <OnIdiom.Desktop>13</OnIdiom.Desktop>
                                            </OnIdiom>
                                        </Label.FontSize>
                                    </Label>

                                    <Button 
                                        Grid.Row="1"
                                        Margin="0,0,0,5"
                                        x:Name="AttachmentRemove_Stack"
                                        Text="Remove"
                                        Style="{StaticResource RemoveButtonStyle}"/>
                                </Grid>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
                <ListView.HeightRequest>
                    <OnIdiom x:TypeArguments="x:Double">
                        <OnIdiom.Phone>220</OnIdiom.Phone>
                        <OnIdiom.Tablet>330</OnIdiom.Tablet>
                        <OnIdiom.Desktop>220</OnIdiom.Desktop>
                    </OnIdiom>
                </ListView.HeightRequest>
            </ListView>
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

MainPage.xaml.cs

public partial class MainPage : ContentPage
{
    public System.Collections.Generic.IEnumerable<Microsoft.Maui.Storage.FileResult> choosedFiles;
    public ObservableCollection<MultipleAttachments> attachmentList;
    FileResult photo;

    public MainPage()
    {
        InitializeComponent();
        attachmentList = new ObservableCollection<MultipleAttachments>();
    }

    private async void OnClicked(object sender, EventArgs e)
    {
        string action = await DisplayActionSheet(null, "Cancel", null, "Photo", "File");
        if (action == "Photo")
        {
            string action1 = await DisplayActionSheet(null, "Cancel", null, "Take photo", "Upload from gallery");
            if (action1 == "Take photo")
            {
                CameraClick();
            }
            else if (action1 == "Upload from gallery")
            {
                GalleryClick();
            }
        }
        else if (action == "File")
        {
            try
            {
                choosedFiles = await FilePicker.Default.PickMultipleAsync();
                foreach (var item in choosedFiles.ToList())
                {
                    attachmentList.Add(new MultipleAttachments()
                    {
                        attachemntName = item.FileName,
                        ImageSource = "ic_doc_xx.png".ToString(),
                        TextColor = Colors.Black,
                        type = "file",
                        path = item.FullPath
                    });
                    attachment_listview.IsVisible = true;
                    attachment_listview.ItemsSource = attachmentList;
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine("exception:>>" + ex);
            }
        }
    }

    private async void CameraClick()
    {
        try
        {
            try
            {
                photo = await MediaPicker.CapturePhotoAsync();
                if (photo != null)
                {
                    var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
                    using (var stream = await photo.OpenReadAsync())
                    using (var newStream = File.OpenWrite(newFile))
                        await stream.CopyToAsync(newStream);

                    attachmentList.Add(new MultipleAttachments()
                    {
                        attachemntName = Path.GetFileName(photo.FullPath),
                        ImageSource = Path.Combine(FileSystem.CacheDirectory, photo.FileName),
                        TextColor = Colors.Black,
                        type = "image",
                        path = photo.FullPath
                    });
                    attachment_listview.IsVisible = true;
                    attachment_listview.ItemsSource = attachmentList;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("Exception:>" + ex);
        }
    }

    async void GalleryClick()
    {
        try
        {
            try
            {
                photo = await MediaPicker.PickPhotoAsync();
                if (photo != null)
                {
                    var newFile = Path.Combine(FileSystem.CacheDirectory, photo.FileName);
                    using (var stream = await photo.OpenReadAsync())
                    using (var newStream = File.OpenWrite(newFile))
                        await stream.CopyToAsync(newStream);

                    attachmentList.Add(new MultipleAttachments()
                    {
                        attachemntName = Path.GetFileName(photo.FullPath),
                        ImageSource = Path.Combine(FileSystem.CacheDirectory, photo.FileName),
                        TextColor = Colors.Black,
                        type = "image",
                        path = photo.FullPath
                    });
                    attachment_listview.IsVisible = true;
                    attachment_listview.ItemsSource = attachmentList;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"CapturePhotoAsync THREW: {ex.Message}");
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("gallery Exception:>" + ex);
        }
    }
}

public class MultipleAttachments : INotifyPropertyChanged
{
    public string attachemntName { get; set; }
    public string type { get; set; }
    public string path { get; set; }

    private ImageSource imageSource;
    public ImageSource ImageSource
    {
        set
        {
            if (value != null)
            {
                imageSource = value;
                NotifyPropertyChanged();
            }
        }
        get
        {
            return imageSource;
        }
    }

    private Color textColor;
    public Color TextColor
    {
        set
        {
            if (value != null)
            {
                textColor = value;
                NotifyPropertyChanged();
            }
        }
        get
        {
            return textColor;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

更新后的尝试代码

添加了数据绑定来控制可见性,但问题依旧,且不清楚之前回答中提到的"服务"指什么。

ViewModel代码

private bool mediaVisibility = false;
public bool MediaVisibility
{
    get
    {
        return mediaVisibility;
    }
    set
    {
        mediaVisibility = value;
        OnPropertyChanged(nameof(MediaVisibility));
    }
}

MainPage.xaml.cs修改部分

// 创建ViewModel实例
MediaViewModel mvm;
......
.....
// 设置绑定上下文
mvm = new MediaViewModel();
BindingContext = mvm;

// 在拍照、选图库、选文件的逻辑中设置
mvm.MediaVisibility = true;

XAML修改部分

<ListView 
    x:Name="attachment_listview"
    Margin="0,0,10,10"
    IsVisible="{Binding MediaVisibility, Mode=TwoWay}"
    HasUnevenRows="True"
    SelectionMode="None">
    <ListView.ItemTemplate>
    ....
</ListView>

解决方案

1. 确保ViewModel完整实现INotifyPropertyChanged

你的MediaViewModel必须完整实现接口,否则属性变更无法通知UI:

public class MediaViewModel : INotifyPropertyChanged
{
    private bool mediaVisibility = false;
    public bool MediaVisibility
    {
        get => mediaVisibility;
        set
        {
            if (mediaVisibility != value)
            {
                mediaVisibility = value;
                OnPropertyChanged(nameof(MediaVisibility));
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 避免重复设置ItemsSource

ObservableCollection本身会自动通知UI更新,只需要在初始化时设置一次ItemsSource即可:

public MainPage()
{
    InitializeComponent();
    attachmentList = new ObservableCollection<MultipleAttachments>();
    attachment_listview.ItemsSource = attachmentList; // 初始化时设置一次
    mvm = new MediaViewModel();
    BindingContext = mvm;
}

之后添加项时,只需要更新集合和可见性,无需重复绑定:

// 文件选择示例
foreach (var item in choosedFiles.ToList())
{
    attachmentList.Add(new MultipleAttachments()
    {
        attachemntName = item.FileName,
        ImageSource = "ic_doc_xx.png",
        TextColor = Colors.Black,
        type = "file",
        path = item.FullPath
    });
}
mvm.MediaVisibility = true; // 最后统一设置可见性

3. 简化绑定模式

IsVisible不需要双向绑定,单向绑定即可:

IsVisible="{Binding MediaVisibility}"

4. 直接代码控制可见性(备选方案)

如果绑定方式仍有问题,可以直接在代码后台控制,跳过ViewModel绑定:

// 初始化时隐藏
public MainPage()
{
    InitializeComponent();
    attachment_listview.IsVisible = false;
    attachmentList = new ObservableCollection<MultipleAttachments>();
    attachment_listview.ItemsSource = attachmentList;
}

// 选择项目后显示
// 在CameraClick、GalleryClick、文件选择逻辑中
attachment_listview.IsVisible = true;

5. 确保UI线程更新

如果遇到线程问题,强制在UI线程更新属性:

MainThread.BeginInvokeOnMainThread(() =>
{
    mvm.MediaVisibility = true;
    // 或者直接设置控件可见性
    // attachment_listview.IsVisible = true;
});

内容的提问来源于stack exchange,提问作者Sreejith Sree

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 17:19:50