【问题标题】:Understanding passing data from a page to a user control了解将数据从页面传递到用户控件
【发布时间】:2023-03-28 11:05:01
【问题描述】:

我一直在努力解决如何在页面和 UserControl 之间传递数据,并且可以使用一些说明来说明我可能做错了什么。如果我删除代码的数据部分并仅用 TextBlocks 替换它,我知道 UserControl 正在工作。

我知道 NetWorth 正在显示,但就是不明白为什么没有传递 List<Account>。我不知道我在这里做错了什么。

PanelNavigation.xaml

        <!-- Navigation Section -->
        <ScrollViewer HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto" CanContentScroll="True" Grid.Row="1" Margin="0,0.333,0,0" Grid.ColumnSpan="2">
            <UserControls:NavigationPanel DataContext="{Binding Accounts}"/>
        </ScrollViewer>

        <!-- Networth Panel -->
        <Grid Grid.Row="2" Height="40">
            <Border BorderThickness="0,1,0,0" BorderBrush="{StaticResource MenuBarBrush}" Background="{StaticResource BackgroundLightBrush}">
                <Grid Margin="5,5,10,5">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*" />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>

                    <TextBlock Margin="10,1,10,1" FontSize="16" FontWeight="Normal" Grid.Column="0" Foreground="#FF346C9C" Text="Net Worth" />
                    <TextBlock FontSize="16" FontWeight="Normal" Grid.Column="1"
                               HorizontalAlignment="Right" Text="{Binding NetWorth, Converter={StaticResource CurrencyConverter}}"
                               Foreground="{Binding NetWorth, Converter={StaticResource ChangeColor}}"/>
                </Grid>
            </Border>
        </Grid>

PanelNavigation.xaml.cs


using APTest.ViewModels;
using System.Windows.Controls;

namespace APTest.Views
{
    /// <summary>
    /// Interaction logic for PanelNavigation.xaml
    /// </summary>
    public partial class PanelNavigation : Page
    {
        public PanelNavigation()
        {
            InitializeComponent();

            this.DataContext = new VMNavigationPanel(this);

        }
    }
}

NavigationPanel.xaml

<UserControl x:Class="APTest.UserControls.NavigationPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:UserControls="clr-namespace:APTest.UserControls"
             mc:Ignorable="d" 
             d:DesignHeight="800" d:DesignWidth="400">

    <StackPanel>
        <StackPanel>
            <ItemsControl x:Name="DataTest" ItemsSource ="{Binding Accounts}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding TotalBalance}" />
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </StackPanel>
    </StackPanel>

</UserControl>
    

NavigationPanel.xaml.cs

using System.Windows.Controls;

namespace APTest.UserControls
{
    public partial class NavigationPanel : UserControl
    {
        public NavigationPanel()
        {
            InitializeComponent();
        }
    }

最后

VMNavigationPanel.cs

using AccountingPlus.ViewModels;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace APTest.ViewModels
{
    class VMNavigationPanel  : BaseViewModel
    {
        private Page mPage;
        private ObservableCollection<Account> accounts;
        public ObservableCollection<Account> Accounts {
            get => accounts;
            set {
                accounts = value;
                OnPropertyChanged();
            }
        }

        public double NetWorth { get; set; } = 127492.30;

        public VMNavigationPanel(Page page)
        {
            mPage = page;

            Accounts = new ObservableCollection<Account>();

            Account test = new Account();
            test.TotalBalance = 100234.23;

            Accounts.Add(test);
        }
    }

    public class Account
    {
        public double TotalBalance {get; set;}
    }
}

BaseViewModel.cs

using PropertyChanged;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace APTest
{
    [AddINotifyPropertyChangedInterface]
    class BaseViewModel : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged = (Sender, e) => { };

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}

【问题讨论】:

  • Itemssource 应该绑定 Accounts。 Observablecollection 而不是列表。始终在视图模型上实现 inotifypropertychanged 并在 setter 中引发 propertychanged。不要将页面等 ui 元素传递到视图模型中。
  • 如果您不需要像向导那样向前向后导航,则框架和页面会产生开销。 social.technet.microsoft.com/wiki/contents/articles/…
  • @Andy 你能解释一下将 UI 元素(如页面)传递给 ViewModel 是什么意思吗?我有一个带有 UIControl 的页面,它通过 嵌入到 mainWindow 中,仍在争论这是否是一件好事。至于 INotifyPropertyChanged,我实际上有,但将其删除以进行测试并将其放回去没有任何区别,而 ObservableCollection 没有任何区别。
  • @AndyAnd 我还在学习,那么你推荐什么而不是框架/页面。举一个我想要达到的目标的例子。想想带有信息和链接列表的侧边导航。然后,这些链接可以将更多内容打开到主要内容部分。我知道我需要在这里使用一个框架,因为我没有看到任何其他方式来更改该主要内容区域,并且该页面必须具有 UserControls。
  • Vmnavigationpanel 是一个视图模型。它应该完全独立于 ui 工作,并且页面是 ui。我在上面的评论中放了一个链接。这不是随机的。阅读。然后首先谷歌视图模型。取字框。取词页。把它们放在一个盒子里。合上盖子..想想 contentcontrol 和 usercontrol。具有数据类型的数据模板定义了您为视图模型获得的用户界面。

标签: c# wpf xaml user-controls


【解决方案1】:

首先,您需要模型中的属性来绑定对象。不能绑定字段。

这样您的 Account 类应该是这样的:

public class Account
{
    public double TotalBalance { get; set; }

}

还请记住,要在 WPF 中更新 UI,我们需要使用 ObservableCollections。例如,如果您单击一个按钮并将一个项目添加到您的 Accounts 集合中,则该项目将在您的集合中,但在 UI 中,如果您使用 List 集合,您将看不到更新的结果,这就是您需要使用 ObservableCollections 的原因。 https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netcore-3.1

另一件事是您的绑定拼写错误。在您的 NavigationPanel.xaml 中,它应该是 TotalBalance。

<TextBlock Text="{Binding TotalBalnce}" />

这是您的视图模型的工作代码:

我还为您实现了 INotifyPropertyChanged 接口,但没有与任何其他属性一起使用。

class VMNavigationPanel : INotifyPropertyChanged
{

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged<T>(ref T property, T value, [CallerMemberName] string propertyName = null)
    {
        property = value;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private Page mPage;

    public double NetWorth { get; set; } = 127492.30;

    private ObservableCollection<Account> accounts;
    public ObservableCollection<Account> Accounts
    {
        get => accounts;
        set
        {
            accounts = value;
        }
    }

    public VMNavigationPanel(Page page)
    {
        mPage = page;

        Accounts = new ObservableCollection<Account>();

        Account test = new Account();
        test.TotalBalance = 100234.23;

        Accounts.Add(test);
    }

}

public class Account
{
    public double TotalBalance { get; set; }

}

【讨论】:

  • 已经进行了这些更改,属性更改位于基类中,我一开始省略了,但没有区别。我已经按照建议反映了帖子的当前更改,并回到了我开始摆弄之前的内容。你没有做任何事情,我不是唯一一个我做了不同的事情并改变了你所拥有的东西,如果它是 null 来创建集合,get 有一个条件。而不是将它放在构造函数中。我移到构造函数没有任何区别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-27
  • 2011-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多