How to hide and show UserControls based on Selecte

2019-08-31 04:50发布

问题:

I have 3 UserControls in my MainWindow,In my UserControl1 i have a ListBox with some names.The UserControl2 and 3 are not visible when we start the application.

When i select some name in the listbox of usercontrol1 then the usercontrol2 should appear on my mainwindow,when i select other name then usercontrol3 should appear on my mainwindow.Struggling with this please help me,i'm new to this

This is my UserControlXaml code

<UserControl x:Class="Wpf_MVVM.UserControl1"
         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" 
         mc:Ignorable="d" 
         x:Name="uc1" Height="Auto" Width="Auto">
<Grid>
    <ListBox Name="listbox" ItemsSource="{Binding mylist}"  HorizontalAlignment="Left" Height="310" VerticalAlignment="Top" Width="150" Margin="0,40,0,0" FontSize="15">

    </ListBox>
    <Label Content="Conversations" HorizontalAlignment="Left" VerticalAlignment="Top"  Height="40" Width="150" FontSize="20" Background="SkyBlue"/>
    <Button Content="Create New Chat" Height="30" HorizontalAlignment="Left" Margin="0,350,0,0" VerticalAlignment="Top" Width="150"/>

</Grid>
</UserControl>

This is my .cs code

public partial class UserControl1 : UserControl
{
    User1 User1 = new User1();
    public UserControl1()
    {
        InitializeComponent();
        this.DataContext = User1;
    }
}
public class User1
{
    private ObservableCollection<string> _mylist = new ObservableCollection<string>();

    public ObservableCollection<string> mylist { get { return _mylist; } }

    public User1()
    {
        mylist.Add("Name1");
        mylist.Add("Name2");
        mylist.Add("Name3");
        mylist.Add("Name4");

    }

This is my mainwindow.xaml code

<Window x:Class="Wpf_MVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:Wpf_MVVM" 
    Title="MainWindow" Background="SlateGray" Height="420" Width="550" >
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="VisibilityConverter" />
</Window.Resources>

<Grid>

    <local:UserControl1 x:Name="uc1"   HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <StackPanel>

        <local:UserControl2 x:Name="uc2"  Visibility="{Binding SelectedItem, Converter={StaticResource VisibilityConverter}}"  HorizontalAlignment="Left" VerticalAlignment="Top" Margin="150,29,0,0" />
        <local:UserControl3 x:Name="uc3" Visibility="{Binding SelectedItem1, Converter={StaticResource VisibilityConverter}}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="340,29,0,0"/>


    </StackPanel>



</Grid>
</Window>

This is my viewmodel code for usercontrol2 and 3

  public class User : INotifyPropertyChanged
    {

        private bool _selectedItem;
        public bool SelectedItem
        {
            get { return _selectedItem; }
            set
            {
                _selectedItem = value;
                PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem"));
            }
        }
        private bool _selectedItem1;
        public bool SelectedItem1
        {
            get { return _selectedItem1; }
            set
            {
                _selectedItem1 = value;
                PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem1"));
            }
        }

        public class BooleanToVisibilityConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {

                return value == null ? Visibility.Collapsed : Visibility.Visible;
            }

            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {

                return null;
            }

        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void Notify(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyName));
        }

        private readonly ObservableCollection<string> items = new ObservableCollection<string>();
        private string text;
        private readonly ObservableCollection<string> newitems = new ObservableCollection<string>();
        private string newtext;

        public class Command : ICommand
        {
            private readonly Action action;

            public Command(Action action)
            {
                this.action = action;
            }

            public bool CanExecute(object parameter)
            {
                return true;
            }


            public event EventHandler CanExecuteChanged;
            public void Execute(object parameter)
            {
                action();
            }
        }

        private readonly ICommand addCommand;
        private readonly ICommand sendCommand;
        public User()
        {

            addCommand = new Command(() => items.Add(Text));
            sendCommand = new Command(() => newitems.Add(NewText));
        }



        public IEnumerable<string> Items
        {
            get { return items; }
        }

        public IEnumerable<string> NewItems
        {
            get { return newitems; }
        }


        public ICommand AddCommand
        {
            get { return addCommand; }
        }
        public ICommand SendCommand
        {
            get { return sendCommand; }
        }

        public string Text
        {
            get { return text; }
            set
            {
                if (text == value)
                    return;

                text = value;
                Notify("Text");
            }
        }
        public string NewText
        {
            get { return newtext; }
            set
            {
                if (newtext == value)
                    return;

                newtext = value;
                Notify("NewText");
            }
        }
    }
}

