【问题标题】:diplay panel on button click with zero code behind using mvvm and wpf使用 mvvm 和 wpf 在按钮单击后显示面板为零代码
【发布时间】:2017-04-14 19:32:41
【问题描述】:

我是 MVVM 和 wpf 的新手...

总结形式的问题 - 如何使用 wpf 和 MVVM 控制控件的可见性。它也应该有零代码。

实际场景-我有多个用户控制面板...说UCPanel1,UCPanel2,UCPnale3...直到6 - 我将这些用户控件导入到一个主用户控件中......比如说 UCMain 这是在顶部有按钮的堆栈面板......就像菜单一样。 - 现在要求非常简单......在按钮1上单击-我应该能够看到隐藏的UCPanel1和其余面板,单击按钮2-我应该能够看到隐藏的UCPanel2和其余面板......等等 - 我使用后面的代码成功地实现了这一点。但要求是实现这样一种方式,即在后面的代码中应该有尽可能少的代码。 那么我的 XAML 和视图模型是什么样的呢?
我无法在 viewmodel 中访问 UCPanel1 的扩展对象..

在 MainPanel XAML...

<Button 
    Style="{StaticResource StackPanelButtonStyle}" 
    Command="{Binding openMessageCommand}" >
    <!--Click="BtnMessege_OnClick" >-->
    <TextBlock 
        Text="Messaging" 
        Style="{StaticResource StackPanelButtonTextStyle}">
    </TextBlock>
</Button>
<Button 
    Style="{StaticResource StackPanelButtonStyle}"
    Command="{Binding openProductsCommand}">
    <!--Click="BtnProducts_OnClick">-->
    <TextBlock 
        Text="Products" 
        Style="{StaticResource StackPanelButtonTextStyle}" ></TextBlock>
</Button>

<local:StackPanelMessaging 
    Grid.Row="2" 
    Visibility="{Binding Panel1Visiblity}"></local:StackPanelMessaging>
<local:WrapPanelProducts 
    Grid.Row="2" 
    Visibility="{Binding Panel2Visiblity}" ></local:WrapPanelProducts>

在主视图模型中...

 private Visibility _panel1Visiblity= Visibility.Visible;
        private Visibility _panel2Visiblity= Visibility.Hidden;


  public Visibility Panel1Visiblity
        {
            get { return _panel1Visiblity; }
            set
            {
                if (_panel1Visiblity != value)
                {
                    _panel1Visiblity = value;
                    OnPropertyChanged("Panel1Visiblity");
                }
            }
        }
        public Visibility Panel2Visiblity
        {
            get { return _panel2Visiblity; }
            set
            {
                if (_panel2Visiblity != value)
                {
                    _panel2Visiblity = value;
                    OnPropertyChanged("Panel2Visiblity");
                }
            }
        }

 private void OpenStackMessagePanel()
        {
            Panel1Visiblity = Visibility.Visible;
            Panel2Visiblity = Visibility.Hidden;
        }

        private bool canExecuteMethod1()
        {
            return true;
        }

        private void OpenWrapProductsPanel()
        {
            Panel2Visiblity = Visibility.Visible;
            Panel1Visiblity = Visibility.Hidden;
        }

        private bool canExecuteMethod2()
        {
            return true;
        }
  public ICommand openMessageCommand
        {
            get
            {
                if (_openMessageCommand == null)
                {
                    _openMessageCommand = new DelegateCommand(OpenStackMessagePanel, canExecuteMethod1, true);
                }
                return _openMessageCommand;
            }
        }


        public ICommand openProductsCommand
        {
            get
            {
                if (_openProductsCommand == null)
                {
                    _openProductsCommand = new DelegateCommand(OpenWrapProductsPanel, canExecuteMethod2, true);
                }
                return _openProductsCommand;
            }
        }

另外我觉得写这么多代码真的值得吗?还是我应该更喜欢只剩下 10 行的代码....

【问题讨论】:

  • 这通常使用视图模型中的命令和可见性属性来完成,或者如果这纯粹是 UI,则将触发器添加到按钮以运行故事板,从而为面板上的可见性属性设置动画。
  • 感谢您的回复。是的,我也这样做了,但不知道我错在哪里,单击按钮后面板仍然没有改变。有关详细信息,请参阅编辑后的问题...
  • 不确定您是怎么知道的 - 您的面板中没有任何内容。添加断点并首先证明您的视图模型。

