【问题标题】:How to popup usercontrol on button click action in my case using mvvm在我的情况下,如何使用 mvvm 在按钮单击操作上弹出用户控件
【发布时间】:2016-12-09 13:18:19
【问题描述】:

我有一个情况,我有一个窗口,我在这个窗口上创建了复选框(复选框的数量是动态决定的,我正在使用 MVVM 而不使用任何内置框架,如 MVVM-Light 或 PRISM),并且在选择这些之后复选框我单击一个按钮,此按钮也存在于同一窗口中。单击此按钮时必须弹出另一个窗口(比如说 GraphDisplay.xaml,它是 UserControl)。但是这个 GraphDisplay 会根据前一个窗口中的复选框选择显示一些图形。

我还必须将选中的复选框信息传递给 GraphDisplay。例如,如果我选中了第 2 和第 5 个复选框,它可能会发送一个字符串“2,5”类型的变量(如消息框http://prntscr.com/dh9u2s 中的给定格式)。这样 GraphDisplay 将只显示第 2 点和第 5 点的图形(像这样http://prntscr.com/dhakx4

我在主视图模型中的按钮事件是这样的:

  public void MyAction()
        {
            string selectedCheckBoxes = verifyHowManyChecked(); //selectedCheckBoxes gives all the selcted checkboxes
            //appended by ","
            GraphDisplay gd = new GraphDisplay(selectedCheckBoxes); //I want to pass here the selcted values so that i can reuse it there decoding
            //them to get the selcted checkboxes
          // gd.Show() which will not work for sure because its not winform. So

        }

MainWindow.Xaml 是

<Window x:Class="DynamicCheckBox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <ListView ItemsSource="{Binding AllActivities}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <TextBlock  Text="{Binding Path=Name, Mode=TwoWay}" />
                        <CheckBox Background="Gray" IsChecked="{Binding Path=ID, Mode=TwoWay}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListView>
        <Button Grid.Row="1" Content="Plot" Height="20" Width="100" Command="{Binding PlotButton}"></Button>
    </Grid>
</Window>

GraphDisplay.xaml 是:

<UserControl x:Class="DynamicCheckBox.GraphDisplay"
             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:d3="http://research.microsoft.com/DynamicDataDisplay/1.0"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <d3:ChartPlotter x:Name="plotter" Grid.Row="1" Grid.Column="1">
            <!--<d3:ChartPlotter.HorizontalAxis>
                <d3:HorizontalDateTimeAxis Name="dateAxis"/>
            </d3:ChartPlotter.HorizontalAxis>-->
            <d3:Header FontFamily="Georgia" Content="Voltage chart"/>
            <d3:VerticalAxisTitle FontFamily="Georgia" Content="Voltage [V]" />
            <d3:HorizontalAxisTitle FontFamily="Georgia" Content="Time"/>
            <d3:HorizontalLine Value="{Binding MaxVoltage}" Stroke="Red" StrokeThickness="2"/>
            <d3:HorizontalLine Value="{Binding MinVoltage}" Stroke="Red" StrokeThickness="2"/>
        </d3:ChartPlotter>
    </Grid>
</UserControl>

GraphDisplay.xaml.cs 是:

 public partial class GraphDisplay : UserControl, INotifyPropertyChanged
    {
        List<double> points_x_y_Graph1 = new List<double>() { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 0.9, 0.8, 0.7 };
        List<double> points_x_y_Graph2 = new List<double>() { 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0, 0.1, 0.2, 0.3 };
        private int _maxVoltage; private int _minVoltage;
    public int MaxVoltage
    {
        get { return _maxVoltage; }
        set { _maxVoltage = value; OnPropertyChanged("MaxVoltage"); }
    }
    public int MinVoltage
    {
        get { return _minVoltage; }
        set { _minVoltage = value; OnPropertyChanged("MinVoltage"); }
    }

    public VoltagePointCollection voltagePointCollection1;
    public VoltagePointCollection voltagePointCollection2;
    DispatcherTimer updateCollectionTimer;
    private int i = 0;
    public GraphDisplay()
    {
        InitializeComponent();
        this.DataContext = this;
        updateCollectionTimer = new DispatcherTimer();
        updateCollectionTimer.Interval = TimeSpan.FromMilliseconds(500);
        updateCollectionTimer.Tick += new EventHandler(updateCollectionTimer_Tick);
        updateCollectionTimer.Start();

        voltagePointCollection1 = new VoltagePointCollection();
        var ds1 = new EnumerableDataSource<VoltagePoint>(voltagePointCollection1);
        ds1.SetXMapping(x => x.time);
        ds1.SetYMapping(y => y.Voltage);

        plotter.AddLineGraph(ds1, Colors.Green, 2, "Volts 1");
        MaxVoltage = 1;
        MinVoltage = -1;

        voltagePointCollection2 = new VoltagePointCollection();
        var ds2 = new EnumerableDataSource<VoltagePoint>(voltagePointCollection2);
        ds2.SetXMapping(x => x.time);
        ds2.SetYMapping(y => y.Voltage);

        plotter.AddLineGraph(ds2, Colors.Blue, 2, "Volts 2");
    }
    void updateCollectionTimer_Tick(object sender, EventArgs e)
    {
        if (i < points_x_y_Graph1.Count)
        {
            //{ i = 0; }
            //For first graph
            voltagePointCollection1.Add(new VoltagePoint(points_x_y_Graph1[i], i));
            //For second graph
            voltagePointCollection2.Add(new VoltagePoint(points_x_y_Graph2[i], i)); // To add one more graph
            i++;
        }
    }


    #region INotifyPropertyChanged members
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

如何在 MyAction() 调用上弹出用户控件。以及如何将选中的复选框传递给 GraphDisplay 用户控件,以便它使用 MVVM 显示选中的复选框 Graph?

【问题讨论】:

  • 您是否为此使用任何框架(Prism、MvvmLight)?
  • 不,我没有使用任何 MVVM 框架。它只是手动实现 MVVM。

标签: wpf xaml mvvm user-controls viewmodel


【解决方案1】:

如果需要,您可以将图形控件添加到 MainWindow.xaml 并使用布尔到可见性转换器将其可见性绑定到 VM 上的属性(例如 IsShowingGraph)。

然后单击按钮会更新 IsShowingGrid。

【讨论】:

  • 感谢您的回答,但这个想法也是要知道这种情况在 WPF 中通常是如何处理的?
  • 好的,如果我使用您在 Mainwindow.xaml 中添加 GraphDisplay 用户控件的想法,我将如何将选定的复选框字符串变量传递给仅显示选定复选框的图形?你能写一个伪代码吗?
  • 可以在声明的xaml中指定DataContext
  • 或者您在 GraphDisplay 上创建一个依赖属性并将其绑定到您的 VM 属性
【解决方案2】:

如果您真的想节省大量时间并遵循最佳实践,我强烈建议您为此使用一些 MVVM 框架。

但是,如果由于设计限制,您无法使用这些框架中的任何一个,那么您需要为视图模型交互实现自己的解决方案。

我还建议您阅读 Prism 文档中有关 Interaction Request Patterns 的信息。虽然这里的内容同样适用于任何框架(甚至当您实现自己的解决方案时)。

根据文档,在 MVVM 中实现通知和交互 应用程序同时保持关注点的干净分离可能是一个非常 棘手的事情。

视图模型负责启动与用户的交互并获取和处理响应,而视图负责使用应用程序中使用的任何呈现技术向用户呈现交互 UI .

两种主要的常用方法:

使用交互服务: 这里视图模型使用服务实现来启动与用户的交互,因此这里的视图模型通过 DI/IoC 依赖于 IInteractionService

使用交互请求对象 在这里,视图模型使用与视图中的行为相结合的交互对象直接向视图发出交互请求。

这是推荐的方法以及它在 Prism 中的实施方式。这是一个简单但非常强大的方法,它正确地保持了关注点的清晰分离。

文档中还有很多内容,因此如果您无法使用这些出色的框架中的任何一个,我再次强烈建议您仔细计划如何实施您的解决方案。

希望这会有所帮助!

【讨论】:

  • 谢谢,你的意思是我应该使用 PRISM 的 IInteractionService 接口。但我没有使用棱镜。
  • 我的意思是你应该使用一个框架,因为它会变得丑陋,但如果你不能,那么你应该实现这两种方法中的任何一种——你最喜欢的一种——交互模式在您的解决方案中。
猜你喜欢
  • 1970-01-01
  • 2015-08-30
  • 1970-01-01
  • 1970-01-01
  • 2014-11-20
  • 1970-01-01
  • 1970-01-01
  • 2020-07-28
  • 1970-01-01
相关资源
最近更新 更多