从一个表单中的列表编辑项目 - MVVM方法

时间:2015-11-04 09:49:06

标签: c# .net wpf mvvm

EDIT2: 我正在处理一些项目,其中我的ComboBox包含一个可编辑元素列表。选择其中一个元素后,这些元素可以编辑。我想要的是当我取消选择时,所选元素的编辑属性会被记住,并且ComboBox下拉列表会使用新元素进行更新。说明。以下是此示例的示例:

Main Window

现在切换后会记住更改,但下拉列表仍包含旧名称,并且不会自动更新:

Dropdown List

这是代码。

MainWindow.xaml

<Window x:Class="MVVMEditComboBoxItemsSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MVVMEditComboBoxItemsSample"
        mc:Ignorable="d"
        Title="MVVM ComboBox edit sample" Height="372.52" Width="415.214">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50*"></RowDefinition>
            <RowDefinition Height="81*"/>
            <RowDefinition Height="26*"/>
            <RowDefinition Height="45*"/>
            <RowDefinition Height="26*"/>
            <RowDefinition Height="44*"/>

        </Grid.RowDefinitions>
        <ComboBox Grid.Row="0" Margin="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" ItemsSource="{Binding Path=Things}" SelectedItem="{Binding Path=SelectedThing, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"></ComboBox>
        <StackPanel Grid.Row="1" Margin="10">
            <Button Command="{Binding Path=AddCommand}">Add Item</Button>
            <Button Command="{Binding Path=CloneCommand}">Clone Item</Button>
            <Button Command="{Binding Path=DeleteCommand}">Delete Item</Button>
        </StackPanel>
        <Label Grid.Row="2" Margin="0"  >Name</Label>
        <TextBox Grid.Row="3" HorizontalAlignment="Stretch" Margin="10"  VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Text="{Binding Path=Name}"/>
        <Label Grid.Row="4" Margin="0"  >Price</Label>
        <TextBox Grid.Row="5" HorizontalAlignment="Stretch" Margin="10" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Text="{Binding Path=Price}"/>

    </Grid>
</Window>

MainViewModel.cs

using MVVMEditComboBoxItemsSample.MockModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace MVVMEditComboBoxItemsSample
{
    class MainViewModel : ViewModelBase
    {
        private ObservableCollection<Thing> things;
        private Thing selectedThing;

        private ICommand addCommand;
        private ICommand cloneCommand;
        private ICommand deleteCommand;

        public MainViewModel()
        {
            Things = new ObservableCollection<Thing>(ThingDataManager.Instance.GetThings());
            SelectedThing = Things.FirstOrDefault();
        }

        public ObservableCollection<Thing> Things
        {
            get
            {
                return things;
            }

            set
            {
                things = value;
                OnPropertyChanged(nameof(Things));
            }
        }

        public Thing SelectedThing
        {
            get
            {
                return selectedThing;
            }

            set
            {
                selectedThing = value;
                OnPropertyChanged(nameof(SelectedThing));
                OnPropertyChanged(nameof(Name));
                OnPropertyChanged(nameof(Price));
                //OnPropertyChanged(nameof(Things));
            }
        }

        public string Name
        {
            get
            {
                if (SelectedThing != null)
                {
                    return SelectedThing.Name;
                }
                return null;
            }

            set
            {
                SelectedThing.Name = value;
                OnPropertyChanged(nameof(Name));
            }
        }

        public string Price
        {
            get
            {
                if (SelectedThing != null)
                {
                    return SelectedThing.Price;
                }
                return null;
            }

            set
            {
                SelectedThing.Price = value;
                OnPropertyChanged(nameof(Price));
            }
        }

        public ICommand AddCommand
        {
            get
            {
                if(addCommand==null)
                {
                    addCommand = new CommandBase(i => AddItem(), null);
                }
                return addCommand;
            }
        }

        public ICommand CloneCommand
        {
            get
            {
                if(cloneCommand==null)
                {
                    cloneCommand = new CommandBase(i => CloneItem(), null);
                }
                return cloneCommand;
            }
        }

        public ICommand DeleteCommand
        {
            get
            {
                if(deleteCommand==null)
                {
                    deleteCommand = new CommandBase(i => DeleteItem(), null);
                }
                return deleteCommand;
            }
        }

        public void AddItem()
        {
            Thing newThing = new Thing();
            Things.Add(newThing);
            SelectedThing = newThing;
        }

        public void CloneItem()
        {
            Thing clonedThing = new Thing();
            clonedThing.Name = SelectedThing.Name;
            clonedThing.Price = SelectedThing.Price;
            Things.Add(clonedThing);
            SelectedThing = clonedThing;
        }

        public void DeleteItem()
        {
            Thing tempThing = new Thing();
            tempThing = SelectedThing;
            if (Things.IndexOf(SelectedThing) != 0)
            {
                SelectedThing = Things.FirstOrDefault();
            }
            else if (Things.Count==1)
            {
                SelectedThing = null;
            }
            else
            {
                SelectedThing = Things[1];
            }

            Things.Remove(tempThing);
        }
    }
}

Thing.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MVVMEditComboBoxItemsSample.MockModel
{
    class Thing
    {
        public string Name { get; set; }
        public string Price { get; set; }

        public override string ToString()
        {
            return Name;
        }
    }
}

