.net 我要从两个不同视图绑定数据

e4yzc0pl  于 2022-11-19  发布在  .NET
关注(0)|答案(2)|浏览(127)

我有两个视图,一个是父视图(Ics视图),我在其中添加了子视图(侧视图)。在IcsView中,我已经为按钮添加文件和添加文件夹编写了代码,现在我想在子视图(即侧视图)中绑定该数据。
产品型号:

public partial class Data:ObservableObject
{
    public string filePath { get; set; }
    public String FilePath
    {
        get { return filePath; }    
        set { filePath = value; }
    }
}

集成电路XAML:

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         x:Class="ICSViewer.MVVM.View.IcsView"
         xmlns:v="clr-namespace:ICSViewer.MVVM.View"
         xmlns:model="clr-namespace:ICSViewer.MVVM.ViewModel"
         >
<ContentPage.BindingContext>
    <model:IcsViewModel/>
</ContentPage.BindingContext>
<ContentPage.MenuBarItems>

<v:SideView Grid.Column="0" Grid.RowSpan="3" />
IcsView代码隐藏:

private readonly IFolderPicker _folderPicker;
public static List<Data> Items = new List<Data>();
public IcsView(IFolderPicker folderPicker)
{
    InitializeComponent();
    _folderPicker = folderPicker;
}

private async void Add_File(object sender, EventArgs e)
{

    var CustomFileType = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<String>>
    {
        { DevicePlatform.WinUI, new[]{"ics"} },
    });
    var results = await FilePicker.PickMultipleAsync(new PickOptions
    {
        FileTypes = CustomFileType,
    });
  
    foreach (var result in results)
    {

        FileInfo fileInfo = new FileInfo(result.FullPath);

        double size = fileSize(fileInfo);
        bool fileExist = false;
        foreach (Data item in Items)
        {
            if (item.FilePath.Equals(result.FullPath))
            {
                fileExist = true;
                break;
            }

        }
        if (!fileExist)
        {
            Items.Add(new Data
            {
                FilePath = result.FullPath,
                
            });
        }
        else
        {
        
            await DisplayAlert("Alert", "File already exist!", "Ok");
        }
    }
    

}

public void getFiles(FileInfo path)
{
    double size = fileSize(path);
    bool fileExist = false;
    foreach (Data item in Items)
    {
        if (item.FilePath.Equals(path.FullName))
        {
            fileExist = true;
            break;
        }
    }
    if (!fileExist)
    {
        Items.Add(new Data
        {
            FilePath = path.FullName,
           
        });
    }
  
}
public double fileSize(FileInfo file)
{
    double fileSize = file.Length;

    double sizeMb = fileSize * 0.000001;
    return Math.Round(sizeMb, 2);
}

侧视图

<StackLayout>
    <Label  Text="{Binding SideModel.HeaderText}" FontSize="18" FontAttributes="Bold" Padding="5" />
    <CollectionView ItemsSource="{Binding Source={x:Reference childView }, Path=icsViewModel.Items}">
        <CollectionView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Label Text="{Binding FilePath}"/>
                </Grid>
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>

</StackLayout>

这是侧视图后面的代码

public string FilePath
{
    get
    {
        string value = (String)GetValue(FilePathProperty);
        return value;
    }
    set
    {
        SetValue(FilePathProperty, value);
    }
}
static void OnFileNameChanged(BindableObject bindable, object oldValue, object newValue)
{
    Console.WriteLine("-----------------> " + newValue);
}
public static readonly BindableProperty MyViewModelProperty =
       BindableProperty.Create(
nameof(IcsViewModel),
           typeof(IcsViewModel),
           typeof(SideView),
null);
public static readonly BindableProperty FilePathProperty = BindableProperty.Create(nameof(File)
   , typeof(Data)
   , typeof(SideView), defaultBindingMode: BindingMode.TwoWay, propertyChanged: OnFileNameChanged);

public IcsViewModel icsViewModel
{
    set { SetValue(MyViewModelProperty, value); }
    get { return (IcsViewModel)GetValue(MyViewModelProperty); }
}
public SideView()
{
    InitializeComponent();
    
}

