XAML 多个视图使用同一个ViewModel

qaxu7uf2  于 2023-08-01  发布在  其他
关注(0)|答案(1)|浏览(112)

我写了一个WPF应用程序。它有以下观点:

  1. AddStockView.cs(用于添加股票)
  2. cs(表示显示所有股票的组合框)。
  3. View.cs(用于MainWindow.xaml)
    当然,每个视图都有一个XAML文件。这两个视图都应链接到ViewModel类。为了确保两个视图的DataContext指向同一个ViewModel对象,我将其作为构造函数参数传递。我正在用Visual Studio代码编译应用程序。编译似乎工作,但没有窗口启动。也许我的方法是错误的。我想问你我需要改变什么才能使应用程序正确运行。App.xaml.cs
namespace analyser
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        // Statische SQLiteConnection-Instanz für die gesamte Anwendung
        public static StockDBContext stockDBContext = new StockDBContext();
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            ViewModel viewModel = new ViewModel();
            StockBoxView stockboxview = new StockBoxView(viewModel);
            AddStockView addstockview = new AddStockView(viewModel);
            
            // Methode zum Hinzufügen von Stock-Objekten in die Datenbank
            stockDBContext.Stocks.Add(new Stock { Wkn = "123456", Titel = "Porsche Automobil Holding" });
            stockDBContext.Stocks.Add(new Stock { Wkn = "654321", Titel = "PayPal" });
            stockDBContext.SaveChanges();

        }
        protected override void OnExit(ExitEventArgs e)
        {
            base.OnExit(e);
        }
}   
       
}

字符串

查看1 AddStockView.cs

namespace analyser
{
    public partial class AddStockView : UserControl
    {
   
        public AddStockView(ViewModel vm)
        {
            InitializeComponent();
            this.DataContext = vm;
        }        
    }  
}

<UserControl x:Class="analyser.AddStockView"
             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:analyser">
    <Grid>
        <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10">
            <!-- Überschrift "Add new Stocks" -->
            <TextBlock Text="Add new Stocks" FontSize="20" FontWeight="Bold" Margin="0,0,0,20" />

            <!-- TextBox für den Namen des Wertpapiers -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                <Label Content="Name des Wertpapiers:" FontSize="16" Width="200" />
                <TextBox x:Name="TitelTextBox" Width="200" Margin="10,0" FontSize="16" Text="{Binding Titel, UpdateSourceTrigger=PropertyChanged}" />
            </StackPanel>

            <!-- TextBox für die WKN des Wertpapiers -->
            <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                <Label Content="WKN des Wertpapiers:" FontSize="16" Width="200" />
                <TextBox x:Name="WknTextBox" Width="200" Margin="10,0" FontSize="16" Text="{Binding Wkn, UpdateSourceTrigger=PropertyChanged}"/>
            </StackPanel>

            <!-- Absendebutton (linksbündig) -->
            <Button Width="150" Content="Absenden" HorizontalAlignment="Left" Command="{Binding SaveCommand}" />
        </StackPanel>
    </Grid>
</UserControl>


查看2 StockBox

namespace analyser
{
    public partial class StockBoxView : UserControl
    {
        public StockBoxView(ViewModel vm)
        {
            InitializeComponent();
            this.DataContext = vm;
        }     
    }

    
}

<UserControl 
        x:Class="analyser.StockBoxView"
         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:analyser">
        <Grid>
             <StackPanel>
            <!-- Verwenden Sie das Binding auf die ObservableCollection<Stock> ObservableStockList -->
            <ComboBox x:Name="StockComboBox" Width="150" SelectedIndex="0"
                  ItemsSource="{Binding ObservableStockList}" 
                  DisplayMemberPath="Titel" />
        </StackPanel>
        </Grid>
      
</UserControl>

ViewModel.cs

namespace analyser
{
    public class ViewModel : INotifyPropertyChanged
    {
        private Stock stock = new Stock();
        public ObservableCollection<Stock> ObservableStockList = new ObservableCollection<Stock>();

        private ListCollectionView ComboBoxItems;

        public ViewModel()
        {
            // Initialisierung der ObservableStockList und ComboBoxItems
            Init();
        }

        // Property für den Namen des Wertpapiers
        private string _titel;
        public string Titel
        {
            get => _titel;
            set
            {
                _titel = value;
                OnPropertyChanged(nameof(Titel));
            }
        }

        // Property für die WKN des Wertpapiers
        private string _wkn;
        public string Wkn
        {
            get => _wkn;
            set
            {
                _wkn = value;
                OnPropertyChanged(nameof(Wkn));
            }
        }

        private ICommand _saveCommand;
        
        public ICommand SaveCommand
        {
            get
            {
                if (_saveCommand == null)
                    _saveCommand = new RelayCommand(Save);
                return _saveCommand;
            }
        }

        public void Init(){

            foreach (var stock in App.stockDBContext.Stocks)
            {
                    ObservableStockList.Add(stock);
            }

             // Erstellen und Konfigurieren Sie den ListCollectionView
            ComboBoxItems = new ListCollectionView(ObservableStockList);
            ComboBoxItems.SortDescriptions.Add(new SortDescription("Titel", ListSortDirection.Ascending));
            ComboBoxItems.IsLiveSorting = true;

        }

        public void Save()
        {
            // Speichern Sie die Werte der Textboxen in das Stock-Objekt
            stock.Titel = Titel;
            stock.Wkn = Wkn;
            Console.WriteLine($"Generate new Stock with Titel {stock.Titel} and WKN {stock.Wkn}");
            App.stockDBContext.Stocks.Add(stock);
            
            // Hier können Sie die Logik zum Speichern des Stock-Objekts in die Datenbank oder an einen anderen Speicherort einfügen.
        }