标签: wpf xaml mvvm data-binding viewmodel


【解决方案1】:

通过使用命令和可见性,您可以实现您想要的。这是一个简单的例子。我没有像你那样使用用户控件,但是通过这个例子你应该明白了。只需将网格替换为您的用户控件即可。

我要做的第一件事是创建一个 BooleanToVisibilityConverter 类。这是一个将布尔值转换为可见性的转换器。我们不想将 Visibility 属性放在 ViewModel 中,因为我们想将 UI 与逻辑分开。所以我们在 ViewModel 中想要的是一个简单的布尔值,它可以判断面板是否可见。

      public class BooleanToVisibilityConverter : IValueConverter
      {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
          bool? boolValue = value as bool?;
          return boolValue.HasValue && boolValue.Value ? Visibility.Visible : Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
          Visibility? visibilityValue = value as Visibility?;
          return visibilityValue.HasValue && visibilityValue.Value == Visibility.Visible;
        }
      }


Now in your MainViewModel class, you will have six boolean properties that will tell if your panel is visible or not. And then you will have 6 command properties that will set those boolean properties to true. 

  public class MainViewModel : BindableBase
  {
    private bool _IsPanel1Visible;

    public bool IsPanel1Visible
    {
      get { return _IsPanel1Visible; }
      set { SetProperty(ref _IsPanel1Visible, value); }
    }

    private bool _IsPanel2Visible;

    public bool IsPanel2Visible
    {
      get { return _IsPanel2Visible; }
      set { SetProperty(ref _IsPanel2Visible, value); }
    }

    private bool _IsPanel3Visible;

    public bool IsPanel3Visible
    {
      get { return _IsPanel3Visible; }
      set { SetProperty(ref _IsPanel3Visible, value); }
    }

    private bool _IsPanel4Visible;

    public bool IsPanel4Visible
    {
      get { return _IsPanel4Visible; }
      set { SetProperty(ref _IsPanel4Visible, value); }
    }

    private bool _IsPanel5Visible;

    public bool IsPanel5Visible
    {
      get { return _IsPanel5Visible; }
      set { SetProperty(ref _IsPanel5Visible, value); }
    }

    private bool _IsPanel6Visible;

    public bool IsPanel6Visible
    {
      get { return _IsPanel6Visible; }
      set { SetProperty(ref _IsPanel6Visible, value); }
    }

    public ICommand ShowPanel1Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel1Visible = true; }); } }
    public ICommand ShowPanel2Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel2Visible = true; }); } }
    public ICommand ShowPanel3Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel3Visible = true; }); } }
    public ICommand ShowPanel4Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel4Visible = true; }); } }
    public ICommand ShowPanel5Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel5Visible = true; }); } }
    public ICommand ShowPanel6Command { get { return new DelegateCommand(() => { HidePanels(); IsPanel6Visible = true; }); } }

    private void HidePanels()
    {
      IsPanel1Visible = false;
      IsPanel2Visible = false;
      IsPanel3Visible = false;
      IsPanel4Visible = false;
      IsPanel5Visible = false;
      IsPanel6Visible = false;
    }
  }

现在在您的 xaml 中,您只需要将布尔属性绑定到面板的可见性,并使用 BooleanToVisibilityConverter 将布尔值转换为可见性。您还需要将按钮绑定到命令。

  <Grid>
    <Grid.DataContext>
      <local:MainViewModel />
    </Grid.DataContext>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.Resources>
      <local:BooleanToVisibilityConverter x:Key="booleanToVisibilityConverter" />
    </Grid.Resources>
    <StackPanel Orientation="Horizontal">
      <Button Content="Show Panel 1" Command="{Binding ShowPanel1Command}" />
      <Button Content="Show Panel 2" Command="{Binding ShowPanel2Command}" />
      <Button Content="Show Panel 3" Command="{Binding ShowPanel3Command}" />
      <Button Content="Show Panel 4" Command="{Binding ShowPanel4Command}" />
      <Button Content="Show Panel 5" Command="{Binding ShowPanel5Command}" />
      <Button Content="Show Panel 6" Command="{Binding ShowPanel6Command}" />
    </StackPanel>
    <StackPanel Grid.Row="1">
      <Grid Visibility="{Binding IsPanel1Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 1" />
      </Grid>
      <Grid Visibility="{Binding IsPanel2Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 2" />
      </Grid>
      <Grid Visibility="{Binding IsPanel3Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 3" />
      </Grid>
      <Grid Visibility="{Binding IsPanel4Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 4" />
      </Grid>
      <Grid Visibility="{Binding IsPanel5Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 5" />
      </Grid>
      <Grid Visibility="{Binding IsPanel6Visible, UpdateSourcetrigger PropertyChanged, Converter={StaticResource booleanToVisibilityConverter}}">
        <TextBlock Text="Panel 6" />
      </Grid>
    </StackPanel>
  </Grid>