回答1:

If you want to use a BooleanToVisibilityConverter, then you'll need to create some bool properties in your view model:

public bool IsControl1Visible
{
    get { return isControl1Visible; }
    set { isControl1Visible = value; NotifyPropertyChanged("IsControl1Visible"); }
}

public bool IsControl2Visible
{
    get { return isControl2Visible; }
    set { isControl2Visible = value; NotifyPropertyChanged("IsControl2Visible"); }
}

Then you'll need a SelectedItem property:

public string SelectedItem
{
    get { return selectedItem; }
    set { selectedItem = value; NotifyPropertyChanged("SelectedItem"); }
}

You'll also need to create a SelectedItem DependencyProperty in your first UserControl and bind that to the ListBox.SelectedItem property (I'm assuming that you either know how to or can find out how to create a DependencyProperty):

In UserControl1:

<ListBox Name="listbox" ItemsSource="{Binding mylist}" 
    SelectedItem="{Binding SelectedItem, RelativeSource={AncestorType={x:Type 
    local:UserControl1}}}" HorizontalAlignment="Left" Height="310" 
    VerticalAlignment="Top" Width="150" Margin="0,40,0,0" FontSize="15" />

Then you can Bind the UserControl1.SelectedItem property (which is internally bound to the ListBox.SelectedItem property) to your view model:

<local:UserControl1 x:Name="uc1" SelectedItem="{Binding SelectedItem}" 
    HorizontalAlignment="Left" VerticalAlignment="Top"/>

Finally, we can update our view model SelectedItem property to change the visibility of the other Usercontrols:

public string SelectedItem
{
    get { return selectedItem; }
    set 
    {
        selectedItem = value;
        NotifyPropertyChanged("SelectedItem");
        if (selectedItem == "Some value") 
        {
            IsControl1Visible = true;
            IsControl2Visible = false;
        }
        else
        {
            IsControl2Visible = true;
            IsControl1Visible = false;
        }
    }
}

As an alternative to this method, you may find my answer to the WPF MVVM navigate views post useful.



回答2:

You can use power of Binding without additional C# code

<Grid>
  <local:UserControl1 x:Name="uc1"   HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <StackPanel>
      <local:UserControl2 x:Name="uc2" Visibility="{Binding ElementName=uc1, Path=SelectedItem, Converter={StaticResource VisibilityConverter}}"  HorizontalAlignment="Left" VerticalAlignment="Top" Margin="150,29,0,0" />
      <local:UserControl3 x:Name="uc3" Visibility="{Binding ElementName=uc2, Path=SelectedItem, Converter={StaticResource VisibilityConverter}}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="340,29,0,0"/>
    </StackPanel>
</Grid>

or with data triggers:

<Style TargetType="{x:Type Control}" x:Key="VisibilityStyle1">
            <Setter Property="Visibility" Value="Visible" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding SelectedItem, ElementName=uc1}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Hidden" />
                </DataTrigger>
            </Style.Triggers>
</Style>

<Style TargetType="{x:Type Control}" x:Key="VisibilityStyle2">
            <Setter Property="Visibility" Value="Visible" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding SelectedItem, ElementName=uc2}" Value="{x:Null}">
                    <Setter Property="Visibility" Value="Hidden" />
                </DataTrigger>
            </Style.Triggers>
</Style>

<Grid>
  <local:UserControl1 x:Name="uc1"   HorizontalAlignment="Left" VerticalAlignment="Top"/>
    <StackPanel>
      <local:UserControl2 x:Name="uc2" Style="{DynamicResource VisibilityStyle1}"  HorizontalAlignment="Left" VerticalAlignment="Top" Margin="150,29,0,0" />
      <local:UserControl3 x:Name="uc3" tyle="{DynamicResource VisibilityStyle2}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="340,29,0,0"/>
    </StackPanel>
</Grid>