        // ... (weiterer Code wie die Implementierung von INotifyPropertyChanged)
        
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

MainWindow.xaml

<Window x:Class="analyser.View"
        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:local="clr-namespace:analyser"
        xmlns:uc="clr-namespace:analyser"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <!-- Define a style for TabItem -->
        <Style TargetType="TabItem">
            <Setter Property="FontSize" Value="16" /> <!-- Set the desired font size (e.g., 16) -->
        </Style>
    </Window.Resources>
    <Grid>
        <DockPanel>
            <Menu DockPanel.Dock="Top">
                <MenuItem Header="_File">
                    <MenuItem Header="_New"/>
                    <MenuItem Header="_Open"/>
                    <Separator />
                    <MenuItem Header="_Exit" />
                </MenuItem>
                <MenuItem Header="_Help">
                    <MenuItem Header="_About"/>
                </MenuItem>
            </Menu>

            <TabControl>
                <TabItem Header="add Stock">
                    <!-- Content for Tab 1 -->
                    <uc:AddStockView/>
                </TabItem>
                <TabItem Header="auswählen">
                    <!-- Content for Tab 1 -->
                    <uc:StockBoxView/>
                </TabItem>
                <TabItem Header="Tab 2">
                    <!-- Content for Tab 2 -->
                    
                </TabItem>
                <TabItem Header="Tab 3">
                    <!-- Content for Tab 3 -->
                    <TextBlock Text="This is Tab 3 content."/>
                </TabItem>
            </TabControl>
        </DockPanel>
    </Grid>
</Window>

View.cs

namespace analyser
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class View : Window
    {
        
        public View()
        {

            InitializeBindings();
        }
        
        private void InitializeBindings() {
            DataContext = this;
        }
    }
}

编辑

MyProjekt
|___Views
|    |___AddStock
|    |    |___AddStock.xaml (UserControl)
|    |    |___AddStock.xaml.cs
|    |___StockBox
|         |___StockBox.xaml (UserControl)
|         |___StockBox.xaml.cs   
|
|___ViewModels
|   |___ViewModel.cs
|
|___Models
|   |___Stock.cs
|   |___StockBoxDBContext
|
|___App.xaml
|___App.xaml.cs
|___MainWindow.xaml
|___MainWindow.xaml.cs

mfpqipee

mfpqipee1#

不能显式分配控件的DataContext。您应该努力使XAML解析器能够为您创建示例,以便您可以方便地使用标记语言设计布局。
除非您显式地将DataContext分配给元素,否则根元素的DataContext将继承给可视化树中的所有子元素。这意味着您通常只分配XAML根元素的DataContext
您可以使用组合来设计您的视图模型类,以便将特定于上下文的DataContext引入到您的布局中(参见下面的示例)。
下面的示例演示如何手动运行主窗口以允许将视图模型传递给构造函数。它还展示了如何使用组合来引入上下文相关的视图模型类。

App.xaml

<!-- Remove the StartupUri attribute 
     and only assign a Startup event handler -->
<Application Startup="OnApplicationStarted">
  ...
</Application>

字符串

App.xaml.cs

partial class App : Application
{
  private void OnApplicationStarted(object sender, EventArgs e)
  {
    var someViewModel = new SomeViewModel();
    var mainViewModel = new MainViewModel(someViewModel);
    
    var mainWindow = new MainWindow(mainViewModel);

    // Start the GUI manually
    mainWindow.Show();
  }
}

MainWindow.xaml

<Window>
  <!-- All children of MainWindow inherit MainViewModel as DataContext -->
  <StackPanel>
    
    <!-- All children use the inherited MainViewModel as DataContext -->
    <ListBox />
    <TextBlock Text="{Binding ExampleText}" />
  
    <!-- Create a new DataContext scope -->
    <StackPanel DataContext="{Binding SomeViewModel}>

      <!-- All children inherit SomeViewModel as their DataContext -->

      <ListBox />
      <DataGrid />
      <MyUserControl SomeItems="{Binding SomeItemsSource}" />
    </StackPanel>

    <!-- MainViewModel DataContext scope continues -->
  </StackPanel>
</Window>

MainWindow.xaml.cs

partial class MainWindow : Window
{
  public MainWindow(MainViewModel mainViewModel)
  {
    InitilaizeComponent();

    // This should be the only place in your application 
    // where you set the DataContext from a constructor
    this.DataContext = mainViewModel;
  }
}

MyUserControl.xaml.cs

partial class MyUserControl : UserControl
{
  // A depndency property to allow binding to the DataContext
  public static DependencyProperty SomeItems = DependencyObject.Register(...);

  // DataContext will be inherited from the visual parent.
  // This enables maximum flexibility and reusability.
  public MyUserControl()
  {
    InitilaizeComponent();
  }
}

MyUserControl.xaml.cs

<UserControl>

  <!-- To enable reusability don't bind directly to the DataContext.
       Instead introduce dependency properties that you can bind the view model to. 
       Bind internals only to dependency properties defined on the current UserControl -->
  <ListBox ItemsSource="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, 
                                 Path=SomeItems}" />
</UserControl>

MainViewModel.cs

class MainViewModel : INotifyPropertyChanged
{
  public SomeViewModel SomeViewModel { get; }
  public string ExampleText { get; }

  public MainViewModel(SomeViewModel someViewModel)
  {
    this.SomeViewModel = someviewModel;
    this.ExampleText = "This is from MainViewModel";
  }
}

SomeViewModel.cs

class SomeViewModel : INotifyPropertyChanged
{
  public ObservableCollection<object> SomeItemsSource { get; }

  public SomeViewModel()
  {
    this.SomeItemsSource = new ObservableCollection<object>();
  }
}

相关问题