【问题标题】:Best approach to add an item to a databound Listbox using MVVM pattern?使用 MVVM 模式将项目添加到数据绑定列表框的最佳方法?
【发布时间】:2015-03-07 17:46:29
【问题描述】:

我目前在我的 WPF 项目中遇到问题。目前我有一个 Viewmodel,它有一个 Manager(与 repo 通信)。

internal class TicketViewModel
{
    private TicketManager mgr;

    public IEnumerable<Ticket> List { get; set; }


    public TicketViewModel()
    {
        mgr = new TicketManager();
        List = mgr.GetTickets();

    }

}

我已经设法将此列表绑定到我的主窗口中的列表框。下一步是我需要在列表中添加一张额外的票,并将其传递给经理。问题是我需要主窗口中某些控件的两个参数。从 MVVM 的角度来看,我需要使用绑定命令,例如一个与视图模型通信的按钮,因为我的视图模型不能/可能无法访问窗口中的控件。使用参数化的命令是否可以到达这里?

下一个问题是我猜列表框不会更新。这是代码:

<ListBox x:Name="listboxTix" BorderThickness="0" ItemsSource="{Binding List}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Bisque" Background="Beige" BorderThickness="2">
                <StackPanel Width="250">
                    <TextBlock Text="{Binding TicketNumber}" />
                    <TextBlock Text="{Binding Text}" />
                    <TextBlock Text="{Binding State}" />
            </StackPanel>
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

我发现使用CompareableCollection 是去这里的方式,但是在添加新Ticket 后我仍然需要再次阅读所有Ticket。

提前致谢, 咻咻咻

【问题讨论】:

  • 你的意思是你需要一个类似按钮的控件来填充新票吗?
  • 如何获得新票的输入?
  • 我认为您需要将其绑定到observablecollection 而不是Ienumerable
  • @kyle 我有 2 个文本框和一个按钮。该按钮需要将文本框中的内容添加到新的工单中,并且列表应该自动更新。经理有方法:AddTicket(int,string)

标签: c# wpf xaml mvvm


【解决方案1】:

好的,这里是代码。

假设您在 MainWindow 上有三个文本框(因为您有三个文本块。)所以您的 MainWindow.xaml 看起来像

<Window.DataContext>
    <local:MyViewModel/>--set's your viewModel
</Window.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="250*"/>
        <RowDefinition Height="90"/>
        <RowDefinition Height="30"/>
    </Grid.RowDefinitions>
    <ListBox Grid.Row="0" x:Name="listboxTix" BorderThickness="0" ItemsSource="{Binding List}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="Bisque" Background="Beige" BorderThickness="2">
                    <StackPanel Width="250">
                        <TextBlock Text="{Binding TicketNumber}" />
                        <TextBlock Text="{Binding Text}" />
                        <TextBlock Text="{Binding State}" />
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <TextBox x:Name="TicketNumber" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=Text}" VerticalAlignment="Top" Width="120"/>
    <TextBox x:Name="Text" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=State}" />
    <TextBox x:Name="State" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=TicketNumber}" />
    <Button Content="Button" Command="{Binding Path=MainCommand}"  Grid.Row="2"/>

</Grid>

我假设您有一个名为 class Ticket 的类,其中包含这三个成员

Class Ticket
{
    public int TicketNumber { get; set; }
    public string Text { get; set; }
    public string State { get; set; }
}

现在在 TicketManager 类中,我们用一些虚拟数据填充它

 class TicketManager
{
    ObservableCollection<Ticket> tl = new ObservableCollection<Ticket>();
    internal ObservableCollection<Ticket> GetTickets()
    {
        tl.Add(new Ticket() { State = "State1", Text = "Text1", TicketNumber = 1 });
        tl.Add(new Ticket() { State = "State2", Text = "Text2", TicketNumber = 2 });
        tl.Add(new Ticket() { State = "State3", Text = "Text3", TicketNumber = 3 });

        return tl;
    }

}