ThingDataManager

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MVVMEditComboBoxItemsSample.MockModel
{
    class ThingDataManager
    {
        private static ThingDataManager _instance;

        public static ThingDataManager Instance
        {
            get
            {
                if (_instance==null)
                {
                    _instance = new ThingDataManager();
                }
                return _instance;
            }
        }

        private ThingDataManager()
        {
        }

        public List<Thing> GetThings()
        {
            List<Thing> things = new List<Thing>();
            things.Add(new Thing { Name = "Book", Price = "12$" });
            things.Add(new Thing { Name = "Hammer", Price = "2$" });
            things.Add(new Thing { Name = "Fridge", Price = "1200$" });

            return things;
        }
    }
}

我希望像ViewModelBase和CommandBase这样的其他内容足够自我描述:)。

为什么我的下拉列表没有使用当前的名称更新的任何想法?

编辑: 好的,我在github上传了简化版:

github.com/piotr-napadlek/MVVMEditComboBoxItemsSample

仍然无法正常工作的是,更改“名称”文本框的值时,ComboBox下拉菜单的项目不会发生变化。另外,如果本例中的一般方法是正确的,请告诉我。欢呼声。

2 个答案:

答案 0 :(得分:0)

如果您查看本文中的示例项目,它将为您提供有关MVVM应用程序的良好体系结构的想法。它使用的是Silverlight,它只是WPF的精简版本:

http://www.codeproject.com/Articles/854816/MVVM-Silverlight-Application-with-Entity-Framework

答案 1 :(得分:0)

好的,所以看起来我太复杂了。映射Thing class&#39;我的ViewModel中的另一个属性的属性是多余的。实际上将WPF窗口上的TextBoxes直接映射到SelectedThing.Name和SelectedThing.Price并仅在SelectedThing上调用OnPropertyChanged足以解决我的问题。这是工作版本:

视图模型:

using MVVMEditComboBoxItemsSample.MockModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace MVVMEditComboBoxItemsSample
{
    class MainViewModel : ViewModelBase
    {
        private ObservableCollection<Thing> things;
        private Thing selectedThing;

    private ICommand addCommand;
    private ICommand cloneCommand;
    private ICommand deleteCommand;

    public MainViewModel()
    {
        Things = new ObservableCollection<Thing>(ThingDataManager.Instance.GetThings());
        SelectedThing = Things.FirstOrDefault();
    }

    public ObservableCollection<Thing> Things
    {
        get
        {
            return things;
        }

        set
        {
            things = value;
            OnPropertyChanged(nameof(Things));
        }
    }

    public Thing SelectedThing
    {
        get
        {
            return selectedThing;
        }

        set
        {
            selectedThing = value;
            OnPropertyChanged(nameof(SelectedThing));
        }
    }

    public ICommand AddCommand
    {
        get
        {
            if(addCommand==null)
            {
                addCommand = new CommandBase(i => AddItem(), null);
            }
            return addCommand;
        }
    }

    public ICommand CloneCommand
    {
        get
        {
            if(cloneCommand==null)
            {
                cloneCommand = new CommandBase(i => CloneItem(), i => SelectedThing!=null);
            }
            return cloneCommand;
        }
    }

    public ICommand DeleteCommand
    {
        get
        {
            if(deleteCommand==null)
            {
                deleteCommand = new CommandBase(i => DeleteItem(), i => SelectedThing!=null);
            }
            return deleteCommand;
        }
    }

    public void AddItem()
    {
        Thing newThing = new Thing();
        Things.Add(newThing);
        SelectedThing = newThing;
    }

    public void CloneItem()
    {
        Thing clonedThing = new Thing();
        clonedThing.Name = SelectedThing.Name + " - copy";
        clonedThing.Price = SelectedThing.Price;
        Things.Add(clonedThing);
        SelectedThing = clonedThing;
    }

    public void DeleteItem()
    {
        Thing tempThing = new Thing();
        tempThing = SelectedThing;
        if (Things.IndexOf(SelectedThing) != 0)
        {
            SelectedThing = Things.FirstOrDefault();
        }
        else if (Things.Count==1)
        {
            SelectedThing = null;
        }
        else
        {
            SelectedThing = Things[1];
        }

        Things.Remove(tempThing);
    }
}

}

的MainView:

<Window x:Class="MVVMEditComboBoxItemsSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MVVMEditComboBoxItemsSample"
    mc:Ignorable="d"
    Title="MVVM ComboBox edit sample" Height="372.52" Width="415.214">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="50*"></RowDefinition>
        <RowDefinition Height="81*"/>
        <RowDefinition Height="26*"/>
        <RowDefinition Height="45*"/>
        <RowDefinition Height="26*"/>
        <RowDefinition Height="44*"/>

    </Grid.RowDefinitions>
    <ComboBox Grid.Row="0" Margin="10" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" ItemsSource="{Binding Path=Things}" SelectedItem="{Binding Path=SelectedThing, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" DisplayMemberPath="Name"></ComboBox>
    <StackPanel Grid.Row="1" Margin="10">
        <Button Command="{Binding Path=AddCommand}">Add Item</Button>
        <Button Command="{Binding Path=CloneCommand}">Clone Item</Button>
        <Button Command="{Binding Path=DeleteCommand}">Delete Item</Button>
    </StackPanel>
    <Label Grid.Row="2" Margin="0"  >Name</Label>
    <TextBox Grid.Row="3" HorizontalAlignment="Stretch" Margin="10"  VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Text="{Binding Path=SelectedThing.Name, UpdateSourceTrigger=PropertyChanged}"/>
    <Label Grid.Row="4" Margin="0"  >Price</Label>
    <TextBox Grid.Row="5" HorizontalAlignment="Stretch" Margin="10" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Text="{Binding Path=SelectedThing.Price}"/>

</Grid>