更新: 在显示另一个面板之前隐藏所有面板。

您可以尝试在此处设置断点进行测试:

【讨论】:

  • 太棒了!!!非常感谢......即使我使用了 Converter 并找到了解决方案......但它有点不同。如果您觉得不合适,请随时发表评论。
  • 要求是......一旦一个面板可见,所有其他面板都应该隐藏......我实现了这个解决方案,但多个面板同时可见,没有命令中断点..可能是我错过了什么..
  • 它应该在 DelegateCommand 的操作上打断点 那就是断点应该在的地方。这有点棘手,因为您没有将断点完全放在该行上。您可以进行操作,然后按 F9。我会根据您的要求更新解决方案。
  • 更新了示例源代码。这一次它将在显示所选面板之前隐藏所有内容。
  • 请更新问题并添加隐藏所有其他面板并仅显示一个面板的要求。
【解决方案2】:
<!--Button1-->
            <Button Style="{StaticResource StackPanelButtonStyle}" Command="{Binding openPanelCommd}" CommandParameter="{Binding ElementName=WrapPanel1}" >
                <TextBlock Text="1"  Style="{StaticResource StackPanelButtonTextStyle}">
                </TextBlock>               
            </Button>
            <!--Button2-->
            <Button Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel2}"  >
                <TextBlock Text="2" Style="{StaticResource StackPanelButtonTextStyle}"></TextBlock>
               </Button>
            <!--Button3-->
            <Button  Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel3}"  >
                <TextBlock Text="3"  Style="{StaticResource StackPanelButtonTextStyle}" ></TextBlock>
            </Button>
            <!--Button4-->
            <Button Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel4}" >
                <TextBlock Text="4" Style="{StaticResource StackPanelButtonTextStyle}" ></TextBlock>
               </Button>
            <!--Button5-->
            <Button  Style="{StaticResource StackPanelButtonStyle}"  Command="{Binding openPanelCommd}"  CommandParameter="{Binding ElementName=WrapPanel5}" >
                <TextBlock Text="5" Style="{StaticResource StackPanelButtonTextStyle}"></TextBlock>
              </Button>
    <!--Panels-->
        <local:WrapPanelProducts x:Name="WrapPanel1" Grid.Row="2"  
                Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel2" Grid.Row="2"  
            Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel3" Grid.Row="2"  
            Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel4" Grid.Row="2"  
            Visibility="Collapsed"/>
    <local:WrapPanelProducts x:Name="WrapPanel5" Grid.Row="2"  
            Visibility="Collapsed"/>

后面的代码是

  public StackPanelMain()
        {

            InitializeComponent();            
            StackPanelMainViewModel StackPanelMainViewModel1 = new StackPanelMainViewModel();
            this.DataContext = StackPanelMainViewModel1;

        }

和查看模型代码如下...

 public RelayCommand openPanelCommd { get; set; }

    //Constructor
        public StackPanelMainViewModel()
        {
            openPanelCommd = new RelayCommand(OpenPanel);
        }


     private void OpenPanel(object parameter)
{
    var args = (object) parameter;

    var elementname = (UIElement) args;

     elementname.Visibility = Visibility.Visible;

 }

【讨论】:

  • 这应该可行,但想法是在 VM 中没有任何 UI 对象。它违背了 MVVM 的目的。 VM 应该与 UI 无关。
猜你喜欢
  • 1970-01-01
  • 2012-05-06
  • 1970-01-01
  • 2014-03-16
  • 2017-10-12
  • 2016-05-25
  • 1970-01-01
  • 2014-02-15
  • 1970-01-01
相关资源
最近更新 更多