gpt4 book ai didi

c# - WPF 数据绑定(bind)不填充选项卡?

转载 作者:太空宇宙 更新时间:2023-11-03 19:57:07 24 4
gpt4 key购买 nike

我在网上搜索了 mvvm 设置并注意到当我创建我的示例时,这些选项卡似乎没有在应用程序启动时生成。但是我并不完全清楚为什么会这样。除了未创建的选项卡之外,我还有其他一些问题...

  1. [完成] 为什么即使在设置绑定(bind)后选项卡也没有出现? (主要问题)
  2. 当用户点击“添加”时,它如何向数据添加另一个项目?
  3. 如何才能在仅选择一个选项卡时启用“删除按钮”?
  4. 当用户点击“删除”时,如果选择了一个标签,它会删除所选标签。

我在网上找到了一些这方面的例子,但很多要么很复杂,要么不完整。感谢您的帮助,谢谢。

MainWindow.cs

using System.Collections.ObjectModel;
using System.Windows;

namespace listBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.DataContext = new ViewModel();
InitializeComponent();
}

public class ViewModel
{
public ObservableCollection<TabItem> Tabs { get; set; }
public ViewModel()
{
Tabs = new ObservableCollection<TabItem>();
Tabs.Add(new TabItem { Header = "One", Content = "One's content" });
Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });
Tabs.Add(new TabItem { Header = "Three", Content = "Three's content" });
}
}
public class TabItem
{
public string Header { get; set; }
public string Content { get; set; }
}

private void AddItem(object sender, RoutedEventArgs e)
{
// Adds new item and generates a new tab
}

private void DeleteItem(object sender, RoutedEventArgs e)
{
// Deletes the selected tab
}

}
}

MainWindow.xaml

<Window x:Class="listBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Width="525"
Height="350">

<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Add" Click="AddItem"></MenuItem>
<MenuItem Header="_Delete" Click="DeleteItem"></MenuItem>
</Menu>


<TabControl ItemsSource="{Binding Tabs}">

<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" />
</DataTemplate>
</TabControl.ItemTemplate>

<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Content}" />
</DataTemplate>
</TabControl.ContentTemplate>

</TabControl>

</DockPanel>
</Window>

最佳答案

好的。首先,不要将您的 DataContext 放在 View 的代码隐藏中。

我建议您在您的解决方案中创建一个小的文件夹层次结构,例如:

  • 转换器
  • helper
  • 模型
  • 查看
  • View 模型

View 模型

在这个文件夹中有您的类,其中包含您的逻辑。 View 模型对任何 View 对象(xaml 文件)一无所知。

在你的情况下,我会创建一个名为 MainWindowViewModel 的类,它看起来像:

