MVVM Jak to zrobić ?

0

Witam,

W między czasie pojawił się jeszcze jeden problem ze zrozumieniem tematu. Może ktoś by podpowiedział co jest źle ?

Mam taki kod opisany poniżej :

w pliku XAML (VIEW) mam coś takiego:

<UserControl x:Class="Procject1.View.DataAdd"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:mui="http://firstfloorsoftware.com/ModernUI"
             xmlns:vm="clr-namespace:Procject1.ViewModel"
             mc:Ignorable="d" 
             x:Name="DataAddDialog"
             d:DesignHeight="491" d:DesignWidth="600">
    <Grid Loaded="Grid_Loaded_1" Height="525" VerticalAlignment="Top">
        <Grid.RowDefinitions>
            <RowDefinition Height="415" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="0*"/>
            <RowDefinition Height="9*"/>
            <RowDefinition Height="2*"/>
            <RowDefinition Height="34*"/>
        </Grid.RowDefinitions>
        <TextBlock Style="{StaticResource Heading2}" Text="Parametry danych" Margin="15,10,0,7" Grid.Row="0" Foreground="Black" />
        <ScrollViewer Grid.Row="0" Margin="50,43,10,16">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="10" />
                    <RowDefinition Height="40" />
                    <RowDefinition Height="40" />
                </Grid.RowDefinitions>
                <StackPanel Name="Aggregate1" Grid.Row="1">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="20" /> 
                            <ColumnDefinition Width="120" />
                            <ColumnDefinition Width="30" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="20" />
                            <ColumnDefinition Width="40" />
                            <ColumnDefinition Width="20" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="30" />
                        </Grid.ColumnDefinitions>
                        <Label Content="Dana 1" Grid.Column="1" Margin="10,10,10,10"/>
                        <TextBox Name="param1" Text="{Binding MED1}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextAlignment="Right" Width="95" Grid.Column="3" Margin="0,10,0,10" Background="White" Foreground="Blue" HorizontalAlignment="Right" />
                        <CheckBox Name="chk1" IsChecked="False" Grid.Column="5" HorizontalAlignment="Center" Visibility="{Binding Moisture}"/>
                        <TextBox Name="sndA1" Text="0.00" TextAlignment="Right" Width="95" Grid.Column="7" Margin="0,10,0,10" Background="White" Foreground="Black" HorizontalAlignment="Right" IsEnabled="False"/>
                    </Grid>
                </StackPanel>
                <StackPanel Name="Aggregate2" Grid.Row="2">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="20" />
                            <ColumnDefinition Width="120" />
                            <ColumnDefinition Width="30" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="20" />
                            <ColumnDefinition Width="40" />
                            <ColumnDefinition Width="20" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="30" />
                        </Grid.ColumnDefinitions>
                        <Label Content="Dana 2" Grid.Column="1" Margin="10,10,10,10"/>
                        <TextBox x:Name="param2" Text=Text="{Binding MED2}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextAlignment="Right" Width="95" Grid.Column="3" Margin="0,10,0,10" Background="White" Foreground="Blue" HorizontalAlignment="Right" />
                        <CheckBox x:Name="chk2" IsChecked="False" Grid.Column="5" HorizontalAlignment="Center"/>
                        <TextBox x:Name="snd2" Text="0.00" TextAlignment="Right" Width="95" Grid.Column="7" Margin="0,10,0,10" Background="White" Foreground="Black" HorizontalAlignment="Right" IsEnabled="False"/>
                    </Grid>
                </StackPanel>
            </Grid>
        </ScrollViewer>
    </Grid>
