了解MVVM

时间:2011-06-29 10:10:49

标签: c# wpf mvvm

我试着了解mvvm。 我想从我的电脑上读取制造商,这就是目标。

问题:   - xaml中的标签为空

我的理解:

  • 在ControlElements上绑定ViewModel属性。
  • 使用ObjectDataProvider
  • 从ViewModel创建实例
  • 通过存储库填写ViewModel

我希望有人能帮助我理解mvvm模式。

我的xaml:

<Window x:Class="MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:get="clr-namespace:MVVM"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
      <TabControl Name="tabControl1">
        <TabItem Header="Uebersicht" Name="tabUeberischt">
          <TabItem.Resources>
            <ObjectDataProvider x:Key="OverviewData" ObjectType="{x:Type get:VM_lalala}" MethodName="GetDataFromRep" />
          </TabItem.Resources>

          <DockPanel>
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition Height="26" />
                <RowDefinition Height="26" />
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto" />
                <ColumnDefinition Width="Auto" />
              </Grid.ColumnDefinitions>
              <Label Content="Hersteller: " Grid.Row="0" Grid.Column="0"/>
              <Label Content="{Binding Path=Hersteller, Source={StaticResource OverviewData}}" Grid.Row="0" Grid.Column="1"/>
            </Grid>
          </DockPanel>
        </TabItem>
      </TabControl>
    </Grid>
</Window>

这里是我的c#代码:

namespace MVVM
{
    class VM_lalala : VM_Base
    {

        private string _Hersteller;
        private UebersichtRepository _Rep;

        public string Hersteller
        {
            get { return this._Hersteller; }
            set
            {
                if (this._Hersteller != value)
                {
                    this._Hersteller = value;
                    this.NotifyPropertyChanged("Hersteller");
                }
            }
        }

        public void GetDataFromRep()
        {
            _Rep.GetInfo(this);
        }

        public VM_lalala()        
        {
            this._Rep = new UebersichtRepository();          
        }

    }

    class UebersichtRepository : VM_Base
    {
        private static VM_lalala _ViewModel;

        public bool GetInfo(VM_lalala Aktu_ViewModel)
        {
            try
            {
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_ComputerSystem");               

                foreach (ManagementObject queryObj in searcher.Get())
                {
                    _ViewModel.Hersteller = queryObj["Manufacturer"].ToString();
                }

                return true;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
                return false;
                throw;
            }
        }
    }

    class VM_Base : INotifyPropertyChanged
    {


        public event PropertyChangedEventHandler PropertyChanged;

        protected void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

    }
}

编辑: 在Steve B的例子中我重构了我的代码:

  • VM_lalala已重命名为ViewModelUebersicht
  • 添加代表Viewmodel的一个项目的类UebersichtWerte
  • 删除依赖

现在它起作用了。 问题是,用他自己的方法(GetDataFromRep)填充Viewmodel是不对的。

工作流程现在是:

  • XAML TabItem.Resource创建ViewModelUebersicht的实例
  • 在构造函数中调用Methode GetDataFromRep
  • GetDataFromRep调用Getinfo
  • Getinfo从所需值返回一个represanting对象
  • 在GetdataFromRep中手动订购的值到ViewModelUebersicht的属性

是mvvm思维和模式的工作流程投诉吗?

新的c#代码:

   public class UebersichtWerte : VM_Base
   {
       public string Hersteller;
       public string Model;
   }

    public class ViewModelUebersicht : VM_Base
    {

        private string _Hersteller;
        private string _Modell;
        private UebersichtRepository _Rep;

        public string Hersteller
        {
            get { return this._Hersteller; }
            set
            {
                if (this._Hersteller != value)
                {
                    this._Hersteller = value;
                    this.NotifyPropertyChanged("Hersteller");
                }
            }
        }
        public string Modell
        {
            get { return this._Modell; }
            set
            {
                if (this._Modell != value)
                {
                    this._Modell = value;

                }
            }
        }

        public void GetDataFromRep()
        {
            UebersichtWerte _PCDATA = new UebersichtWerte();
            _PCDATA = _Rep.GetInfo();
            this.Hersteller = _PCDATA.Hersteller;
            this.Modell = _PCDATA.Model;
        }

        public ViewModelUebersicht()        
        {
            this._Rep = new UebersichtRepository();
            GetDataFromRep();
        }

    }


    class UebersichtRepository
    {    
        public UebersichtWerte GetInfo()
        {
            try
            {
                UebersichtWerte _DATA = new UebersichtWerte();
                ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_ComputerSystem");               

                foreach (ManagementObject queryObj in searcher.Get())
                {
                    _DATA.Hersteller = queryObj["Manufacturer"].ToString();
                    _DATA.Model = queryObj["Model"].ToString();
                }

                return _DATA;
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
                return null;
                throw;
            }
        }
    }