在您的主窗口 ViewModel 中,我们将其命名为 MyViewModel.cs

class MyViewModel:INotifyPropertyChanged
{
    private TicketManager mgr;
    public ObservableCollection<Ticket> List { get; set; }

    private string text;
    private string state;
    private int ticketNumber;

    private readonly DelegateCommand<object> MyButtonCommand;
    public Class1()
    {
        mgr = new TicketManager();
        List = mgr.GetTickets();
        MyButtonCommand = new DelegateCommand<object>((s) => { AddListToGrid(text, state, ticketNumber); }, (s) => { return !string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(state); });

    }

    private void AddListToGrid(string text, string state, int ticketNumber)
    {
        List.Add(new Ticket() {Text=text,State=state,TicketNumber=ticketNumber });
    }

    public DelegateCommand<object> MainCommand
    {
        get
        {
            return MyButtonCommand;
        }
    }

    public string Text
    {
        get
        {
            return text;
        }
        set
        {
            text = value;
            OnPropertyChanged("Text");
            MyButtonCommand.RaiseCanExecuteChanged();
        }
    }

    public string State
    {
        get
        {
            return state;
        }
        set
        {
            state = value;
            OnPropertyChanged("State");
            MyButtonCommand.RaiseCanExecuteChanged();
        }
    }

    public int TicketNumber
    {
        get
        {
            return ticketNumber;
        }
        set
        {
            ticketNumber = value;
            OnPropertyChanged("TicketNumber");
            MyButtonCommand.RaiseCanExecuteChanged();
        }
    }

    private void OnPropertyChanged(string p)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(p));
    }


    public event PropertyChangedEventHandler PropertyChanged;
}

你可以随意修改代码

这个 ViewModel 实现了一些从 MVVM 角度来看非常重要的东西

1) INotifyPropertyChanged

2)WPF Delegate Command

P.S: 代码经过测试,按预期运行

【讨论】:

    【解决方案2】:

    不要挂断MVVM,它只是将数据与视图分离,模型在两者之间共享,大部分业务逻辑(在共享组件上)应在 VM 上执行;它不是一种宗教,只是一个三层数据系统。 恕我直言

    如果您的按钮需要执行操作,请让它调用(很可能在后面的代码中)对 VM 上的一个方法进行调用,该方法处理业务逻辑,使用新项目更新列表并通知经理.

    我会将相关列表绑定到ObservableCollection,它可以在插入/删除项目时发出通知。

    【讨论】:

    • 感谢您的评论,我有一些问题。在我向经理添加票后调用 List = mgr.getTickets() 是一种干净的方法吗?如何在后面的代码中通知经理? atm 后面的代码中唯一的代码是声明数据上下文
    • @Hicy 是的,我就是这样做的。有关示例,请参阅我的博客文章 Xaml: ViewModel Main Page Instantiation and Loading Strategy for Easier Binding.
    • @Hicy 如果后面的代码在数据上下文中有管理器(我通常也保留一个属性以便于访问),只需在 VM 上调用一个方法,该方法将在后面的代码。
    • 这是我的代码隐藏中唯一的代码:Datacontext = new TicketViewModel();所以我可以在我的代码隐藏中保留一个属性视图模型?这里还需要使用命令吗?
    • @Hicy 可以添加任何想要的内容。请记住,Xaml 最终被编译成一个“代码隐藏”,该代码隐藏随后与编写在对象上的代码隐藏相结合。一切,我的意思是 Xaml 中的一切都可以在后面的代码中完成;所以不要纠结于代码隐藏中的内容和没有的内容。只需根据需要添加方法。记住将业务逻辑放在 VM 上并从视图的代码隐藏中调用它。这将业务逻辑与视图分开,并导致更好的开发/维护。 MVVM 我们简单来说就是一个三层的数据系统。不多也不少。 HTH
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-09
    • 2010-10-07
    • 1970-01-01
    相关资源
    最近更新 更多