英文:
How to access ObservableCollection from another ViewModel?
问题
I have a BaseViewModel where I define my ObservableCollection and then I populate it. In another ViewModel I have a Grid and I bind it to my collection, everything works.
public partial class BaseViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<Patient> patientInfo;
public BaseViewModel()
{
PopulateObservableCollection();
}
public void PopulateObservableCollection()
{
PatientInfo = new ObservableCollection<Patient>();
try
{
string query = "select * from " + App.userDetails.DbTable;
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(query, conn);
using (sqlDataAdapter)
{
System.Data.DataTable dt = new System.Data.DataTable();
sqlDataAdapter.Fill(dt);
foreach (System.Data.DataRow row in dt.Rows)
PatientInfo.Add(new Patient(Convert.ToInt32(row[0]), row[1].ToString(), row[2].ToString(), row[3].ToString(), row[4].ToString(), row[5].ToString(), row[6].ToString(), row[7].ToString(), row[8].ToString()));
}
}
catch (Exception)
{ }
}
}
Now I want to change my ObservableCollection from the other ViewModels and be able to access the memory from the BaseViewModel.
Next a ViewModel where I try to change the ObservableCollection, but I'm not accessing the objected created in the BaseViewModel:
[QueryProperty(nameof(Patient), nameof(Patient))]
public partial class EditingViewModel : BaseViewModel
{
[ObservableProperty] private Patient patient;
[RelayCommand]
private async Task Delete()
{
try
{
string query = "DELETE from " + App.userDetails.DbTable + " WHERE id = @patientId";
sqlConnection = new SqlConnection(conn);
SqlCommand sqlCommand = new SqlCommand(query, sqlConnection);
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
using (sqlDataAdapter)
{
sqlConnection.Open();
sqlCommand.Parameters.AddWithValue("@patientId", Patient.Id);
sqlCommand.ExecuteScalar();
}
//Removing object from observable collection
PatientInfo.Remove(PatientInfo.SingleOrDefault(x => x.Id == Patient.Id));
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Aplicação", ex.ToString(), "Sair");
}
finally
{
sqlConnection.Close();
}
}
}
My "DashboardView" where the grid is defined:
<?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"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="PatientAppMultiPlatf.Views.DashboardPage"
xmlns:viewModels="clr-namespace:PatientAppMultiPlatf.ViewModels"
xmlns:syncfusion="clr-namespace:Syncfusion.Maui.DataGrid;assembly=Syncfusion.Maui.DataGrid"
Title="Lista de Pacientes">
<VerticalStackLayout Padding="10">
<HorizontalStackLayout Padding="20" >
<Button
Text="Exportar" Command="{Binding PDFCommand}" CornerRadius="20" WidthRequest="100" HorizontalOptions="End">
</Button>
<Button
Text="Filtrar" Command="{Binding FilterCommand}" WidthRequest="100" CornerRadius="20" HorizontalOptions="Center">
</Button>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Date}" VerticalOptions="Center" Placeholder="Data"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Name}" VerticalOptions="Center" Placeholder="Nome"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Age}" VerticalOptions="Center" Placeholder="Idade"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Gender}" VerticalOptions="Center" Placeholder="Genero"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Process}" VerticalOptions="Center" Placeholder="Processo"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Diagnostic}" VerticalOptions="Center" Placeholder="Diagnostico"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Discharge}" VerticalOptions="Center" Placeholder="Alta"/>
</Frame>
</HorizontalStackLayout>
<syncfusion:SfDataGrid x:Name="dataGrid" DefaultColumnWidth="90"
ItemsSource="{Binding PatientInfo}" SortingMode="Single" SelectedRow="{Binding SelectedPatient}" SelectionMode="Single"
HeightRequest="600" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" AutoGenerateColumnsMode="None">
<syncfusion:SfDataGrid.Behaviors>
<toolkit:EventToCommandBehavior
EventName="CellDoubleTapped"
Command="{Binding CellDoubleTappedCommand}">
</toolkit:EventToCommandBehavior>
</syncfusion:SfDataGrid.Behaviors>
<syncfusion:SfDataGrid.Columns VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<syncfusion:DataGridTextColumn HeaderText="Data" MappingName="Date"/>
<syncfusion:DataGridTextColumn HeaderText="Nome" MappingName="Name" ColumnWidthMode="Fill"/>
<syncfusion:DataGridTextColumn HeaderText="Idade" MappingName="Age"/>
<syncfusion:DataGridTextColumn HeaderText="Genero" MappingName="Gender"/>
<syncfusion:DataGridTextColumn HeaderText="Processo" MappingName="Process"/>
<syncfusion:DataGridTextColumn HeaderText="Diagnostico" MappingName="Diagnostic" ColumnWidthMode="Fill"/>
<syncfusion:DataGridTextColumn HeaderText="Alta" MappingName="Discharge" ColumnWidthMode="LastColumnFill"/>
</syncfusion:SfDataGrid.Columns>
<syncfusion:SfDataGrid.DefaultStyle>
<syncfusion:DataGridStyle HeaderRowBackground="#b2cbc8" HeaderRowTextColor="Black" />
</syncfusion:SfDataGrid.DefaultStyle>
</syncfusion:SfDataGrid>
</VerticalStackLayout>
</ContentPage>
Each view has a xaml.cs where I bind the page to the view model:
namespace PatientAppMultiPlatf.Views;
public partial class DashboardPage : ContentPage
{
public DashboardPage(DashboardViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
}
I'm using MVVM architecture. What is the best method to access the ObservableCollection that is being
英文:
I have a BaseViewModel where I define my ObservableCollection and then I populate it. In another ViewModel I have a Grid and I bind it to my collection, everything works.
public partial class BaseViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<Patient> patientInfo;
public BaseViewModel()
{
PopulateObservableCollection();
}
public void PopulateObservableCollection()
{
PatientInfo = new ObservableCollection<Patient>();
try
{
string query = "select * from " + App.userDetails.DbTable;
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(query, conn);
using (sqlDataAdapter)
{
System.Data.DataTable dt = new System.Data.DataTable();
sqlDataAdapter.Fill(dt);
foreach (System.Data.DataRow row in dt.Rows)
PatientInfo.Add(new Patient(Convert.ToInt32(row[0]), row[1].ToString(), row[2].ToString(), row[3].ToString(), row[4].ToString(), row[5].ToString(), row[6].ToString(), row[7].ToString(), row[8].ToString()));
}
}
catch (Exception)
{ }
}
}
Now I want to change my ObservableCollection from the other ViewModels and be able to access the memory from the BaseViewModel.
Next a ViewModel where I try to change the ObservableCollection, but I'm not accessing the objected created in the BaseViewModel:
[QueryProperty(nameof(Patient), nameof(Patient))]
public partial class EditingViewModel : BaseViewModel
{
[ObservableProperty] private Patient patient;
[RelayCommand]
private async Task Delete()
{
try
{
string query = "DELETE from " + App.userDetails.DbTable + " WHERE id = @patientId";
sqlConnection = new SqlConnection(conn);
SqlCommand sqlCommand = new SqlCommand(query, sqlConnection);
SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand);
using (sqlDataAdapter)
{
sqlConnection.Open();
sqlCommand.Parameters.AddWithValue("@patientId", Patient.Id);
sqlCommand.ExecuteScalar();
}
//Removing object from observable collection
PatientInfo.Remove(PatientInfo.SingleOrDefault(x => x.Id == Patient.Id));
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Aplicaçao", ex.ToString(), "Sair");
}
finally
{
sqlConnection.Close();
}
}
}
My "DashboardView" where the grid is defined:
<?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"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="PatientAppMultiPlatf.Views.DashboardPage"
xmlns:viewModels="clr-namespace:PatientAppMultiPlatf.ViewModels"
xmlns:syncfusion="clr-namespace:Syncfusion.Maui.DataGrid;assembly=Syncfusion.Maui.DataGrid"
Title="Lista de Pacientes">
<VerticalStackLayout Padding="10">
<HorizontalStackLayout Padding="20" >
<Button
Text="Exportar" Command="{Binding PDFCommand}" CornerRadius="20" WidthRequest="100" HorizontalOptions="End">
</Button>
<Button
Text="Filtrar" Command="{Binding FilterCommand}" WidthRequest="100" CornerRadius="20" HorizontalOptions="Center">
</Button>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Date}" VerticalOptions="Center" Placeholder="Data"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Name}" VerticalOptions="Center" Placeholder="Nome"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Age}" VerticalOptions="Center" Placeholder="Idade"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Gender}" VerticalOptions="Center" Placeholder="Genero"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Process}" VerticalOptions="Center" Placeholder="Processo"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Diagnostic}" VerticalOptions="Center" Placeholder="Diagnostico"/>
</Frame>
<Frame HeightRequest="45" Padding="5" HasShadow="True" BorderColor="White">
<Entry Text="{Binding Discharge}" VerticalOptions="Center" Placeholder="Alta"/>
</Frame>
</HorizontalStackLayout>
<syncfusion:SfDataGrid x:Name="dataGrid" DefaultColumnWidth="90"
ItemsSource="{Binding PatientInfo}" SortingMode="Single" SelectedRow="{Binding SelectedPatient}" SelectionMode="Single"
HeightRequest="600" VerticalOptions="CenterAndExpand" HorizontalOptions="Center" AutoGenerateColumnsMode="None">
<syncfusion:SfDataGrid.Behaviors>
<toolkit:EventToCommandBehavior
EventName="CellDoubleTapped"
Command="{Binding CellDoubleTappedCommand}">
</toolkit:EventToCommandBehavior>
</syncfusion:SfDataGrid.Behaviors>
<syncfusion:SfDataGrid.Columns VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<syncfusion:DataGridTextColumn HeaderText="Data" MappingName="Date"/>
<syncfusion:DataGridTextColumn HeaderText="Nome" MappingName="Name" ColumnWidthMode="Fill"/>
<syncfusion:DataGridTextColumn HeaderText="Idade" MappingName="Age"/>
<syncfusion:DataGridTextColumn HeaderText="Genero" MappingName="Gender"/>
<syncfusion:DataGridTextColumn HeaderText="Processo" MappingName="Process"/>
<syncfusion:DataGridTextColumn HeaderText="Diagnostico" MappingName="Diagnostic" ColumnWidthMode="Fill"/>
<syncfusion:DataGridTextColumn HeaderText="Alta" MappingName="Discharge" ColumnWidthMode="LastColumnFill"/>
</syncfusion:SfDataGrid.Columns>
<syncfusion:SfDataGrid.DefaultStyle>
<syncfusion:DataGridStyle HeaderRowBackground="#b2cbc8" HeaderRowTextColor="Black" />
</syncfusion:SfDataGrid.DefaultStyle>
</syncfusion:SfDataGrid>
</VerticalStackLayout>
</ContentPage>
Each view has a xaml.cs where I bind the page to the view model:
namespace PatientAppMultiPlatf.Views;
public partial class DashboardPage : ContentPage
{
public DashboardPage(DashboardViewModel viewModel)
{
InitializeComponent();
BindingContext = viewModel;
}
}
I'm using MVVM architecture. What is the best method to access the ObservableCollection that is being binded?
答案1
得分: 3
在BaseViewModel
中,将以下部分进行更改:
private ObservableCollection<Patient> patientInfo;
更改为:
protected ObservableCollection<Patient> patientInfo;
英文:
In the BaseViewModel
, change
[ObservableProperty]
private ObservableCollection<Patient> patientInfo;
to
[ObservableProperty]
protected ObservableCollection<Patient> patientInfo;
答案2
得分: 1
ObservableCollections 不是 ObservableProperties。
对于集合本身的更改足以通知任何更改。
如果我担心将其设置为其他内容,通常会这样做:
public ObservableCollection MyProperty {get;} = new();
此外,我没有看到您的 x:DataType 在任何地方。为什么没有设置它,以及为什么您的 VisualElement 有名称?
编辑:我不确定我是否足够强调“PUBLIC”这个词,所以我想再次指出。
英文:
ObservableCollections are not ObservableProperties.
The change to the collection itself is more than enough to notify any changes.
If I am concerned about setting it to something else, I usually do this:
**public** ObservableCollection MyProperty {get;} = new();
Also, I do not see anywhere your x:DataType. Why are you not setting it, and why is your VisualElement named?
Edit: I am not sure I put enough stress on the word PUBLIC, so I want to point it out again here.
答案3
得分: 0
根据您的代码,我创建了一个演示,它可以从继承自父类(BaseViewModel
)属性的PatientInfo
中移除项目。您可以参考以下代码:
BaseViewModel.cs
public partial class BaseViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<Patient> patientInfo;
public BaseViewModel()
{
PopulateObservableCollection();
}
public void PopulateObservableCollection()
{
PatientInfo = new ObservableCollection<Patient>();
try
{
PatientInfo.Add(new Patient { Id = 01, Name = "test1" });
PatientInfo.Add(new Patient { Id = 02, Name = "test2" });
PatientInfo.Add(new Patient { Id = 03, Name = "test3" });
}
catch (Exception)
{ }
}
}
public class Patient
{
public int Id { get; set; }
public string Name { get; set; }
}
EditingViewModel.cs
public partial class EditingViewModel : BaseViewModel
{
[RelayCommand]
private async Task Delete()
{
try
{
// 从可观察集合中移除对象
// 这里我可以从父类`BaseViewModel`的`PatientInfo`中移除项目
PatientInfo.RemoveAt(0);
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("应用", ex.ToString(), "退出");
}
finally
{
}
}
}
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"
xmlns:MauiMvvmApp="clr-namespace:MauiMvvmApp226"
x:Class="MauiMvvmApp226.MainPage">
<ContentPage.BindingContext>
<MauiMvvmApp:EditingViewModel></MauiMvvmApp:EditingViewModel>
</ContentPage.BindingContext>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Start">
<ListView ItemsSource="{Binding PatientInfo}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Id}"
Detail="{Binding Name}"
TextColor="#f35e20"
DetailColor="#503026" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
Command="{Binding DeleteCommand}"
x:Name="CounterBtn"
Text="点击我"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
英文:
Based on your code,I created a demo and it could remove the item from PatientInfo
which inherits from the properties of the parent class( BaseViewModel
)
You can refer to the following code:
BaseViewModel.cs
public partial class BaseViewModel: ObservableObject
{
[ObservableProperty]
private ObservableCollection<Patient> patientInfo;
public BaseViewModel()
{
PopulateObservableCollection();
}
public void PopulateObservableCollection()
{
PatientInfo = new ObservableCollection<Patient>();
try
{
PatientInfo.Add(new Patient { Id = 01, Name="test1"});
PatientInfo.Add(new Patient { Id = 02, Name = "test2" });
PatientInfo.Add(new Patient { Id = 03, Name = "test3" });
}
catch (Exception)
{ }
}
}
public class Patient
{
public int Id { get; set; }
public string Name { get; set; }
}
EditingViewModel.cs
public partial class EditingViewModel : BaseViewModel
{
//[ObservableProperty] private Patient patient;
[RelayCommand]
private async Task Delete()
{
try
{
//Removing object from observable collection
//here I could remove the item from PatientInfo from parent class `BaseViewModel `
PatientInfo.RemoveAt(0);
}
catch (Exception ex)
{
await Shell.Current.DisplayAlert("Aplicaçao", ex.ToString(), "Sair");
}
finally
{
}
}
}
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"
xmlns:MauiMvvmApp="clr-namespace:MauiMvvmApp226"
x:Class="MauiMvvmApp226.MainPage">
<ContentPage.BindingContext>
<MauiMvvmApp:EditingViewModel></MauiMvvmApp:EditingViewModel>
</ContentPage.BindingContext>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Start">
<ListView ItemsSource="{Binding PatientInfo}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Id}"
Detail="{Binding Name}"
TextColor="#f35e20"
DetailColor="#503026" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
Command="{ Binding DeleteCommand}"
x:Name="CounterBtn"
Text="Click me"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentPage>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论