WPF 和 MVVM 问题

发布于 2024-10-03 17:12:48 字数 4785 浏览 5 评论 0原文

如果尝试在 WPF 应用程序中实现我的第一个 MVVM。我有基于 winforms 的旧应用程序,我想使用这个项目中的逻辑(类)。

我有 Model,它由以下类组成:

public class FriendData
{
//...
}

public class PingData
{
//...
}

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


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


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

以及在服务器上发送 HTTP GET 和 POST 请求的服务类,此类实现此接口:

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

}

我尝试使用 WPF Model-View-ViewModel Toolkit 0.1 中的 DelegateCommand。

使用 View 我有任何问题。但我的问题是如何在 ViewModel 中“包装”PokecService 类的方法。

方法 LogOn 的示例。

首先,我创建 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" />

它仅包含 2 个文本框和一个按钮,我将按钮命令绑定到 ViewModel 的属性上。

VieModel StartUpViewModel.cs

在这个类中,我想要将类 PokecService 中的方法包装到 DelegateCommand 上,并将这些方法绑定到 UI 控件上。

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

我的问题是:

  1. 我可以从 ViewModel 中的属性视图绑定 UI 控件,这没有问题。 这是使用 DelegateCommad 在 ViewModel 中“包装”我的类 PokecService 中的方法的好方法吗?

  2. 在 ViewModel 中创建新窗口/视图很好吗?如何关闭 ViewModel 中的实际视图(窗口)?

  3. 这个问题最合适的解决方案是什么?

我认为我只需要使用 DelegateCommand 变量包装我的方法,并为这些变量属性创建并将此属性绑定到 UI 控件上,但我绝对是 MVVM 的初学者。我读了一些文章,但它们只展示了非常简单的演示。

感谢您的任何提前。对不起我的英语。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

迷途知返 2024-10-10 17:12:48
  1. MVVM 中的视图和视图模型之间通过命令进行通信。为了将 PokecService 从 ViewModel 中抽象出来,我建议您使用依赖注入(我自己使用 MEF)。
  2. 我将为视图提供依赖注入,因此该类更容易测试。如果需要,创建一个接口,以便您可以替换服务类的实际实现,而无需替换各处的类型。
  3. 使用 DI 容器。

注意:我将 WAF 与 MEF 一起用作 MVVM 框架,它的工作方式非常神奇。

简短示例:

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

在启动方法中(即 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();
  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();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文