Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何通过主视图模型将UserControl内容更改为另一个UserControl。如何在内容之间导航_C#_Wpf_Xaml_User Controls - Fatal编程技术网

C# 如何通过主视图模型将UserControl内容更改为另一个UserControl。如何在内容之间导航

C# 如何通过主视图模型将UserControl内容更改为另一个UserControl。如何在内容之间导航,c#,wpf,xaml,user-controls,C#,Wpf,Xaml,User Controls,我有一个主窗口,其中有一个侧栏用于导航,还有一个用户控件,其中显示了3个视图(默认值、视图1、视图2)。在主视图模型(称为AppVM)中,我正在将contentcontrol初始化为默认视图,该视图有一个按钮可前进到view1(导航侧栏除外)。我在AppVM中有命令可以切换到三个视图中的任意一个。View1还有另一个按钮,应该移动到view2(使用主视图模型中的命令)。但是,每当我按下view1中的按钮(移动到view2)时,显示不会改变。奇怪的是,在调试时,按view1中的按钮时,内容控件绑定

我有一个主窗口,其中有一个侧栏用于导航,还有一个用户控件,其中显示了3个视图(默认值、视图1、视图2)。在主视图模型(称为AppVM)中,我正在将contentcontrol初始化为默认视图,该视图有一个按钮可前进到view1(导航侧栏除外)。我在AppVM中有命令可以切换到三个视图中的任意一个。View1还有另一个按钮,应该移动到view2(使用主视图模型中的命令)。但是,每当我按下view1中的按钮(移动到view2)时,显示不会改变。奇怪的是,在调试时,按view1中的按钮时,内容控件绑定到的变量被设置为默认视图,而不是当前视图(即view1)

我认为,按照我设置命令的方式,它会创建内容控件绑定变量的新实例,但我不知道如何使它使用相同的实例,而不一次又一次地打开新实例

主视图模型(AppVM)

视图1虚拟机

public class View1VM : ObservableObject     {

        public InfoClass View1InfoClass { get; set; }



        public View1VM()        {           View1InfoClass = new InfoClass //Apparently I  need to instantiate and initialize this to activate binding          {

                FirstName =  "Abbas",
                //FirstName = passedInforClass,
                LastName = "Syed",
                Number = 12

            };


        }   }
view1.xaml中的命令

<UserControl.Resources>
        <vm:AppVM x:Name="AppVMinView1" x:Key="AppVMinView1"></vm:AppVM>
    </UserControl.Resources>
    <UserControl.DataContext>
        <vm:View1VM></vm:View1VM>
    </UserControl.DataContext>
    <Grid Background="Aqua">
        <StackPanel Margin="100">
            <TextBlock Text="First Name"/>
            <TextBox x:Name="firstNameTextBoxView1" Text="{Binding View1InfoClass.FirstName, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>
            <TextBlock Text="Last Name"/>
            <TextBox x:Name="lastNameTextBoxView1" Text="{Binding View1InfoClass.LastName, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>
            <TextBlock Text="Random Useless Number" ></TextBlock>
            <TextBox x:Name="randomUselessNumberView1" Text="{Binding View1InfoClass.Number, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>

            <TextBlock Text="First Name Entered"></TextBlock>
            <TextBlock Text="{Binding View1InfoClass.FirstName}"></TextBlock>
            <TextBlock Text="Last Name Entered" ></TextBlock>
            <TextBlock Text="{Binding View1InfoClass.LastName}"></TextBlock>
            <TextBlock Text="Random Useless Number Entered"></TextBlock>
            <TextBlock Text="{Binding View1InfoClass.Number}"></TextBlock>

            <Button DataContext="{DynamicResource AppVMinView1}" Content="Go to view2" Height="20" Width="70" Command="{Binding View2ButtonCommand}" />



        </StackPanel>
    </Grid>

根据我所读到的(这里和互联网上),我需要将视图设置为单例视图,我尝试的方法是使用私有setter将view2的静态属性声明为一个新的view2,但这并没有阻止它。如果能在这方面得到任何帮助,我将不胜感激


我还应该补充一点,即使当view1中要更改为view2的按钮不起作用时,侧导航栏按钮也可以正常工作

看起来您正在创建多个
AppVm
实例
View1
中的按钮和导航栏的按钮显然没有绑定到同一个
AppVm

这同样适用于
CurrentView
属性:您的内容主机绑定到不同的实例,即不同于您在
View1
中修改的
CurrentView
的属性值引用。因此,从
View1
内部更改
CurrentView
不会对内容主机-->视图产生任何影响。
确保始终在同一上下文中引用同一(共享)实例

