C# 在用户控件内单击按钮时更改视图

C# 在用户控件内单击按钮时更改视图,c#,wpf,xaml,mvvm,C#,Wpf,Xaml,Mvvm,我在窗户里有两排格子。在第一排有一个带按钮的堆栈面板。点击一个按钮,在网格的第二行显示一个用户控件。现在在用户控件中有多个按钮,可以更改网格第二行的内容(将当前用户控件更改为另一个)。 当我在Customers用户控件中单击一个按钮,并在BaseViewModel中的NavigationCommand上放置一个断点时,它实际上会在更改CurrentViewModel时出现,但不会出现在实际窗口中 main window.xaml <Window x:Class="TestProject.V

我在窗户里有两排格子。在第一排有一个带按钮的堆栈面板。点击一个按钮,在网格的第二行显示一个用户控件。现在在用户控件中有多个按钮,可以更改网格第二行的内容(将当前用户控件更改为另一个)。 当我在Customers用户控件中单击一个按钮,并在BaseViewModel中的NavigationCommand上放置一个断点时,它实际上会在更改CurrentViewModel时出现,但不会出现在实际窗口中

main window.xaml

<Window x:Class="TestProject.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodel="clr-namespace:TestProject.ViewModel"
        xmlns:local="clr-namespace:TestProject"
        xmlns:view="clr-namespace:TestProject.View"
        mc:Ignorable="d"
        Title="MainWindow" Width="966" Height="897">
    <Window.DataContext>
        <viewmodel:MainWindowViewModel/>
    </Window.DataContext>
<Grid >
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <!--Верхнее меню -->
    <Grid Grid.Row="0">
        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" >
            <Button x:Name="Visits" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="visits"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">        
                    <Image Source="../icon/document-changed.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Patients" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="patients"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/document-changed.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Customers" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="customers"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/user.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Goods" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="customer"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/folder_documents.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Services" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="services" BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/folder_documents.png" Width="16" Height="16"/>
            </Button>                
        </StackPanel>
    </Grid>
    <ContentControl x:Name="Content" Grid.Row="1" Content="{Binding CurrentViewModel}"></ContentControl>
    </Grid>
</Window>
namespace TestProject.ViewModel
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public DelegateCommand<string> NavigationCommand { get; set; }        
        public BaseViewModel()
        {        
            NavigationCommand = new DelegateCommand<string>(OnNavigate);            
        }

        private void OnNavigate(string navPath)
        {
            switch (navPath)
            {
                case "customers":
                    CurrentViewModel = new CustomersViewModel();                    
                    break;
                case "visits":
                    CurrentViewModel = new VisitsViewModel();                    
                    break;
                case "patients":
                    CurrentViewModel = new PatientsViewModel();                    
                    break;
                case "customer":                    
                    CurrentViewModel = new CustomerViewModel();
                    break;
                case "visit":                    
                    CurrentViewModel = new VisitViewModel();
                    break;
            }
        }

        private object _currentViewModel;

        public object CurrentViewModel
        {
            get { return _currentViewModel; }
            set
            {
                if (_currentViewModel != value)
                {
                    _currentViewModel = value;
                    OnPropertyChanged();
                }
            }
        }
        private object _currentText;

        public object CurrentText
        {
            get { return _currentText; }
            set
            {
                if (_currentText != value)
                {
                    _currentText = value;
                    OnPropertyChanged();
                }
            }
        }
    }
}
<UserControl x:Class="TestProject.View.Customers"
             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:local="clr-namespace:TestProject.View"
             xmlns:viewModel="clr-namespace:TestProject.ViewModel"
             mc:Ignorable="d"       
             >
    <UserControl.DataContext>
        <viewModel:CustomersViewModel/>
        </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Background="#FFF3EB96">Клиенты</Label>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <Button Command="{Binding NavigationCommand}" CommandParameter="customer"  Background="Transparent"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                <StackPanel Orientation="Horizontal">
                    <Image Source="../icon/plus_32.png" Width="32" Height="32"/>
                </StackPanel>
            </Button>

        </StackPanel>
    </Grid>
</UserControl>

BaseViewModel

<Window x:Class="TestProject.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodel="clr-namespace:TestProject.ViewModel"
        xmlns:local="clr-namespace:TestProject"
        xmlns:view="clr-namespace:TestProject.View"
        mc:Ignorable="d"
        Title="MainWindow" Width="966" Height="897">
    <Window.DataContext>
        <viewmodel:MainWindowViewModel/>
    </Window.DataContext>
<Grid >
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <!--Верхнее меню -->
    <Grid Grid.Row="0">
        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" >
            <Button x:Name="Visits" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="visits"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">        
                    <Image Source="../icon/document-changed.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Patients" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="patients"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/document-changed.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Customers" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="customers"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/user.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Goods" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="customer"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/folder_documents.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Services" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="services" BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/folder_documents.png" Width="16" Height="16"/>
            </Button>                
        </StackPanel>
    </Grid>
    <ContentControl x:Name="Content" Grid.Row="1" Content="{Binding CurrentViewModel}"></ContentControl>
    </Grid>