更新的视图模型:我还没有在这里添加set方法,我也不知道我应该怎么在这里添加这个属性,所以你能看一遍吗?
名称空间DataBinding.MVVM.ViewModel {内部局部类ParentViewModel:信息属性已更改{

public ObservableCollection<Data> Item { get; set; }
    public ParentViewModel()
        {
            Item = new ObservableCollection<Data>();
        }
    [RelayCommand]
    public async void Add_File()
    {
        var CustomFileType = new FilePickerFileType(new Dictionary<DevicePlatform, IEnumerable<String>>
    {
        { DevicePlatform.WinUI, new[]{"ics"} },
    });
        var results = await FilePicker.PickMultipleAsync(new PickOptions
        {
            FileTypes = CustomFileType,
        });

        foreach (var result in results)
        {
            FileInfo fileInfo = new FileInfo(result.FullPath);
            double size = fileSize(fileInfo);
            bool fileExist = false;
            foreach (Data item in Item)
            {
                if (item.name.Equals(result.FullPath))
                {
                    fileExist = true;
                    break;
                }
            }
            if (!fileExist)
            {
                Item.Add(new Data
                {
                    name = result.FullPath,
                });
            }
            else
            {
                Item = Item;
            }
        }
    }

    public void getFiles(FileInfo path)
    {
        double size = fileSize(path);
        bool fileExist = false;
        foreach (Data item in Item)
        {
            if (item.name.Equals(path.FullName))
            {
                fileExist = true;
                break;
            }
        }
        if (!fileExist)
        {
            Item.Add(new Data
            {
                name = path.FullName,

            });
        }

    }
    public double fileSize(FileInfo file)
    {
        double fileSize = file.Length;
        double sizeMb = fileSize * 0.000001;
        return Math.Round(sizeMb, 2);
    }

    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;
        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

}
如果选择特定文件,则希望在侧视图中填充该文件或文件夹,但无法将数据从IcsView.xaml.cs绑定到sideview.xaml.cs

4c8rllxm

4c8rllxm1#

我基于MVVM实现了你的功能。它在我这边工作。
可以参考下面的代码:

我的视图模型.cs

public class MyViewModel: INotifyPropertyChanged 
    {

        public int index = 0;
        public ObservableCollection<Data> Items { get; set; }

        private string _testName;
        public string TestName
        {
            set { SetProperty(ref _testName, value); }
            get { return _testName; }
        }

        public ICommand ChangeNameCommand => new Command(changeMethod);

        public ICommand PickDataCommand => new Command(addItemMethod);

        private void addItemMethod(object obj)
        {
            Add_File();
        }

        private void changeMethod()
        {
            index++;

            TestName = "change data" + index;

            Items.Add(new Data { FilePath= TestName });
        }

        public MyViewModel()
        {
            TestName = "test string";

            Items = new ObservableCollection<Data>();
        }

        public async void Add_File()
        {
            var results = await FilePicker.PickMultipleAsync(new PickOptions
            {
                //FileTypes = customFileType
            });

            foreach (var result in results)
            {
                bool fileExist = false;

                foreach (Data item in Items) {
                    if (item != null) {
                        if (result.FileName.Equals(item.FileName))  // here I don't suggest compare `FilePath`,sometimes, if we select the same image, the FullPath maybe different  (result.FullPath.Equals(item.FilePath))
                        {
                            fileExist = true;
                            break;
                        }
                        else {
                            continue;
                        }
                    }
                }

                if (!fileExist) { 
                   Items.Add( new Data {  FilePath= result.FullPath,FileName= result.FileName });
                }
            }

        }

        bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
        {
            if (Object.Equals(storage, value))
                return false;
            storage = value;
            OnPropertyChanged(propertyName);
            return true;
        }
        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

数据.cs

public class Data 
{
    public string FilePath { get; set; }

    public string FileName { get; set; }
}

子视图.xaml

<?xml version="1.0" encoding="utf-8" ?> 
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiContentViewApp.ChildView"
             x:Name="TestControlView"
             >
    <VerticalStackLayout>
        <Label   Text="{Binding Source={x:Reference TestControlView}, Path=YourName}"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

        <ListView ItemsSource="{Binding Source={x:Reference TestControlView}, Path=myViewModel.Items }" HasUnevenRows="True" >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Label Text="{Binding FileName}" TextColor="#f35e20"  VerticalOptions="Center"/>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </VerticalStackLayout>
</ContentView>

子视图.xaml.cs

public partial class ChildView : ContentView 
{
    public String YourName
    {
        get
        {
            String value = (String)GetValue(YourNameProperty);
            return value;
        }
        set
        {
            SetValue(YourNameProperty, value);
        }
    }

    public static readonly BindableProperty YourNameProperty = BindableProperty.Create(nameof(YourName)
    , typeof(String)
    , typeof(ChildView), defaultBindingMode: BindingMode.TwoWay, propertyChanged: OnYourNameChanged);

    static void OnYourNameChanged(BindableObject bindable, object oldValue, object newValue)
    {
        Console.WriteLine("-----------------> " + newValue);
    }

    //add MyViewModelProperty
    public static readonly BindableProperty myViewModelProperty =
        BindableProperty.Create(
            nameof(myViewModel),
            typeof(MyViewModel),
            typeof(ChildView),
            null);

    public MyViewModel myViewModel
    {
        set { SetValue(myViewModelProperty, value); }
        get { return (MyViewModel)GetValue(myViewModelProperty); }
    }

    public ChildView()
      {
            InitializeComponent();
      }
}

主页面.xaml.cs

public partial class MainPage : ContentPage 
{
    public MainPage()
      {
            InitializeComponent();

      }
}

主页.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:mauiapp="clr-namespace:MauiContentViewApp"
             x:Class="MauiContentViewApp.MainPage"
             x:Name="mainpage"
             >

    <ContentPage.BindingContext>
        <mauiapp:MyViewModel></mauiapp:MyViewModel>
    </ContentPage.BindingContext>

    <ScrollView>
        <VerticalStackLayout>
            <Label Text="{Binding Name}" IsVisible="false"></Label>
            
            <mauiapp:ChildView YourName="{Binding TestName}" myViewModel="{Binding Path=BindingContext, Source={x:Reference mainpage}}"></mauiapp:ChildView>

            <Button  Text="Change"  Command="{Binding ChangeNameCommand}" IsVisible="false"></Button>

            <Button Text="Add file" Command="{Binding PickDataCommand}"></Button>
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

备注:

1.请在文件AndroidManifest.xml中添加权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

2.实际上,要实现这样的功能,并不需要单独新建一个ContentViewChildView),增加代码的难度,直接将ListView添加到父页面即可。
您可以在此处查看实现此功能的另一种方法:无法检测到活动窗口。请确保已在Application类中调用了Init。

icomxhvb

icomxhvb2#

我有两个视图,一个是父视图(Ics视图),我在其中添加了子视图(侧视图)
如果side View包含在父视图(Ics view)中,常用的方法是引用父视图的视图模型中的父变量。
在这种情况下,可以在side View中创建BindableProperty
我创建了一个简单的演示来模拟这个问题(我的父视图是MainPage,子视图是ChildView)。
可以参考下面的代码:
MainPage.xaml.cs

public partial class MainPage : ContentPage 
{
      public MainPage()
      {
            InitializeComponent();

            this.BindingContext =  new MyViewModel();
      }
}

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:mauiapp="clr-namespace:MauiContentViewApp"
             x:Class="MauiContentViewApp.MainPage"
             x:Name="mainpage"
             >

    <ScrollView>
        <VerticalStackLayout>
            <Label Text="{Binding Name}"></Label>
            <mauiapp:ChildView YourName="{Binding TestName}" MyViewModel="{Binding Path=BindingContext, Source={x:Reference mainpage}}"></mauiapp:ChildView>
            
            
            <Button Command="{Binding ChangeNameCommand}"></Button>
        </VerticalStackLayout>
    </ScrollView>
</ContentPage>

MyViewModel.cs

public class MyViewModel: INotifyPropertyChanged 
{
    public string Name { get; set; }

    public int index = 0;

    public ObservableCollection<string> Items { get; set; }

    private string _testName;
    public string TestName
    {
        set { SetProperty(ref _testName, value); }
        get { return _testName; }
    }

    public ICommand ChangeNameCommand => new Command(changeMethod);

    private void changeMethod()
    {
        index++;

        TestName = "change data" + index;

        Items.Add(TestName);
    }

    public MyViewModel()
    {
        Name = "abc";
        TestName = "test string";

        Items = new ObservableCollection<string>();
    }
    bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Object.Equals(storage, value))
            return false;
        storage = value;
        OnPropertyChanged(propertyName);
        return true;
    }
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

