Marcus
Marcus

Reputation: 757

understanding MVVM

i try to understand mvvm. i want read the manufacturer from my pc, that´s the goal.

The Problem: - the label in xaml is empty

My understanding:

i hope anyone could help me understanding the mvvm pattern.

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

and here my c# code:

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));
            }
        }

    }
}

EDIT: on the Example from Steve B i Refactored my Code:

now it work´s. The Question is, is it right to fill the Viewmodel in his own Method (GetDataFromRep).

The Workflow is, now:

is the workflow complaint with the mvvm thinking and pattern ?

the new c# code:

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

and the new XAML Code:

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

Upvotes: 0

Views: 535

Answers (4)

Steve B
Steve B

Reputation: 37710

Several steps :

Firstly, I suggest you to refactor your code to avoid dependences between layers. Concretely, change your repository class to avoid it to have dependence to the 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;            
    }
}

then, in your calling code, simply :

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

Secondly, in order to fire the data retrieval, you can simply call the GetDataFromRep

Finally, you have to correctly set up bindings. On the possible way is to define the datacontext directly to an instance of you VM :

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

then, simply bind your label :

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

Upvotes: 1

J&#246;rg Reichardt
J&#246;rg Reichardt

Reputation: 361

A few comments on the MVVM part:

Your UebersichtRepository would be the 'Model' Part of Model-View-ViewModel. Hence it should not derive from VM_Base - it doesn't even use Properties which could change.

Also the Model should not be dependend on the ViewModel. I wonder why the Code runs without Nullpointer Exception, since you pass Aktu_ViewModel as an argument, but set _ViewModel.Hersteller later on - and _ViewModel itself is never set. But anyway, you should remove Aktu_ViewModel and _ViewModel alltogether and instead return the info not a bool. The bool is especially useless since you use Exceptions for Error Handling.

Who calls the GetDataFromRep method?

Upvotes: 0

MatthiasG
MatthiasG

Reputation: 4532

Define the resource as a resource of the outer grid and modify the definition of the grid:

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

Otherwise the bindings have no context that they can use.

Upvotes: 0

stukselbax
stukselbax

Reputation: 5935

you can use Window resources to specify static resource, which will represent to your ViewModel like this :

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

Then, you can use it as DataContext of your Grid.

 <Grid DataContext="{StaticResource viewmodel}">

Then you can write

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

Also, use public class instead of just class.

Upvotes: 0

Related Questions