</Window>
namespace TestProject.ViewModel
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public DelegateCommand<string> NavigationCommand { get; set; }        
        public BaseViewModel()
        {        
            NavigationCommand = new DelegateCommand<string>(OnNavigate);            
        }

        private void OnNavigate(string navPath)
        {
            switch (navPath)
            {
                case "customers":
                    CurrentViewModel = new CustomersViewModel();                    
                    break;
                case "visits":
                    CurrentViewModel = new VisitsViewModel();                    
                    break;
                case "patients":
                    CurrentViewModel = new PatientsViewModel();                    
                    break;
                case "customer":                    
                    CurrentViewModel = new CustomerViewModel();
                    break;
                case "visit":                    
                    CurrentViewModel = new VisitViewModel();
                    break;
            }
        }

        private object _currentViewModel;

        public object CurrentViewModel
        {
            get { return _currentViewModel; }
            set
            {
                if (_currentViewModel != value)
                {
                    _currentViewModel = value;
                    OnPropertyChanged();
                }
            }
        }
        private object _currentText;

        public object CurrentText
        {
            get { return _currentText; }
            set
            {
                if (_currentText != value)
                {
                    _currentText = value;
                    OnPropertyChanged();
                }
            }
        }
    }
}
<UserControl x:Class="TestProject.View.Customers"
             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:local="clr-namespace:TestProject.View"
             xmlns:viewModel="clr-namespace:TestProject.ViewModel"
             mc:Ignorable="d"       
             >
    <UserControl.DataContext>
        <viewModel:CustomersViewModel/>
        </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Background="#FFF3EB96">Клиенты</Label>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <Button Command="{Binding NavigationCommand}" CommandParameter="customer"  Background="Transparent"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                <StackPanel Orientation="Horizontal">
                    <Image Source="../icon/plus_32.png" Width="32" Height="32"/>
                </StackPanel>
            </Button>

        </StackPanel>
    </Grid>
</UserControl>
namespace TestProject.ViewModel
{
公共类BaseViewModel:INotifyPropertyChanged
{
公共事件PropertyChangedEventHandler PropertyChanged=委托{};
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
公共DelegateCommand导航命令{get;set;}
公共BaseViewModel()
{        
NavigationCommand=新的DelegateCommand(OnNavigate);
}
私有void OnNavigate(字符串navPath)
{
交换机(导航路径)
{
案例“客户”:
CurrentViewModel=新CustomerViewModel();
打破
个案“探访”:
CurrentViewModel=新建VisitsViewModel();
打破
个案"病人:
CurrentViewModel=新的PatientsViewModel();
打破
案例“客户”:
CurrentViewModel=新的CustomerViewModel();
打破
“访问”案例:
CurrentViewModel=新的VisitViewModel();
打破
}
}
私有对象_currentViewModel;
公共对象CurrentViewModel
{
获取{return\u currentViewModel;}
设置
{
if(_currentViewModel!=值)
{
_currentViewModel=值;
OnPropertyChanged();
}
}
}
私有对象_currentText;
公共对象当前文本
{
获取{return\u currentText;}
设置
{
如果(_currentText!=值)
{
_currentText=值;
OnPropertyChanged();
}
}
}
}
}
客户。xaml

<Window x:Class="TestProject.View.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewmodel="clr-namespace:TestProject.ViewModel"
        xmlns:local="clr-namespace:TestProject"
        xmlns:view="clr-namespace:TestProject.View"
        mc:Ignorable="d"
        Title="MainWindow" Width="966" Height="897">
    <Window.DataContext>
        <viewmodel:MainWindowViewModel/>
    </Window.DataContext>
<Grid >
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <!--Верхнее меню -->
    <Grid Grid.Row="0">
        <StackPanel HorizontalAlignment="Left" Orientation="Horizontal" >
            <Button x:Name="Visits" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="visits"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">        
                    <Image Source="../icon/document-changed.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Patients" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="patients"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/document-changed.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Customers" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="customers"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/user.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Goods" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="customer"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/folder_documents.png" Width="16" Height="16"/>
            </Button>
            <Button x:Name="Services" Background="Transparent" Command="{Binding NavigationCommand}" CommandParameter="services" BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                    <Image Source="../icon/folder_documents.png" Width="16" Height="16"/>
            </Button>                
        </StackPanel>
    </Grid>
    <ContentControl x:Name="Content" Grid.Row="1" Content="{Binding CurrentViewModel}"></ContentControl>
    </Grid>