</UserControl>
</CODE>
W pliku modelu mam tak:
```csharp
using System;
using System.ComponentModel;
using Modbus;
using System.Threading.Tasks;

namespace Procject1.Model
{
    public class DaneModel : INotifyPropertyChanged
    {
        #region Fields

        private double _mrs1;
        private double _mrs2;

        private double _med1;
        private double _med2;

        #endregion
        #region INotifyPropertyChangedImplementation

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string PropertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
        }

        #endregion
        #region Properties

        public double MRS1
        {
            get { return _mrs1; }
            set { _mrs1 = value; OnPropertyChanged("MSR1"); }
        }
        public double MRS2
        {
            get { return _mrs2; }
            set { _mrs2 = value; OnPropertyChanged("MSR2"); }
        }

        public bool CBRS1 { get; set; }
        public bool CBRS2 { get; set; }

        public double MED1
        {
            get { return _med1; }
            set { _med1 = value; OnPropertyChanged("MED1"); }
        }
        public double MED2
        {
            get { return _med2; }
            set { _med2 = value; OnPropertyChanged("MED2"); }
        }
        #endregion
        #region Constructor
        public DaneModel()
        {
            MED1 = 0.00; MED2 = 0.00; 
            DataFromOther(2); // Pobiera dane dla MRS1 = wartość1; MRS2 = wartość2;
        }

        #endregion
	
	private void DataFromOther(int licznik)
	{
		// pobranie danych z jakiegoś źródłą (nie baza danych)
	}
    }
}
</CODE>
W pliku ViewModel mam tak:
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConcreteProductionProcject1.Model;
using ConcreteProductionProcject1.Model.Entity_Data_Model;
using System.Windows.Data;
using System.ComponentModel;
using System.Windows.Input;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Reflection;
using System.Collections;
using System.Data.Entity;
using System.Data;
using System.Data.SqlClient;
using System.Xml;

namespace Procject1.ViewModel
{
     public class DataAddViewModel : ViewModelBase
    {
         #region Fields

         private int many;

         public int IleDanych 
         {
             get { return many; }
             set { many = value; }
         }
         DaneModel _dane = new DaneModel() ;

         #endregion
         #region Properties

         public double MED1
         {
             get { return _moistures.MED1; }
             set { _moistures.MED1 = value; OnPropertyChanged("MED1"); }
         }
         public double MED2
         {
             get { return _moistures.MED2; }
             set { _moistures.MED2 = value; OnPropertyChanged("MED2"); }
         }
         public double MED3
         {
             get { return _moistures.MED3; }
             set { _moistures.MED3 = value; OnPropertyChanged("MED3"); }
         }
         public double MED4
         {
             get { return _moistures.MED4; }
             set { _moistures.MED4 = value; OnPropertyChanged("MED4"); }
         }
         public double MED5
         {
             get { return _moistures.MED5; }
             set { _moistures.MED5 = value; OnPropertyChanged("MED5"); }
         }
         public double MED6
         {
             get { return _moistures.MED6; }
             set { _moistures.MED6 = value; OnPropertyChanged("MED6"); }
         }
         public double MED7
         {
             get { return _moistures.MED7; }
             set { _moistures.MED7 = value; OnPropertyChanged("ME7"); }
         }
         public double MED8
         {
             get { return _moistures.MED8; }
             set { _moistures.MED8 = value; OnPropertyChanged("MED8"); }
         }

         public ICommand OkCommand { get; set; }
         public ICommand CancelCommand { get; set; }

         #endregion
         #region Constructor

         public MoistureViewModel(Production CurrentEntity, int m)
         {
             many = m;
             _moistures = new Moistures();
             if (CurrentEntity != null)
             {
                 if (IleDanych>= 1) MED1 = wart[0];
                 if (IleDanych >= 2) MED2 = wart[1];
            }
            InitCommands();
        }

       #endregion
       #region CommandRegistration

       protected void InitCommands()
       {
           OkCommand = new BasicCommand(o => { try { dynamic Dialog = ((dynamic)o).Parent; Dialog.DialogResult = true; Dialog.Close(); } catch { } }, o => true);
           CancelCommand = new BasicCommand(o => { try { dynamic Dialog = ((dynamic)o).Parent; Dialog.DialogResult = false; Dialog.Close(); } catch { } }, o => true);
       }

       #endregion
    }
}
</CODE>
// W parencie (jakaś inna forma WPF)

mam procedurę wywołującą okno DaneAdd...

```csharp
        public void MoistureControlOpen(object param)
        {
            int IleDanych = 2;  // Ta zmienna ma docelowo być pobrana z konfiguracji. 

            if (IleDanych > 8) IleDanych = 8; // Zabezpieczenie przekroczenia limitu 8 danych...
            View.DaneAdd daneadd = new View.DaneAdd();
            daneadd.IleDanych = IleDanych; // Ile ma par danych;
            daneadd.ViewModel = new MoistureViewModel();
            FirstFloor.ModernUI.Windows.Controls.ModernDialog Dialog = new FirstFloor.ModernUI.Windows.Controls.ModernDialog()
            {
                Title = "Parametry danych",
                Content = daneadd,
            };
            Dialog.IsEnabled = true;

            Dialog.Buttons = new[] { Dialog.OkButton, Dialog.CancelButton };
            Dialog.ShowDialog();
            if (Dialog.DialogResult.HasValue && Dialog.DialogResult.Value)
            {
		// dalsza obsługa danych...
            }
        }