ChildView.xaml

<?xml version="1.0" encoding="utf-8" ?> 
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MauiContentViewApp.ChildView"
             x:Name="TestControlView"
             >
    <VerticalStackLayout>
        <Label   Text="{Binding Source={x:Reference TestControlView}, Path=YourName}"
            VerticalOptions="Center" 
            HorizontalOptions="Center" />

        <ListView ItemsSource="{Binding Source={x:Reference TestControlView}, Path=MyViewModel.Items }" >
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Label Text="{Binding .}" TextColor="#f35e20" />
       
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </VerticalStackLayout>
</ContentView>

ChildView.xaml.cs

public partial class ChildView : ContentView 
{
    public String YourName
    {
        get
        {
            String value = (String)GetValue(YourNameProperty);
            return value;
        }
        set
        {
            SetValue(YourNameProperty, value);
        }
    }

    public static readonly BindableProperty YourNameProperty = BindableProperty.Create(nameof(YourName)
    , typeof(String)
    , typeof(ChildView), defaultBindingMode: BindingMode.TwoWay, propertyChanged: OnYourNameChanged);

    static void OnYourNameChanged(BindableObject bindable, object oldValue, object newValue)
    {
        Console.WriteLine("-----------------> " + newValue);
    }

    //add MyViewModelProperty
    public static readonly BindableProperty MyViewModelProperty =
        BindableProperty.Create(
            nameof(MyViewModel),
            typeof(MyViewModel),
            typeof(ChildView),
            null);