internal class MainWindowViewModel : INotifyPropertyChanged
{
private ICommand addCommand;
private ObservableCollection<ContentItem> contentItems;
private ICommand deleteCommand;
private ContentItem selectedContentItem;

public MainWindowViewModel()
{
ContentItems.Add(new ContentItem("One", "One's content"));
ContentItems.Add(new ContentItem("Two", "Two's content"));
ContentItems.Add(new ContentItem("Three", "Three's content"));
}

public ObservableCollection<ContentItem> ContentItems
{
get { return contentItems ?? (contentItems = new ObservableCollection<ContentItem>()); }
}

public ICommand AddCommand
{
get { return addCommand ?? (addCommand = new RelayCommand(AddContentItem)); }
}

public ICommand DeleteCommand
{
get { return deleteCommand ?? (deleteCommand = new RelayCommand(DeleteContentItem, CanDeleteContentItem)); }
}

public ContentItem SelectedContentItem
{
get { return selectedContentItem; }
set
{
selectedContentItem = value;
OnPropertyChanged();
}
}

private bool CanDeleteContentItem(object parameter)
{
return SelectedContentItem != null;
}

private void DeleteContentItem(object parameter)
{
ContentItems.Remove(SelectedContentItem);
}

private void AddContentItem(object parameter)
{
ContentItems.Add(new ContentItem("New content item", DateTime.Now.ToLongDateString()));
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

ContentItems-Collection 包含您要在 View 中显示为 TabItems 的所有项目。 SelectedContentItem-Property 始终包含 TabControl 中当前选定的 TabItem。

命令 AddCommandDeleteCommand 是单击添加或删除时执行的命令。在 MVVM 中,您通常不使用事件来进行 View 和 ViewModel 之间的通信。

助手

在这个文件夹中,我放置了一个名为 RelayCommand 的类,我已经在 MainWindowViewModel 中使用过它。该类看起来像这样:

public class RelayCommand : ICommand
{
private readonly Predicate<object> canExecute;
private readonly Action<object> execute;

public RelayCommand(Action<object> execute, Predicate<object> canExecute = null)
{
if (execute == null)
throw new ArgumentNullException("execute");
this.execute = execute;
this.canExecute = canExecute;
}

public bool CanExecute(object parameter)
{
return canExecute == null || canExecute(parameter);
}

public void Execute(object parameter)
{
execute(parameter);
}

public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}

您需要此类(或 ICommand 的类似实现)在您要单击的 View 中的对象(MenuItem、Buttons...)和相应的 ViewModel 之间进行交互。

型号

这是您的数据对象。在本例中,它是具有两个属性的 ContentItem。

public class ContentItem : INotifyPropertyChanged
{
private string contentText;
private string header;

public ContentItem(string header, string contentText)
{
Header = header;
ContentText = contentText;
}

public string Header
{
get { return header; }
set
{
header = value;
OnPropertyChanged();
}
}

public string ContentText
{
get { return contentText; }
set
{
contentText = value;
OnPropertyChanged();
}
}

public event PropertyChangedEventHandler PropertyChanged;

protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

查看

此文件夹中是您的应用程序的用户可以看到的内容。在您的情况下,只有一个名为 MainWindowView.xaml 的文件,如下所示:

<Window x:Class="MVVMDemo.View.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindowView" Height="350" Width="525"
WindowStartupLocation="CenterScreen">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Add" Command="{Binding AddCommand}"/>
<MenuItem Header="_Delete" Command="{Binding DeleteCommand}"/>
</Menu>
<TabControl ItemsSource="{Binding ContentItems}"
SelectedItem="{Binding SelectedContentItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding ContentText}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</DockPanel>
</Window>

如您所见,MenuItems 绑定(bind)到 ViewModel 中的 ICommand-Properties。所以你不需要 Event 在这里进行通信。并且因为您的 TabControl 绑定(bind)到 View 模型中的模型对象集合,您可以在 tabcontrol 中添加或删除项目,只需从绑定(bind)集合中添加或删除模型对象。

到目前为止,View 和 ViewModel 之间没有任何联系。如果您现在运行代码,TabControl 中将没有条目。

有几种方法可以在 View 和 View 模型之间建立连接。

在 App.xaml/App.xaml.cs 中:

打开 App.xaml 并删除 StartupUri="MainWindow.xaml" 部分并将其替换为 Startup="App_OnStartup"。现在您必须在 App.xaml.cs 中为 App_OnStartup 创建事件处理程序,如下所示:

private void App_OnStartup(object sender, StartupEventArgs e)
{
MainWindowViewModel viewModel = new MainWindowViewModel();
MainWindowView view = new MainWindowView
{
DataContext = viewModel
};
view.ShowDialog();
}

现在您已建立连接。

在您的 MainWindowView 的 XAML 中

另一种将 View 连接到 View 模型的方法是直接在 xaml 中设置 View 的数据上下文。

为此,您必须向 MainWindowViewModel 添加一个 xmlns-,如下所示:xmlns:viewModel="clr-namespace:MVVMDemo.ViewModel" 然后您可以在之后添加以下 xaml窗口标签:

<Window.DataContext>
<viewModel:MainWindowViewModel/>
</Window.DataContext>

希望此示例对您有所帮助。如果您对此有任何疑问,请随时提问

关于c# - WPF 数据绑定(bind)不填充选项卡?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32431814/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com