.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
相关产品推荐
相关产品推荐