</Window>
namespace TestProject.ViewModel
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public DelegateCommand<string> NavigationCommand { get; set; }        
        public BaseViewModel()
        {        
            NavigationCommand = new DelegateCommand<string>(OnNavigate);            
        }

        private void OnNavigate(string navPath)
        {
            switch (navPath)
            {
                case "customers":
                    CurrentViewModel = new CustomersViewModel();                    
                    break;
                case "visits":
                    CurrentViewModel = new VisitsViewModel();                    
                    break;
                case "patients":
                    CurrentViewModel = new PatientsViewModel();                    
                    break;
                case "customer":                    
                    CurrentViewModel = new CustomerViewModel();
                    break;
                case "visit":                    
                    CurrentViewModel = new VisitViewModel();
                    break;
            }
        }

        private object _currentViewModel;

        public object CurrentViewModel
        {
            get { return _currentViewModel; }
            set
            {
                if (_currentViewModel != value)
                {
                    _currentViewModel = value;
                    OnPropertyChanged();
                }
            }
        }
        private object _currentText;

        public object CurrentText
        {
            get { return _currentText; }
            set
            {
                if (_currentText != value)
                {
                    _currentText = value;
                    OnPropertyChanged();
                }
            }
        }
    }
}
<UserControl x:Class="TestProject.View.Customers"
             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:local="clr-namespace:TestProject.View"
             xmlns:viewModel="clr-namespace:TestProject.ViewModel"
             mc:Ignorable="d"       
             >
    <UserControl.DataContext>
        <viewModel:CustomersViewModel/>
        </UserControl.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"></RowDefinition>
            <RowDefinition Height="50"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Label Grid.Row="0" Background="#FFF3EB96">Клиенты</Label>
        <StackPanel Grid.Row="1" Orientation="Horizontal">
            <Button Command="{Binding NavigationCommand}" CommandParameter="customer"  Background="Transparent"  BorderThickness="0" Width="Auto"  Height="Auto" Margin="8,0,0,0">
                <StackPanel Orientation="Horizontal">
                    <Image Source="../icon/plus_32.png" Width="32" Height="32"/>
                </StackPanel>
            </Button>

        </StackPanel>
    </Grid>
</UserControl>

Клиенты

您似乎已经在所有视图模型的公共基类中定义了
CurrentViewModel
属性。这是错误的

视图中的
ContentControl
绑定到视图模型类的特定实例,因此设置
CustomerViewModel
CurrentViewModel
属性不会影响绑定到
MainWindowViewModel
ContentControl
属性的
ContentControl

CustomerViewModel
应该直接引用
MainWindowViewModel
,或者您必须使用某种messenger/事件聚合器或共享服务在它们之间进行通信:

如果在创建子视图模型时,在子视图模型中插入对
MainWindowViewModel
的引用,则可以使用此引用来导航:

MainWindowViewModel:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public DelegateCommand<string> NavigationCommand { get; set; }
    public BaseViewModel()
    {
        NavigationCommand = new DelegateCommand<string>(OnNavigate);
    }

    private void OnNavigate(string navPath)
    {
        switch (navPath)
        {
            case "customers":
                CurrentViewModel = new CustomersViewModel(this);
                break;
            ...
        }
    }
public class CustomersViewModel
{
    private readonly MainWindowViewModel _vm;
    public CustomersViewModel(MainWindowViewModel vm)
    {
        _vm = vm;
        NavigationCommand = new DelegateCommand<string>(OnNavigate);
    }

    public DelegateCommand<string> NavigationCommand { get; set; }


    private void OnNavigate(string navPath)
    {
        _vm.CurrentViewModel = new SomeOtherViewModel();
    }
}
public类MainWindowViewModel:INotifyPropertyChanged
{
公共事件PropertyChangedEventHandler PropertyChanged=委托{};
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
公共DelegateCommand导航命令{get;set;}
公共BaseViewModel()
{
NavigationCommand=新的DelegateCommand(OnNavigate);
}
私有void OnNavigate(字符串navPath)
{
交换机(导航路径)
{
案例“客户”:
CurrentViewModel=新的CustomerViewModel(此);
打破
...
}
}
客户视图模型:

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public DelegateCommand<string> NavigationCommand { get; set; }
    public BaseViewModel()
    {
        NavigationCommand = new DelegateCommand<string>(OnNavigate);
    }

    private void OnNavigate(string navPath)
    {
        switch (navPath)
        {
            case "customers":
                CurrentViewModel = new CustomersViewModel(this);
                break;
            ...
        }
    }
public class CustomersViewModel
{
    private readonly MainWindowViewModel _vm;
    public CustomersViewModel(MainWindowViewModel vm)
    {
        _vm = vm;
        NavigationCommand = new DelegateCommand<string>(OnNavigate);
    }

    public DelegateCommand<string> NavigationCommand { get; set; }


    private void OnNavigate(string navPath)
    {
        _vm.CurrentViewModel = new SomeOtherViewModel();
    }
}
公共类CustomerViewModel
{
私有只读MainWindowViewModel\u vm;
公共CustomerViewModel(MainWindowViewModel虚拟机)
{
_vm=vm;
NavigationCommand=新的DelegateCommand(OnNavigate);
}
公共DelegateCommand导航命令{get;set;}
私有void OnNavigate(字符串navPath)
{
_vm.CurrentViewModel=新建SomeOtherViewModel();
}
}

您似乎在所有视图模型的公共基类中定义了
CurrentViewModel
属性。这是错误的

视图中的
ContentControl
绑定到视图模型类的特定实例,因此设置
CustomerViewModel
CurrentViewModel
属性不会影响绑定到
MainWindowViewModel
ContentControl
属性的
ContentControl