    public MyViewModel MyViewModel
    {
        set { SetValue(MyViewModelProperty, value); }
        get { return (MyViewModel)GetValue(MyViewModelProperty); }
    }

    public ChildView()
      {
            InitializeComponent();
      }
}

备注:

1.在这里,我为MainPage创建了一个视图模型MyViewModel,在视图模型中,我为ChildView创建了一个变量TestName,并为MyViewModel实现了接口INotifyPropertyChanged。一旦修改了TestName的值,UI将在ChildView上自动刷新。
2.如果要在ChildView中添加一个ListView,可以在ChildView.xaml.cs中添加一个新的BindableProperty MyViewModelProperty,在ViewModel MyViewModel中添加一个ObservableCollection Items

public ObservableCollection<string> Items { get; set; }

更新日期:

我看不到你的应用程序的其他代码,但从你张贴的代码,我发现有几个问题。
1.you 可以重新检查您是否已为页面IcsView设置了BindingContext
例如:

public partial class MainPage : ContentPage 
   {
      public MainPage()
      {
            InitializeComponent();

            this.BindingContext =  new MyViewModel();
      }
    }

2.you 可以调试以查看您是否在ViewModel中获得了Items的更新数据。
您还需要更改代码:

public static List<Data> Items = new List<Data>();

public   ObservableCollection<Data> Items { get; set; }

并在视图模型的构造函数中初始化它。

Items = new ObservableCollection<Data>();

3.您的自定义属性icsViewModel使用不正确。
可系结属性的命名惯例是,可系结属性识别码必须符合Create方法中指定的属性名称,并附加“Property”。如需详细信息,请核取:建立可系结属性。
可以参考下面的代码:

//add myViewModelProperty ,it should be `myViewModel`+`Property`.
public static readonly BindableProperty myViewModelProperty =
    BindableProperty.Create(
        nameof(myViewModel),  //here it should be the same as the following property `myViewModel`
        typeof(MyViewModel),
        typeof(ChildView),
        null);

public MyViewModel myViewModel
{
    set { SetValue(myViewModelProperty, value); }
    get { return (MyViewModel)GetValue(myViewModelProperty); }
}

相关问题