user481758
user481758

Reputation:

WPF and MVVM problem

if try implemnt my first MVVM in WPF app. I have old app based on winforms and I want use my logic (class) from this project.

I have Model, it consist with these classes:

public class FriendData
{
//...
}

public class PingData
{
//...
}

public class PokecAccount : INotifyPropertyChanged, IDataErrorInfo
{
//...
}


public class Rp :INotifyPropertyChanged, IDataErrorInfo
{
//...
}


public class JsonUser:INotifyPropertyChanged
{
//...
}

And service class which send HTTP GET and POST request on server, this class implement this interface:

interface IPokecService
{
    bool LogOn(string nick, string password);
    bool LogOff();
    JsonUser CreateJsonUser(string nick);
    void Ping();
    void IbRp();
    bool SendRp(Rp rp);
    Rp LoadRp();
}


public class PokecService:IPokec
{
 public PokecAccount account;
 public PingData pingData;

 //impelent interface IPokec

}

I try use DelegateCommand from WPF Model-View-ViewModel Toolkit 0.1.

With View I have any problem. But my problem is how "wrap" methods from class PokecService in ViewModel.

Example with method LogOn.

First I create View.

StartUpWindow.xaml

    <StackPanel Grid.Row="1" Margin="12,12,12,12">
        <Label Name="lbAzetID" Content="AzetID" Style="{StaticResource lb1}"></Label>
        <TextBox Name="tbAzetID" Style="{StaticResource tb1}">
            <TextBox.Text>
                <Binding Path="AzetId" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged">
                </Binding>
            </TextBox.Text>
        </TextBox>
        <Label Name="lbRegistration" Content="Registrácia" Style="{StaticResource lb1}">
            <Label.ToolTip>
                <StackPanel>
                    <TextBlock FontWeight="Bold">Registrácia</TextBlock>
                    <TextBlock>Nemáte vlástené AzetID, registrujte sa tu!</TextBlock>
                </StackPanel>
            </Label.ToolTip>
        </Label>
        <Label Name="lbPassword" Content="Heslo" Style="{StaticResource lb1}" ></Label>
        <TextBox Name="tbPassword" Style="{StaticResource tb1}">
            <TextBox.Text>
                <Binding Path="Password" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged">
                </Binding>
            </TextBox.Text>
        </TextBox>
        <Label Name="lbForgetPassword" Content="Zabudli ste heslo?" Style="{StaticResource lb1}">
            <Label.ToolTip>
                <StackPanel>
                    <TextBlock FontWeight="Bold">Zabudli ste svoje heslo?</TextBlock>
                    <TextBlock>Nechajte si ho zaslať na Váš email.</TextBlock>
                </StackPanel>
            </Label.ToolTip>
        </Label>
    </StackPanel>
    <Button Name="LogOn"
            Command="{Binding LogOnCommand}"
            Content="Prihlásiť" 
            Width="100" 
            Height="25" 
            VerticalAlignment="Center"
            Grid.Row="2" />

It consist only 2 texboxes and one button, I bind button commad on property of ViewModel.

VieModel StartUpViewModel.cs

In this class I want wrap methods from class PokecService on DelegateCommand, and these bind on UI controls.

public class StartUpViewModel
{

    private string _name = "KecMessanger";
    private string _password = "KecMessanger";
    private PokecService _pokecService;

    public StartUpViewModel()
    {
        _pokecService=new PokecService();
    }

    DelegateCommand _logOnCommand;

    public ICommand LogOnCommand
    {
        get
        {
            if(_logOnCommand==null)
            {
                _logOnCommand=new DelegateCommand(LogOn,CanLogOn);
            }
            return _logOnCommand;
        }
    }

    private void LogOn()
    {
        //In this method I need to call method LogOn from calss PokecService _pokecService.LogOn(_name,_password)          
        //if loging is success I need create another window - view and close this window
        //somehing like this:
        if (_pokecService.LogOn(_name, _password))
        {
            var newViewWindow = new AnotherView();
            //close StartUpView (its typeof window) but I don’t know how
            AnotherView.Show();
        }           
    }

    private bool CanLogOn()
    {
        return true;
    }
}

My questions are:

  1. I can bind UI controls from view on properties in ViewModel, it is no problem. It is good way to "wrap" methods from my class PokecService in ViewModel with DelegateCommad?

  2. It is good create new window/View in ViewModel ? How can I close actual View(Window) in ViewModel?

  3. What is the most suitable solution for this problem?

I think I need only wrap my methods with DelegateCommand variable, and create for these variable properties and this properties bind on UI controls but I am absolute beginner in MVVM. I read some articles, but they show only very simple demo.

Thank for any advance. Sorry for my english.

Upvotes: 1

Views: 473

Answers (1)

Femaref
Femaref

Reputation: 61497

  1. Commands are made to communicate between view and viewmodel in MVVM. To abstract the PokecService away from the ViewModel, I'd advise you to use Dependency Injection (I myself use MEF).
  2. I would supply the view with dependency injection, so the class is easier testable. Create an interface if needed so you could replace the actual implementation of the service class without replacing the type everywhere.
  3. use a DI container.

Note: I use WAF as MVVM framework together with MEF and it works like a charm.

Short Example:

[Export(typeof(IService))]
public class Service : IService
{
}

public interface IService
{
  void Method();
}

[Export]
public class Consumer
{
  private readonly IService _Service;

  [ImportingConstructor]
  public Consumer(IService service)
  {
    ser = service;
  }


  public void DoStuff()
  {
    //stuff
    _Service.Method();
  }
}

In a startup method (ie. Application.OnStartup):

var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()); //insert the assembly defining the mentioned classes above
var container = new CompositionContainer(catalog);
container.ComposeParts(this);

Consumer c = container.GetExportedValue<Consumer>();
c.DoStuff();

Upvotes: 1

Related Questions