【问题标题】:Editing items from a list within one form - MVVM approach在一个表单中编辑列表中的项目 - MVVM 方法
【发布时间】:2015-11-04 09:49:06
【问题描述】:

编辑2: 我正在做一些项目,我的 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 下拉菜单的项目在更改名称文本框的值时不会更改。另外,请让我知道此示例中的一般方法是否正确。干杯。

【问题讨论】:

    标签: c# .net wpf mvvm


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      好吧,看来我把它弄得太复杂了。将 Thing 类的属性映射到 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);
          }
      }
      

      }

      主视图:

      <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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-05
        • 2021-12-25
        • 2022-07-07
        • 1970-01-01
        • 1970-01-01
        • 2016-06-30
        相关资源
        最近更新 更多