</CODE>
Wydaje mi się że to dobrze rozumiem z przykładów dostępnych na necie ale jednak jest coś nie tak. 

W niektórych miejscach w pliku XAML jest wpis Text="0.00", bo nie działa mi 

<TextBox Name="param1" Text="{Binding MED1}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" TextAlignment="Right" Width="95" Grid.Column="3" Margin="0,10,0,10" Background="White" Foreground="Blue" HorizontalAlignment="Right" />

nie wiem czemu MED1 to nie jest własność MED1 z pliku DaneModel ani z DataAddViewModel.

Nie wiem w którym miejscu czegoś mi zabrakło. Jestem otwarty na sugestie.. Z góry dzięki.

Pozdrowienia dla wszystkich.
0

A działa jakikolwiek inny Binding? Bo w przedstawionym kodzie nie widzę, żeby gdzieś był ustawiany DataContext, który właśnie mówi widokowi, skąd odczytywać właściwości.

0

Witam,

Dzięki za odpowiedź. A możesz podpowiedzieć gdzie to powinno być zrobione ?
Próbowałem dodać taki wpis w DaneAdd.xaml.cs po InitializeComponent(); w metodzie DaneAdd();
i wpisywałem inaczej jako DataContext="DaneAddViewModel" na koncu definicji <UserControl>.

w obu przypadkach nic to nie dało.

Pozdrawiam.

0

Trochę to mylące, że masz nazwy DaneAdd i DataAdd. W każdym razie problem widzisz w pliku XAML definiującym UserControl. Tej kontrolki używasz w jakimś oknie (w pliku, w którym na początku jest <Window>). To okno musi mieć ustawioną właściwość DataContext na obiekt view modelu, z którego chcesz wyciągnąć dane - może to być zrobione w pliku .cs po Initalize() albo gdzieś tam, gdzie to okno pokazujesz. Zależy, gdzie ten view model jest tworzony. Wtedy wartość DataContext "spłynie w dół" po całym drzewie XAML i kontrolka też ją dostanie, więc będzie mieć dostęp do tego obiektu i z niego weźmie to, co jest w {Binding}.

Aha, napisanie DataContext="DaneAddViewModel" w XAML-u dla UserControl nic nie daje, bo do prawidłowego działania DataContext to musi być obiekt klasy DaneAddViewModel, a w tym przypadku podajesz mu tekst. Działałoby, gdyby to było w postaci DataContext={Binding A.B.C}, gdzie A.B.C to ścieżka od obiektu, który stanowi DataContext okna, do obiektu wewnętrznego, który ma być kontekstem dla kontrolki. Przykładowo, jeśli kontekstem okna jest obiekt klasy MainViewModel i ona ma właściwość o nazwie ControlViewModel przechowującą obiekt z danymi dla kontrolki - wtedy w XAML-u trzeba kontrolce zrobić DataContext="{Binding ControlViewModel}".

0

pomogło - dziękuję. Te przypisanie robiłem w złym miejscu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1