wpf 使用ViewModel在xaml中显示列表

zf2sa74q  于 2023-06-24  发布在  其他
关注(0)|答案(3)|浏览(171)

我有一个名为“UserControllerIo”的用户控件,这是它的内容:

public ObservableCollection<string> Messages { get; set; }
        public UserControllerIo()
        {
            Messages = new ObservableCollection<string>();
            InitializeComponent();
            IoComponentViewModel.Instance = new IoComponentViewModel();
            Label1.DataContext = IoComponentViewModel.Instance;
            Messages.Add(Label1.Text);
        }

我在xml中使用它,如下所示:

<Grid>
        <Label>
            <TextBlock x:Name="Label1" TextWrapping="WrapWithOverflow"
                       Text="{Binding Path=XState, Mode=OneWay}">
            </TextBlock>
        </Label>
         <ListView 
             x:Name="ListView"
                 ItemsSource="{Binding Messages}" />   
    </Grid>

我有一个用于此控件的视图模型:

class IoComponentViewModel : INotifyPropertyChanged
    {
        public static IoComponentViewModel Instance { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private string _xState;

        public string XState
        {
            get { return _xState; }
            set
            {
                _xState = value;
                OnPropertyChanged($"XState");
            }
        }

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

我在另一个类上调用来填充列表,如下所示:

case x:
IoComponentViewModel.Instance.XState = msg;
break;

我的问题是,它没有显示在我的列表视图,虽然我可以看到它在我的标签。我如何才能做到这一点?

bqjvbblv

bqjvbblv1#

我不知道从提供的代码中我对您的任务理解了多少,但是请看这个实现变体。

IoComponentViewModel

public class IoComponentViewModel : INotifyPropertyChanged
{
    public static IoComponentViewModel Instance { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    private string _xState;

    public string XState
    {
        get { return _xState; }
        set
        {
            if (_xState == value)
                return;

            XStates.Add(_xState = value);
            OnPropertyChanged($"XState");
            
        }
    }

    public ObservableCollection<string> XStates { get; } = new ObservableCollection<string>();

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML

<Grid x:Name="PART_Grid">
    <Grid.DataContext>
        <local:IoComponentViewModel/>
    </Grid.DataContext>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <!--<Label>-->
        <TextBlock x:Name="Label1" TextWrapping="WrapWithOverflow"
                   Text="{Binding XState, Mode=OneWay}">
        </TextBlock>
    <!--</Label>-->
    <ListView Grid.Row="1"
         x:Name="ListView"
             ItemsSource="{Binding XStates}" />
</Grid>

代码隐藏

//public ObservableCollection<string> Messages { get; set; }
    public UserControllerIo()
    {
        //Messages = new ObservableCollection<string>();
        InitializeComponent();
        // IoComponentViewModel.Instance = new IoComponentViewModel();
        //Label1.DataContext = IoComponentViewModel.Instance;
        IoComponentViewModel.Instance = (IoComponentViewModel)PART_Grid.DataContext;
        //Messages.Add(Label1.Text);
    }
niknxzdl

niknxzdl2#

我最初误解了这个问题。有两个问题。您的列表没有绑定到视图模型,因此您需要一个元素引用。

<UserControl x:Class="StackOverflow.UserControllerIo"
         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:local="clr-namespace:StackOverflow"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800"
         x:Name="MyUserControl"
         >
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Label>

    <TextBlock Foreground="Black" x:Name="Label1" TextWrapping="WrapWithOverflow"
               Text="{Binding Path=XState, Mode=OneWay}">
    </TextBlock>
    </Label>

    <ListView  Grid.Row="1"
        x:Name="ListView"
        ItemsSource="{Binding Messages, ElementName=MyUserControl}" >

    </ListView>
</Grid>

其次,在您将Label1.Text添加到数据绑定的时候,它还没有准备好。因此,在读取文本之前,您需要等待绑定,例如在load事件中,如下所示:

public partial class UserControllerIo : UserControl
{
    public ObservableCollection<string> Messages { get; set; }
    public UserControllerIo()
    {
        Messages = new ObservableCollection<string>();
        InitializeComponent();
        IoComponentViewModel.Instance = new IoComponentViewModel();
        Label1.DataContext = IoComponentViewModel.Instance;

        IoComponentViewModel.Instance.XState = "Something";
        

        Loaded += UserControllerIo_Loaded;

    }
    private void UserControllerIo_Loaded(object sender, RoutedEventArgs e)
    {
        Messages.Add(Label1.Text);
    }
}
sirbozc5

sirbozc53#

编辑:
我的第一个测试误导了我,通过使用int属性来测试在运行时向List添加值。ObservableCollection无论如何都会更新!

问题在于如何声明Messages属性。如果控件上有一个属性,则它需要是一个依赖属性来通知UI。
替换

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

public ObservableCollection<string> Messages
{
  get { return (ObservableCollection<string>)GetValue(MessagesProperty); }
  set { SetValue(MessagesProperty, value); }
}

public static readonly DependencyProperty MessagesProperty =
    DependencyProperty.Register("Messages", typeof(ObservableCollection<string>), typeof(UserControllerIo), new PropertyMetadata(null));

你应该没事的

你可以在你的UserControl类上实现INotifyPropertyChanged。
别忘了维护@Clemens关于绑定的评论!!!
ItemsSource="{Binding Messages, RelativeSource={RelativeSource AncestorType=UserControl}}

相关问题