和新的XAML代码:

<Window x:Class="MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:MVVM"
        Title="MainWindow" Height="350" Width="525">

  <Grid>
      <TabControl Name="tabControl1">
        <TabItem Header="Uebersicht" Name="tabUeberischt">
                <TabItem.Resources>
                    <VM:ViewModelUebersicht  x:Key="VM_Uebersicht" />
                </TabItem.Resources>
                <DockPanel>
                    <Grid DataContext="{StaticResource VM_Uebersicht}">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="26" />
                                <RowDefinition Height="26" />
                                <RowDefinition Height="26" />
                                <RowDefinition Height="26" />
                                <RowDefinition Height="26" />
                                <RowDefinition Height="26" />
                                <RowDefinition Height="26"/>
                                <RowDefinition Height="26"/>
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>
                            <Label Content="Hersteller: " Grid.Row="0" Grid.Column="0"/>
                            <Label Content="{Binding Hersteller, UpdateSourceTrigger=PropertyChanged}" Grid.Row="0" Grid.Column="1"/>
                            <Label Content="Modell: " Grid.Row="1" Grid.Column="0"/>
                            <Label Content="{Binding Modell, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1" Grid.Column="1"/>                            
                        </Grid>
                </DockPanel>
        </TabItem>
      </TabControl>
    </Grid>
</Window>

4 个答案:

答案 0 :(得分:1)

几个步骤:

首先,我建议您重构代码以避免层之间的依赖。具体而言,更改您的存储库类以避免它依赖于VM:

public class UebersichtRepository 
{


    public string GetInfo()
    {
        string result = null;

            ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_ComputerSystem");               

            foreach (ManagementObject queryObj in searcher.Get())
            {
                result = queryObj["Manufacturer"].ToString();
            }

        return result;            
    }
}

然后,在您的调用代码中,只需:

public void GetDataFromRep()
{
    this.Hersteller = _Rep.GetInfo();
}

其次,为了触发数据检索,您只需调用GetDataFromRep

即可

最后,您必须正确设置绑定。可能的方法是将datacontext直接定义到VM的实例:

<Window.Resources>
    <vm:VM_lalala  x:Key="lalala" />
</Window.Resources>

然后,只需绑定您的标签:

<Label Content="{Binding Hersteller}" Grid.Row="0" Grid.Column="1"/>

答案 1 :(得分:0)

您可以使用Window资源来指定静态资源,这将代表您的ViewModel

<Window.Resources>
    <vm:VM_lalala  x:Key="viewmodel" />
</Window.Resources> 

然后,您可以将其用作网格的DataContext

 <Grid DataContext="{StaticResource viewmodel}">

然后你可以写

 <Label Content="{Binding Hersteller}" Grid.Row="0" Grid.Column="1"/>

另外,请使用public class而不是class

答案 2 :(得分:0)

将资源定义为外部网格的资源并修改网格的定义:

<Grid DataContext="{Binding Source={StaticResource OverviewData}}" >

否则绑定没有他们可以使用的上下文。

答案 3 :(得分:0)

关于MVVM部分的一些评论:

您的UebersichtRepository将是Model-View-ViewModel的“模型”部分。因此它不应该从VM_Base派生 - 它甚至不使用可能改变的Properties。

此外,模型不应该依赖于ViewModel。我想知道为什么代码运行没有Nullpointer Exception,因为你将Aktu_ViewModel作为参数传递,但稍后设置_ViewModel.Hersteller - 并且_ViewModel本身永远不会被设置。但无论如何,你应该完全删除Aktu_ViewModel和_ViewModel,而不是返回信息而不是bool。由于您使用Exceptions进行错误处理,因此bool特别无用。

谁调用了GetDataFromRep方法?