根据用户界面的结构,有多种方法可以实现这一点。创建视图模型类的单例是迄今为止最糟糕的选择。单身人士应该也可以永远避免

最简单的解决方案是在应用程序xaml
ResourceDictionary
中将视图模型声明为资源:

App.xaml
通过
StaticResource
markup extension资源字典查找,此文件中定义的资源在任何XAML上下文中都是全局可用的

<Application>
  <Application.Resources>
    <AppVM x:Key="AppVMinView1" />
  </Application.Resources>
</Application>
View1.xaml

<!-- DataContext is inherited from the surrounding DataTemplate and is the corresponding page view model -->
<UserControl>    
  <StackPanel>
    <TextBox Text="{Binding View1InfoClass.FirstName}" />

    <!-- 
      Bind to the command of the same view model instance,
      which is the DataContext of the content host 
    -->
    <Button Content="Show View2"
            Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=MainWindow}, Path=DataContext.View2ButtonCommand}" />
  </StackPanel>
</UserControl>
<Window>
  <Window.DataContext>
    <AppVM />
  </Window.DataContext>
  <Window.Resources>

    <!-- Define the views as implicit (keyless) DataTemplate -->
    <DataTemplate DataType="{x:Type DefaultVM}">
      <DefaultView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type View1VM}">
      <View1 />
    </DataTemplate>

    <DataTemplate DataType="{x:Type View2VM}">
      <View2 />
    </DataTemplate>
  </Window.Resources>

  <!-- 
    Host of the pages.
    The implicit DataTemplates will apply automatically 
    and show the control that maps to the current CurrentView view model
  -->
  <ContentPresenter Content="{Binding CurrentView}" />
</Window>

main window.xaml

<!-- DataContext is inherited from the surrounding DataTemplate and is the corresponding page view model -->
<UserControl>    
  <StackPanel>
    <TextBox Text="{Binding View1InfoClass.FirstName}" />

    <!-- 
      Bind to the command of the same view model instance,
      which is the DataContext of the content host 
    -->
    <Button Content="Show View2"
            Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=MainWindow}, Path=DataContext.View2ButtonCommand}" />
  </StackPanel>
</UserControl>
<Window>
  <Window.DataContext>
    <AppVM />
  </Window.DataContext>
  <Window.Resources>

    <!-- Define the views as implicit (keyless) DataTemplate -->
    <DataTemplate DataType="{x:Type DefaultVM}">
      <DefaultView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type View1VM}">
      <View1 />
    </DataTemplate>

    <DataTemplate DataType="{x:Type View2VM}">
      <View2 />
    </DataTemplate>
  </Window.Resources>

  <!-- 
    Host of the pages.
    The implicit DataTemplates will apply automatically 
    and show the control that maps to the current CurrentView view model
  -->
  <ContentPresenter Content="{Binding CurrentView}" />
</Window>


你的问题格式很奇怪。有些代码甚至不显示。代码应仅格式化为代码而不是块引号。您的按钮设置了工作DataContext
DataContext
必须是
AppVM
,否则
命令
绑定无法解析。将视图设置为单例是没有用的。你好,BionicCode。感谢您的回复,并指出错误的格式(很抱歉!)我将它绑定到AppVM,但在调试时,单击View1中的按钮导航到View2时,我在AppVM中到达了断点,但CurrentView变量设置为DefaultVM(但它应该是View1[它的最后一个值])。看起来您正在创建多个AppVm实例。确保始终使用相同的实例。您正在修改的实例不是触发新视图的实例。您好BionicCode。谢谢你回复我。事实上,这是我感到困惑的部分。我了解到可以声明主视图模型(AppVM)的静态属性以使用同一实例。但是,由于我有非静态成员(命令),所以不能有静态构造函数。还有别的办法吗?我很抱歉,如果我听起来很愚蠢,这是我的第一个项目。谢谢你花时间来做这件事!你好,生物代码。非常感谢您的详细回答!
<Window>
  <Window.DataContext>
    <AppVM />
  </Window.DataContext>
  <Window.Resources>

    <!-- Define the views as implicit (keyless) DataTemplate -->
    <DataTemplate DataType="{x:Type DefaultVM}">
      <DefaultView />
    </DataTemplate>

    <DataTemplate DataType="{x:Type View1VM}">
      <View1 />
    </DataTemplate>

    <DataTemplate DataType="{x:Type View2VM}">
      <View2 />
    </DataTemplate>
  </Window.Resources>

  <!-- 
    Host of the pages.
    The implicit DataTemplates will apply automatically 
    and show the control that maps to the current CurrentView view model
  -->
  <ContentPresenter Content="{Binding CurrentView}" />
</Window>